Skip site navigation (1)Skip section navigation (2)
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>