Date: Wed, 27 Oct 2004 19:49:20 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 63844 for review Message-ID: <200410271949.i9RJnK4H011345@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=63844 Change 63844 by sam@sam_ebb on 2004/10/27 19:48:32 add per-station statistics and an ioctl to retrieve them Affected files ... .. //depot/projects/wifi/sys/net80211/ieee80211_input.c#3 edit .. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.c#6 edit .. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#3 edit .. //depot/projects/wifi/sys/net80211/ieee80211_node.h#3 edit .. //depot/projects/wifi/sys/net80211/ieee80211_output.c#3 edit Differences ... ==== //depot/projects/wifi/sys/net80211/ieee80211_input.c#3 (text+ko) ==== @@ -223,7 +223,8 @@ ni->ni_rxseq >> IEEE80211_SEQ_SEQ_SHIFT, rxseq & IEEE80211_SEQ_FRAG_MASK, ni->ni_rxseq & IEEE80211_SEQ_FRAG_MASK); - ic->ic_stats.is_rx_dup++; /* XXX per-station stat */ + ic->ic_stats.is_rx_dup++; + IEEE80211_NODE_STAT(ni, rx_dup); goto out; } ni->ni_rxseq = rxseq; @@ -293,7 +294,8 @@ ni->ni_rxseqs[tid] >> IEEE80211_SEQ_SEQ_SHIFT, rxseq & IEEE80211_SEQ_FRAG_MASK, ni->ni_rxseqs[tid] & IEEE80211_SEQ_FRAG_MASK); - ic->ic_stats.is_rx_dup++; /* XXX per-station stat */ + ic->ic_stats.is_rx_dup++; + IEEE80211_NODE_STAT(ni, rx_dup); goto out; } ni->ni_rxseqs[tid] = rxseq; @@ -393,11 +395,13 @@ "[%s] discard WEP frame 'cuz PRIVACY " "off\n", ether_sprintf(wh->i_addr2)); ic->ic_stats.is_rx_noprivacy++; + IEEE80211_NODE_STAT(ni, rx_noprivacy); goto out; } key = ieee80211_crypto_decap(ic, ni, m); if (key == NULL) { /* NB: stats+msgs handled in crypto_decap */ + IEEE80211_NODE_STAT(ni, rx_wepfail); goto out; } } else { @@ -410,7 +414,6 @@ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { m = ieee80211_defrag(ic, ni, m); if (m == NULL) { - /* XXX statistic */ /* Fragment dropped or frame not complete yet */ goto out; } @@ -423,7 +426,7 @@ if (key != NULL && !ieee80211_crypto_demic(ic, key, m)) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT, "%s: discard frame on demic error\n", __func__); - /* XXX statistic? */ + IEEE80211_NODE_STAT(ni, rx_demicfail); goto out; } @@ -439,6 +442,7 @@ IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT, "%s: decapsulation error\n", __func__); ic->ic_stats.is_rx_decap++; + IEEE80211_NODE_STAT(ni, rx_decap); goto err; } eh = mtod(m, struct ether_header *); @@ -458,7 +462,7 @@ ether_sprintf(eh->ether_shost), eh->ether_type, m->m_pkthdr.len); ic->ic_stats.is_rx_unauth++; - /* XXX node statistic */ + IEEE80211_NODE_STAT(ni, rx_unauth); goto err; } ni->ni_inact = ic->ic_inact_auth; @@ -474,11 +478,14 @@ * Drop unencrypted frames. */ ic->ic_stats.is_rx_unencrypted++; + IEEE80211_NODE_STAT(ni, rx_unencrypted); goto out; } ni->ni_inact = ic->ic_inact_run; } ifp->if_ipackets++; + IEEE80211_NODE_STAT(ni, rx_data); + IEEE80211_NODE_STAT_ADD(ni, rx_bytes, m->m_pkthdr.len); /* perform as a bridge within the AP */ if (ic->ic_opmode == IEEE80211_M_HOSTAP && @@ -524,6 +531,7 @@ return; case IEEE80211_FC0_TYPE_MGT: + IEEE80211_NODE_STAT(ni, rx_mgmt); if (dir != IEEE80211_FC1_DIR_NODS) { ic->ic_stats.is_rx_wrongdir++; goto err; @@ -582,6 +590,7 @@ return; case IEEE80211_FC0_TYPE_CTL: + IEEE80211_NODE_STAT(ni, rx_ctrl); ic->ic_stats.is_rx_ctl++; if (ic->ic_opmode != IEEE80211_M_HOSTAP) goto out; @@ -668,7 +677,7 @@ if (mfrag == NULL) { if (fragno != 0) { /* !first fragment, discard */ - /* XXX statistic */ + IEEE80211_NODE_STAT(ni, rx_defrag); m_freem(m); return NULL; } @@ -1594,7 +1603,9 @@ * use this info to do things like update LED's. */ ic->ic_stats.is_rx_beacon++; - } + IEEE80211_NODE_STAT(ni, rx_beacons); + } else + IEEE80211_NODE_STAT(ni, rx_proberesp); /* * We process beacon/probe response frames for: * o station mode when associated: to collect state @@ -2316,6 +2327,7 @@ IEEE80211_VERIFY_LENGTH(efrm - frm, 2); reason = le16toh(*(u_int16_t *)frm); ic->ic_stats.is_rx_deauth++; + IEEE80211_NODE_STAT(ni, rx_deauth); switch (ic->ic_opmode) { case IEEE80211_M_STA: ieee80211_new_state(ic, IEEE80211_S_AUTH, @@ -2352,6 +2364,7 @@ IEEE80211_VERIFY_LENGTH(efrm - frm, 2); reason = le16toh(*(u_int16_t *)frm); ic->ic_stats.is_rx_disassoc++; + IEEE80211_NODE_STAT(ni, rx_disassoc); switch (ic->ic_opmode) { case IEEE80211_M_STA: ieee80211_new_state(ic, IEEE80211_S_ASSOC, ==== //depot/projects/wifi/sys/net80211/ieee80211_ioctl.c#6 (text+ko) ==== @@ -912,6 +912,31 @@ } static int +ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq) +{ + struct ieee80211_node *ni; + u_int8_t macaddr[IEEE80211_ADDR_LEN]; + const int off = __offsetof(struct ieee80211req_sta_stats, is_stats); + int error; + + if (ireq->i_len < off) + return EINVAL; + error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN); + if (error != 0) + return error; + ni = ieee80211_find_node(ic, macaddr); + if (ni == NULL) + return EINVAL; /* XXX */ + if (ireq->i_len > sizeof(struct ieee80211req_sta_stats)) + ireq->i_len = sizeof(struct ieee80211req_sta_stats); + /* NB: copy out only the statistics */ + error = copyout(&ni->ni_stats, (u_int8_t *) ireq->i_data + off, + ireq->i_len - off); + ieee80211_free_node(ic, ni); + return error; +} + +static int ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq) { union { @@ -1154,6 +1179,9 @@ case IEEE80211_IOC_SCAN_RESULTS: error = ieee80211_ioctl_getscanresults(ic, ireq); break; + case IEEE80211_IOC_STA_STATS: + error = ieee80211_ioctl_getstastats(ic, ireq); + break; default: error = EINVAL; break; ==== //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#3 (text+ko) ==== @@ -50,34 +50,40 @@ u_int32_t ns_rx_ucast; /* rx unicast frames */ u_int32_t ns_rx_mcast; /* rx multi/broadcast frames */ u_int64_t ns_rx_bytes; /* rx data count (bytes) */ + u_int64_t ns_rx_beacons; /* rx beacon frames */ + u_int32_t ns_rx_proberesp; /* rx probe response frames */ u_int32_t ns_rx_dup; /* rx discard 'cuz dup */ u_int32_t ns_rx_noprivacy; /* rx w/ wep but privacy off */ u_int32_t ns_rx_wepfail; /* rx wep processing failed */ + u_int32_t ns_rx_demicfail; /* rx demic failed */ u_int32_t ns_rx_decap; /* rx decapsulation failed */ + u_int32_t ns_rx_defrag; /* rx defragmentation failed */ u_int32_t ns_rx_disassoc; /* rx disassociation */ u_int32_t ns_rx_deauth; /* rx deauthentication */ u_int32_t ns_rx_decryptcrc; /* rx decrypt failed on crc */ u_int32_t ns_rx_unauth; /* rx on unauthorized port */ + u_int32_t ns_rx_unencrypted; /* rx unecrypted w/ privacy */ u_int32_t ns_tx_data; /* tx data frames */ u_int32_t ns_tx_mgmt; /* tx management frames */ u_int32_t ns_tx_ucast; /* tx unicast frames */ u_int32_t ns_tx_mcast; /* tx multi/broadcast frames */ u_int64_t ns_tx_bytes; /* tx data count (bytes) */ + u_int32_t ns_tx_probereq; /* tx probe request frames */ u_int32_t ns_tx_novlantag; /* tx discard 'cuz no tag */ u_int32_t ns_tx_vlanmismatch; /* tx discard 'cuz bad tag */ /* MIB-related state */ - u_int32_t ns_mib_assoc; /* [re]associations */ - u_int32_t ns_mib_assoc_fail; /* [re]association failures */ - u_int32_t ns_mib_auth; /* [re]authentications */ - u_int32_t ns_mib_auth_fail; /* [re]authentication failures*/ - u_int32_t ns_mib_deauth; /* deauthentications */ - u_int32_t ns_mib_deauth_code; /* last deauth reason */ - u_int32_t ns_mib_disassoc; /* disassociations */ - u_int32_t ns_mib_disassoc_code; /* last disassociation reason */ + u_int32_t ns_tx_assoc; /* [re]associations */ + u_int32_t ns_tx_assoc_fail; /* [re]association failures */ + u_int32_t ns_tx_auth; /* [re]authentications */ + u_int32_t ns_tx_auth_fail; /* [re]authentication failures*/ + u_int32_t ns_tx_deauth; /* deauthentications */ + u_int32_t ns_tx_deauth_code; /* last deauth reason */ + u_int32_t ns_tx_disassoc; /* disassociations */ + u_int32_t ns_tx_disassoc_code; /* last disassociation reason */ }; /* @@ -246,6 +252,18 @@ u_int8_t wpa_ie[IEEE80211_MAX_OPT_IE]; }; +/* + * Retrieve per-node statistics. + */ +struct ieee80211req_sta_stats { + union { + /* NB: explicitly force 64-bit alignment */ + u_int8_t macaddr[IEEE80211_ADDR_LEN]; + u_int64_t pad; + } is_u; + struct ieee80211_nodestats is_stats; +}; + #ifdef __FreeBSD__ /* * FreeBSD-style ioctls. @@ -313,6 +331,7 @@ #define IEEE80211_IOC_KEYMGTALGS 37 /* key management algorithms */ #define IEEE80211_IOC_RSNCAPS 38 /* RSN capabilities */ #define IEEE80211_IOC_WPAIE 39 /* WPA information element */ +#define IEEE80211_IOC_STA_STATS 40 /* per-station statistics */ #ifndef IEEE80211_CHAN_ANY #define IEEE80211_CHAN_ANY 0xffff /* token for ``any channel'' */ ==== //depot/projects/wifi/sys/net80211/ieee80211_node.h#3 (text+ko) ==== @@ -159,6 +159,10 @@ #define IEEE80211_NODE_AID(ni) IEEE80211_AID(ni->ni_associd) +#define IEEE80211_NODE_STAT(ni,stat) (ni->ni_stats.ns_##stat++) +#define IEEE80211_NODE_STAT_ADD(ni,stat,v) (ni->ni_stats.ns_##stat += v) +#define IEEE80211_NODE_STAT_SET(ni,stat,v) (ni->ni_stats.ns_##stat = v) + static __inline struct ieee80211_node * ieee80211_ref_node(struct ieee80211_node *ni) { ==== //depot/projects/wifi/sys/net80211/ieee80211_output.c#3 (text+ko) ==== @@ -142,6 +142,7 @@ ieee80211_chan2ieee(ic, ni->ni_chan)); } #endif + IEEE80211_NODE_STAT(ni, tx_mgmt); IF_ENQUEUE(&ic->ic_mgtq, m); ifp->if_timer = 1; if_start(ifp); @@ -260,7 +261,7 @@ struct ieee80211_node *ni = NULL; struct ieee80211_key *key; struct llc *llc; - int hdrsize; + int hdrsize, datalen; if (m->m_len < sizeof(struct ether_header) && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { @@ -285,11 +286,11 @@ if (ni->ni_vlan != 0) { struct m_tag *mtag = VLAN_OUTPUT_TAG(ic->ic_ifp, m); if (mtag != NULL) { - ni->ni_stats.ns_tx_novlantag++; + IEEE80211_NODE_STAT(ni, tx_novlantag); goto bad; } if (VLAN_TAG_VALUE(mtag) != ni->ni_vlan) { - ni->ni_stats.ns_tx_vlanmismatch++; + IEEE80211_NODE_STAT(ni, tx_vlanmismatch); goto bad; } } @@ -332,6 +333,7 @@ llc->llc_snap.org_code[1] = 0; llc->llc_snap.org_code[2] = 0; llc->llc_snap.ether_type = eh.ether_type; + datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ M_PREPEND(m, hdrsize, M_DONTWAIT); if (m == NULL) { @@ -444,6 +446,10 @@ */ ni->ni_inact = ic->ic_inact_run; } + + IEEE80211_NODE_STAT(ni, tx_data); + IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); + *pni = ni; return m; bad: @@ -791,6 +797,7 @@ } m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); + IEEE80211_NODE_STAT(ni, tx_probereq); timer = IEEE80211_TRANS_WAIT; break; @@ -920,6 +927,13 @@ } } else m->m_pkthdr.len = m->m_len = 3 * sizeof(u_int16_t); + + /* XXX not right for shared key */ + if (status == IEEE80211_STATUS_SUCCESS) + IEEE80211_NODE_STAT(ni, tx_auth); + else + IEEE80211_NODE_STAT(ni, tx_auth_fail); + /* * When 802.1x is not in use mark the port * authorized at this point so traffic can flow. @@ -942,6 +956,9 @@ *(u_int16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(u_int16_t); + IEEE80211_NODE_STAT(ni, tx_deauth); + IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); + ieee80211_node_unauthorize(ic, ni); /* port closed */ break; @@ -1047,8 +1064,11 @@ *(u_int16_t *)frm = htole16(arg); /* status */ frm += 2; - if (arg == IEEE80211_STATUS_SUCCESS) + if (arg == IEEE80211_STATUS_SUCCESS) { *(u_int16_t *)frm = htole16(ni->ni_associd); + IEEE80211_NODE_STAT(ni, tx_assoc); + } else + IEEE80211_NODE_STAT(ni, tx_assoc_fail); frm += 2; frm = ieee80211_add_rates(frm, &ni->ni_rates); @@ -1065,6 +1085,9 @@ senderr(ENOMEM, is_tx_nobuf); *(u_int16_t *)frm = htole16(arg); /* reason */ m->m_pkthdr.len = m->m_len = sizeof(u_int16_t); + + IEEE80211_NODE_STAT(ni, tx_disassoc); + IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); break; default:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200410271949.i9RJnK4H011345>