diff options
-rw-r--r-- | sys/net80211/ieee80211_crypto.c | 23 | ||||
-rw-r--r-- | sys/net80211/ieee80211_input.c | 106 | ||||
-rw-r--r-- | sys/net80211/ieee80211_ioctl.c | 5 | ||||
-rw-r--r-- | sys/net80211/ieee80211_ioctl.h | 46 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 6 | ||||
-rw-r--r-- | sys/net80211/ieee80211_output.c | 25 | ||||
-rw-r--r-- | sys/net80211/ieee80211_var.h | 2 |
7 files changed, 174 insertions, 39 deletions
diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c index 25a2c8b..6cb9ee0 100644 --- a/sys/net80211/ieee80211_crypto.c +++ b/sys/net80211/ieee80211_crypto.c @@ -113,16 +113,23 @@ ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag) n0 = NULL; if ((ctx = ic->ic_wep_ctx) == NULL) { ctx = malloc(arc4_ctxlen(), M_DEVBUF, M_NOWAIT); - if (ctx == NULL) + if (ctx == NULL) { + ic->ic_stats.is_crypto_nomem++; goto fail; + } ic->ic_wep_ctx = ctx; } m = m0; left = m->m_pkthdr.len; MGET(n, M_DONTWAIT, m->m_type); n0 = n; - if (n == NULL) + if (n == NULL) { + if (txflag) + ic->ic_stats.is_tx_nombuf++; + else + ic->ic_stats.is_rx_nombuf++; goto fail; + } M_MOVE_PKTHDR(n, m); len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; if (txflag) { @@ -188,8 +195,13 @@ ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag) len = n->m_len - noff; if (len == 0) { MGET(n->m_next, M_DONTWAIT, n->m_type); - if (n->m_next == NULL) + if (n->m_next == NULL) { + if (txflag) + ic->ic_stats.is_tx_nombuf++; + else + ic->ic_stats.is_rx_nombuf++; goto fail; + } n = n->m_next; n->m_len = MLEN; if (left >= MINCLSIZE) { @@ -223,8 +235,10 @@ ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag) else { n->m_len = noff; MGET(n->m_next, M_DONTWAIT, n->m_type); - if (n->m_next == NULL) + if (n->m_next == NULL) { + ic->ic_stats.is_tx_nombuf++; goto fail; + } n = n->m_next; n->m_len = sizeof(crcbuf); noff = 0; @@ -252,6 +266,7 @@ ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag) n0->m_len, -1, -1); } #endif + ic->ic_stats.is_rx_decryptcrc++; goto fail; } } diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 2152c12..6a03c1c 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -113,6 +113,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, if_printf(ifp, "receive packet with wrong version: %x\n", wh->i_fc[0]); ieee80211_unref_node(&ni); + ic->ic_stats.is_rx_badversion++; goto err; } @@ -124,19 +125,21 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, * them to go through bpf tapping at the 802.11 layer. */ if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) { + /* XXX statistic */ IEEE80211_DPRINTF2(("%s: frame too short, len %u\n", __func__, m->m_pkthdr.len)); - /* XXX statistic */ + ic->ic_stats.is_rx_tooshort++; goto out; /* XXX */ } if (ic->ic_state != IEEE80211_S_SCAN) { switch (ic->ic_opmode) { case IEEE80211_M_STA: if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) { + /* not interested in */ IEEE80211_DPRINTF2(("%s: discard frame from " "bss %s\n", __func__, ether_sprintf(wh->i_addr2))); - /* not interested in */ + ic->ic_stats.is_rx_wrongbss++; goto out; } break; @@ -153,6 +156,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, IEEE80211_DPRINTF2(("%s: discard frame from " "bss %s\n", __func__, ether_sprintf(bssid))); + ic->ic_stats.is_rx_wrongbss++; goto out; } break; @@ -171,6 +175,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) && rxseq == ni->ni_rxseq) { /* duplicate, silently discarded */ + ic->ic_stats.is_rx_dup++; /* XXX per-station stat */ goto out; } ni->ni_inact = 0; @@ -180,8 +185,10 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, case IEEE80211_FC0_TYPE_DATA: switch (ic->ic_opmode) { case IEEE80211_M_STA: - if (dir != IEEE80211_FC1_DIR_FROMDS) + if (dir != IEEE80211_FC1_DIR_FROMDS) { + ic->ic_stats.is_rx_wrongdir++; goto out; + } if ((ifp->if_flags & IFF_SIMPLEX) && IEEE80211_IS_MULTICAST(wh->i_addr1) && IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_myaddr)) { @@ -191,17 +198,22 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, * It should be silently discarded for * SIMPLEX interface. */ + ic->ic_stats.is_rx_mcastecho++; goto out; } break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: - if (dir != IEEE80211_FC1_DIR_NODS) + if (dir != IEEE80211_FC1_DIR_NODS) { + ic->ic_stats.is_rx_wrongdir++; goto out; + } break; case IEEE80211_M_HOSTAP: - if (dir != IEEE80211_FC1_DIR_TODS) + if (dir != IEEE80211_FC1_DIR_TODS) { + ic->ic_stats.is_rx_wrongdir++; goto out; + } /* check if source STA is associated */ if (ni == ic->ic_bss) { IEEE80211_DPRINTF(("%s: data from unknown src " @@ -215,6 +227,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, IEEE80211_REASON_NOT_AUTHED); ieee80211_free_node(ic, ni); } + ic->ic_stats.is_rx_notassoc++; goto err; } if (ni->ni_associd == 0) { @@ -225,6 +238,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_NOT_ASSOCED); ieee80211_unref_node(&ni); + ic->ic_stats.is_rx_notassoc++; goto err; } break; @@ -234,18 +248,24 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, if (wh->i_fc[1] & IEEE80211_FC1_WEP) { if (ic->ic_flags & IEEE80211_F_WEPON) { m = ieee80211_wep_crypt(ifp, m, 0); - if (m == NULL) + if (m == NULL) { + ic->ic_stats.is_rx_wepfail++; goto err; + } wh = mtod(m, struct ieee80211_frame *); - } else + } else { + ic->ic_stats.is_rx_nowep++; goto out; + } } /* copy to listener after decrypt */ if (ic->ic_rawbpf) bpf_mtap(ic->ic_rawbpf, m); m = ieee80211_decap(ifp, m); - if (m == NULL) + if (m == NULL) { + ic->ic_stats.is_rx_decap++; goto err; + } ifp->if_ipackets++; /* perform as a bridge within the AP */ @@ -286,21 +306,29 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, return; case IEEE80211_FC0_TYPE_MGT: - if (dir != IEEE80211_FC1_DIR_NODS) + if (dir != IEEE80211_FC1_DIR_NODS) { + ic->ic_stats.is_rx_wrongdir++; goto err; - if (ic->ic_opmode == IEEE80211_M_AHDEMO) + } + if (ic->ic_opmode == IEEE80211_M_AHDEMO) { + ic->ic_stats.is_rx_ahdemo_mgt++; goto out; + } subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; /* drop frames without interest */ if (ic->ic_state == IEEE80211_S_SCAN) { if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && - subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) + subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) { + ic->ic_stats.is_rx_mgtdiscard++; goto out; + } } else { if (ic->ic_opmode != IEEE80211_M_IBSS && - subtype == IEEE80211_FC0_SUBTYPE_BEACON) + subtype == IEEE80211_FC0_SUBTYPE_BEACON) { + ic->ic_stats.is_rx_mgtdiscard++; goto out; + } } if (ifp->if_flags & IFF_DEBUG) { @@ -336,6 +364,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, return; case IEEE80211_FC0_TYPE_CTL: + ic->ic_stats.is_rx_ctl++; goto out; default: IEEE80211_DPRINTF(("%s: bad type %x\n", __func__, type)); @@ -475,6 +504,7 @@ ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni, IEEE80211_DPRINTF(("%s: extended rate set too large;" " only using %u of %u rates\n", __func__, nxrates, xrates[1])); + ic->ic_stats.is_rx_rstoobig++; } memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates); rs->rs_nrates += nxrates; @@ -482,13 +512,13 @@ ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni, return ieee80211_fix_rate(ic, ni, flags); } -/* XXX statistics */ /* Verify the existence and length of __elem or get out. */ #define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen) do { \ if ((__elem) == NULL) { \ IEEE80211_DPRINTF(("%s: no " #__elem "in %s frame\n", \ __func__, ieee80211_mgt_subtype_name[subtype >> \ IEEE80211_FC0_SUBTYPE_SHIFT])); \ + ic->ic_stats.is_rx_elem_missing++; \ return; \ } \ if ((__elem)[1] > (__maxlen)) { \ @@ -497,6 +527,7 @@ ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni, ieee80211_mgt_subtype_name[subtype >> \ IEEE80211_FC0_SUBTYPE_SHIFT], \ ether_sprintf(wh->i_addr2))); \ + ic->ic_stats.is_rx_elem_toobig++; \ return; \ } \ } while (0) @@ -508,6 +539,7 @@ ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni, ieee80211_mgt_subtype_name[subtype >> \ IEEE80211_FC0_SUBTYPE_SHIFT], \ ether_sprintf(wh->i_addr2))); \ + ic->ic_stats.is_rx_elem_toosmall++; \ return; \ } \ } while (0) @@ -598,6 +630,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, IEEE80211_DPRINTF(("%s: invalid ERP " "element; length %u, expecting " "1\n", __func__, frm[1])); + ic->ic_stats.is_rx_elem_toobig++; break; } erp = frm[2]; @@ -605,6 +638,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, default: IEEE80211_DPRINTF2(("%s: element id %u/len %u " "ignored\n", __func__, *frm, frm[1])); + ic->ic_stats.is_rx_elem_unknown++; break; } frm += frm[1] + 2; @@ -620,6 +654,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, "%u\n", __func__, ISPROBE(subtype) ? "probe response" : "beacon", chan)); + ic->ic_stats.is_rx_badchan++; return; } if (chan != bchan) { @@ -634,7 +669,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, "for channel %u\n", __func__, ISPROBE(subtype) ? "probe response" : "beacon", bchan, chan)); - /* XXX statistic */ + ic->ic_stats.is_rx_chanmismatch++; return; } @@ -669,8 +704,10 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, #endif if (ni == NULL) { ni = ieee80211_alloc_node(ic, wh->i_addr2); - if (ni == NULL) + if (ni == NULL) { + ic->ic_stats.is_rx_nodealloc++; return; + } ni->ni_esslen = ssid[1]; memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); memcpy(ni->ni_essid, ssid + 2, ssid[1]); @@ -741,13 +778,16 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, printf(" from %s\n", ether_sprintf(wh->i_addr2)); } #endif + ic->ic_stats.is_rx_ssidmismatch++; return; } if (ni == ic->ic_bss) { ni = ieee80211_dup_bss(ic, wh->i_addr2); - if (ni == NULL) + if (ni == NULL) { + ic->ic_stats.is_rx_nodealloc++; return; + } IEEE80211_DPRINTF(("%s: new req from %s\n", __func__, ether_sprintf(wh->i_addr2))); allocbs = 1; @@ -792,12 +832,24 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, /* TODO: shared key auth */ IEEE80211_DPRINTF(("%s: unsupported auth %d from %s\n", __func__, algo, ether_sprintf(wh->i_addr2))); + ic->ic_stats.is_rx_auth_unsupported++; return; } + if (ic->ic_state != IEEE80211_S_RUN) { + IEEE80211_DPRINTF(("%s: discard auth from %s; " + "state %u\n", __func__, + ether_sprintf(wh->i_addr2), ic->ic_state)); + ic->ic_stats.is_rx_bad_auth++; + break; + } + if (seq != (ic->ic_opmode == IEEE80211_M_STA ? 2 : 1)) { + IEEE80211_DPRINTF(("%s: discard auth from %s; seq %u\n", + __func__, ether_sprintf(wh->i_addr2), seq)); + ic->ic_stats.is_rx_bad_auth++; + break; + } switch (ic->ic_opmode) { case IEEE80211_M_IBSS: - if (ic->ic_state != IEEE80211_S_RUN || seq != 1) - return; ieee80211_new_state(ic, IEEE80211_S_AUTH, wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); break; @@ -807,12 +859,12 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, break; case IEEE80211_M_HOSTAP: - if (ic->ic_state != IEEE80211_S_RUN || seq != 1) - return; if (ni == ic->ic_bss) { ni = ieee80211_alloc_node(ic, wh->i_addr2); - if (ni == NULL) + if (ni == NULL) { + ic->ic_stats.is_rx_nodealloc++; return; + } IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); ni->ni_rssi = rssi; ni->ni_rstamp = rstamp; @@ -829,8 +881,6 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, break; case IEEE80211_M_STA: - if (ic->ic_state != IEEE80211_S_AUTH || seq != 2) - return; if (status != 0) { if_printf(&ic->ic_if, "authentication failed (reason %d) for %s\n", @@ -838,6 +888,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, ether_sprintf(wh->i_addr3)); if (ni != ic->ic_bss) ni->ni_fails++; + ic->ic_stats.is_rx_auth_fail++; return; } ieee80211_new_state(ic, IEEE80211_S_ASSOC, @@ -877,6 +928,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) { IEEE80211_DPRINTF(("%s: ignore other bss from %s\n", __func__, ether_sprintf(wh->i_addr2))); + ic->ic_stats.is_rx_assoc_bss++; return; } capinfo = le16toh(*(u_int16_t *)frm); frm += 2; @@ -909,6 +961,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, printf(" from %s\n", ether_sprintf(wh->i_addr2)); } #endif + ic->ic_stats.is_rx_ssidmismatch++; return; } if (ni == ic->ic_bss) { @@ -921,6 +974,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, IEEE80211_REASON_ASSOC_NOT_AUTHED); ieee80211_free_node(ic, ni); } + ic->ic_stats.is_rx_assoc_notauth++; return; } /* XXX per-node cipher suite */ @@ -935,6 +989,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, ni->ni_associd = 0; IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_CAPINFO); + ic->ic_stats.is_rx_assoc_capmismatch++; return; } ieee80211_setup_rates(ic, ni, rates, xrates, @@ -946,6 +1001,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, ni->ni_associd = 0; IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_BASIC_RATE); + ic->ic_stats.is_rx_assoc_norate++; return; } ni->ni_rssi = rssi; @@ -1003,6 +1059,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, status, ether_sprintf(wh->i_addr3)); if (ni != ic->ic_bss) ni->ni_fails++; + ic->ic_stats.is_rx_auth_fail++; return; } ni->ni_associd = le16toh(*(u_int16_t *)frm); @@ -1039,6 +1096,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, */ IEEE80211_VERIFY_LENGTH(efrm - frm, 2); reason = le16toh(*(u_int16_t *)frm); + ic->ic_stats.is_rx_deauth++; switch (ic->ic_opmode) { case IEEE80211_M_STA: ieee80211_new_state(ic, IEEE80211_S_AUTH, @@ -1068,6 +1126,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, */ IEEE80211_VERIFY_LENGTH(efrm - frm, 2); reason = le16toh(*(u_int16_t *)frm); + ic->ic_stats.is_rx_disassoc++; switch (ic->ic_opmode) { case IEEE80211_M_STA: ieee80211_new_state(ic, IEEE80211_S_ASSOC, @@ -1091,6 +1150,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, default: IEEE80211_DPRINTF(("%s: mgmt frame with subtype 0x%x not " "handled\n", __func__, subtype)); + ic->ic_stats.is_rx_badsubtype++; break; } #undef ISPROBE diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index d442415..6065a52 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -720,6 +720,7 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) int error = 0; u_int kid, len; struct ieee80211req *ireq; + struct ifreq *ifr; u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE]; char tmpssid[IEEE80211_NWID_LEN]; struct ieee80211_channel *chan; @@ -981,6 +982,10 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; error = ieee80211_cfgset(ifp, cmd, data); break; + case SIOCG80211STATS: + ifr = (struct ifreq *)data; + copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats)); + break; default: error = ether_ioctl(ifp, cmd, data); break; diff --git a/sys/net80211/ieee80211_ioctl.h b/sys/net80211/ieee80211_ioctl.h index f820e6a..56d6374 100644 --- a/sys/net80211/ieee80211_ioctl.h +++ b/sys/net80211/ieee80211_ioctl.h @@ -38,6 +38,50 @@ * IEEE 802.11 ioctls. */ +struct ieee80211_stats { + u_int32_t is_rx_badversion; /* rx frame with bad version */ + u_int32_t is_rx_tooshort; /* rx frame too short */ + u_int32_t is_rx_wrongbss; /* rx from wrong bssid */ + u_int32_t is_rx_dup; /* rx discard 'cuz dup */ + u_int32_t is_rx_wrongdir; /* rx w/ wrong direction */ + u_int32_t is_rx_mcastecho; /* rx discard 'cuz mcast echo */ + u_int32_t is_rx_notassoc; /* rx discard 'cuz sta !assoc */ + u_int32_t is_rx_nowep; /* rx w/ wep but wep !config */ + u_int32_t is_rx_wepfail; /* rx wep processing failed */ + u_int32_t is_rx_decap; /* rx decapsulation failed */ + u_int32_t is_rx_mgtdiscard; /* rx discard mgt frames */ + u_int32_t is_rx_ctl; /* rx discard ctrl frames */ + u_int32_t is_rx_rstoobig; /* rx rate set truncated */ + u_int32_t is_rx_elem_missing; /* rx required element missing*/ + u_int32_t is_rx_elem_toobig; /* rx element too big */ + u_int32_t is_rx_elem_toosmall; /* rx element too small */ + u_int32_t is_rx_elem_unknown; /* rx element unknown */ + u_int32_t is_rx_badchan; /* rx frame w/ invalid chan */ + u_int32_t is_rx_chanmismatch; /* rx frame chan mismatch */ + u_int32_t is_rx_nodealloc; /* rx frame dropped */ + u_int32_t is_rx_ssidmismatch; /* rx frame ssid mismatch */ + u_int32_t is_rx_auth_unsupported; /* rx w/ unsupported auth alg */ + u_int32_t is_rx_auth_fail; /* rx sta auth failure */ + u_int32_t is_rx_assoc_bss; /* rx assoc from wrong bssid */ + u_int32_t is_rx_assoc_notauth; /* rx assoc w/o auth */ + u_int32_t is_rx_assoc_capmismatch;/* rx assoc w/ cap mismatch */ + u_int32_t is_rx_assoc_norate; /* rx assoc w/ no rate match */ + u_int32_t is_rx_deauth; /* rx deauthentication */ + u_int32_t is_rx_disassoc; /* rx disassociation */ + u_int32_t is_rx_badsubtype; /* rx frame w/ unknown subtype*/ + u_int32_t is_rx_nombuf; /* rx failed for lack of mbuf */ + u_int32_t is_rx_decryptcrc; /* rx decrypt failed on crc */ + u_int32_t is_rx_ahdemo_mgt; /* rx discard ahdemo mgt frame*/ + u_int32_t is_rx_bad_auth; /* rx bad auth request */ + u_int32_t is_tx_nombuf; /* tx failed for lack of mbuf */ + u_int32_t is_tx_nonode; /* tx failed for no node */ + u_int32_t is_tx_unknownmgt; /* tx of unknown mgt frame */ + u_int32_t is_scan_active; /* active scans started */ + u_int32_t is_scan_passive; /* passive scans started */ + u_int32_t is_node_timeout; /* nodes timed out inactivity */ + u_int32_t is_crypto_nomem; /* no memory for crypto ctx */ +}; + #ifdef __FreeBSD__ /* * FreeBSD-style ioctls. @@ -79,6 +123,8 @@ struct ieee80211req { #ifndef IEEE80211_CHAN_ANY #define IEEE80211_CHAN_ANY 0xffff /* token for ``any channel'' */ #endif + +#define SIOCG80211STATS _IOWR('i', 236, struct ifreq) #endif /* __FreeBSD__ */ #endif /* _NET80211_IEEE80211_IOCTL_H_ */ diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index eae29e9..6ef241a 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -148,8 +148,11 @@ ieee80211_begin_scan(struct ifnet *ifp) * In all but hostap mode scanning starts off in * an active mode before switching to passive. */ - if (ic->ic_opmode != IEEE80211_M_HOSTAP) + if (ic->ic_opmode != IEEE80211_M_HOSTAP) { ic->ic_flags |= IEEE80211_F_ASCAN; + ic->ic_stats.is_scan_active++; + } else + ic->ic_stats.is_scan_passive++; if (ifp->if_flags & IFF_DEBUG) if_printf(ifp, "begin %s scan\n", (ic->ic_flags & IEEE80211_F_ASCAN) ? @@ -581,6 +584,7 @@ restart: IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_EXPIRE); ieee80211_free_node(ic, ni); + ic->ic_stats.is_node_timeout++; goto restart; } } diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 01b87cd..6ea342d 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -155,7 +155,7 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni) if (m->m_len < sizeof(struct ether_header)) { m = m_pullup(m, sizeof(struct ether_header)); if (m == NULL) { - /* XXX statistic */ + ic->ic_stats.is_tx_nombuf++; goto bad; } } @@ -183,6 +183,7 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni) IEEE80211_DPRINTF(("%s: no node for dst %s, " "discard frame\n", __func__, ether_sprintf(eh.ether_dhost))); + ic->ic_stats.is_tx_nonode++; goto bad; } ni = ic->ic_bss; @@ -200,8 +201,10 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni) llc->llc_snap.org_code[2] = 0; llc->llc_snap.ether_type = eh.ether_type; M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); - if (m == NULL) + if (m == NULL) { + ic->ic_stats.is_tx_nombuf++; goto bad; + } wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; *(u_int16_t *)wh->i_dur = 0; @@ -312,7 +315,7 @@ int ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, int type, int arg) { -#define senderr(_x) do { ret = _x; goto bad; } while (0) +#define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0) struct ifnet *ifp = &ic->ic_if; struct mbuf *m; u_int8_t *frm; @@ -343,7 +346,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) - senderr(ENOMEM); + senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen); @@ -375,7 +378,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, + 6 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) - senderr(ENOMEM); + senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); @@ -435,7 +438,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, case IEEE80211_FC0_SUBTYPE_AUTH: MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) - senderr(ENOMEM); + senderr(ENOMEM, is_tx_nombuf); MH_ALIGN(m, 2 * 3); m->m_pkthdr.len = m->m_len = 6; frm = mtod(m, u_int8_t *); @@ -453,7 +456,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, ether_sprintf(ni->ni_macaddr), arg); MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) - senderr(ENOMEM); + senderr(ENOMEM, is_tx_nombuf); MH_ALIGN(m, 2); m->m_pkthdr.len = m->m_len = 2; *mtod(m, u_int16_t *) = htole16(arg); /* reason */ @@ -478,7 +481,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) - senderr(ENOMEM); + senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); @@ -534,7 +537,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) - senderr(ENOMEM); + senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); frm = mtod(m, u_int8_t *); @@ -565,7 +568,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, ether_sprintf(ni->ni_macaddr), arg); MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) - senderr(ENOMEM); + senderr(ENOMEM, is_tx_nombuf); MH_ALIGN(m, 2); m->m_pkthdr.len = m->m_len = 2; *mtod(m, u_int16_t *) = htole16(arg); /* reason */ @@ -574,7 +577,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, default: IEEE80211_DPRINTF(("%s: invalid mgmt frame type %u\n", __func__, type)); - senderr(EINVAL); + senderr(EINVAL, is_tx_unknownmgt); /* NOTREACHED */ } diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index c8fd126..8027aa6 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -40,6 +40,7 @@ #include <net80211/ieee80211.h> #include <net80211/ieee80211_crypto.h> +#include <net80211/ieee80211_ioctl.h> /* for ieee80211_stats */ #include <net80211/ieee80211_node.h> #include <net80211/ieee80211_proto.h> @@ -193,6 +194,7 @@ struct ieee80211com { int ic_wep_txkey; /* default tx key index */ void *ic_wep_ctx; /* wep crypt context */ u_int32_t ic_iv; /* initial vector for wep */ + struct ieee80211_stats ic_stats; /* statistics */ }; #define ic_if ic_ac.ac_if #define ic_softc ic_if.if_softc |