PERFORCE change 63844 for review
Sam Leffler
sam at FreeBSD.org
Wed Oct 27 12:49:22 PDT 2004
http://perforce.freebsd.org/chv.cgi?CH=63844
Change 63844 by sam at 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:
More information about the p4-projects
mailing list