I'd like to add some 802.11n-related counters to netstat -W output. The first diff below is for the kernel, the second for netstat.
ok? Index: ieee80211_input.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v retrieving revision 1.171 diff -u -p -r1.171 ieee80211_input.c --- ieee80211_input.c 15 Apr 2016 03:04:27 -0000 1.171 +++ ieee80211_input.c 27 Apr 2016 11:30:08 -0000 @@ -707,7 +707,7 @@ ieee80211_input_ba(struct ieee80211com * timeout_add_usec(&ba->ba_to, ba->ba_timeout_val); if (SEQ_LT(sn, ba->ba_winstart)) { /* SN < WinStartB */ - ic->ic_stats.is_rx_dup++; + ic->ic_stats.is_ht_rx_frame_below_ba_winstart++; m_freem(m); /* discard the MPDU */ return; } @@ -730,6 +730,7 @@ ieee80211_input_ba(struct ieee80211com * "%d, expecting %d:%d\n", __func__, sn, ba->ba_winstart, ba->ba_winend); #endif + ic->ic_stats.is_ht_rx_frame_above_ba_winend++; if (count > ba->ba_winsize) { if (ba->ba_winmiss < IEEE80211_BA_MAX_WINMISS) { if (ba->ba_missedsn == sn - 1) @@ -743,6 +744,7 @@ ieee80211_input_ba(struct ieee80211com * } /* It appears the window has moved for real. */ + ic->ic_stats.is_ht_rx_ba_window_jump++; ba->ba_winmiss = 0; ba->ba_missedsn = 0; @@ -754,7 +756,8 @@ ieee80211_input_ba(struct ieee80211com * ieee80211_input(ifp, ba->ba_buf[ba->ba_head].m, ni, &ba->ba_buf[ba->ba_head].rxi); ba->ba_buf[ba->ba_head].m = NULL; - } + } else + ic->ic_stats.is_ht_rx_ba_frame_lost++; ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ; } @@ -769,6 +772,7 @@ ieee80211_input_ba(struct ieee80211com * /* store the received MPDU in the buffer */ if (ba->ba_buf[idx].m != NULL) { ifp->if_ierrors++; + ic->ic_stats.is_ht_rx_ba_no_buf++; m_freem(m); return; } @@ -820,6 +824,8 @@ ieee80211_input_ba_gap_timeout(void *arg struct ieee80211com *ic = ni->ni_ic; int s, skipped; + ic->ic_stats.is_ht_rx_ba_window_gap_timeout++; + s = splnet(); skipped = 0; @@ -828,6 +834,7 @@ ieee80211_input_ba_gap_timeout(void *arg ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ; ba->ba_winstart = (ba->ba_winstart + 1) & 0xfff; skipped++; + ic->ic_stats.is_ht_rx_ba_frame_lost++; } if (skipped > 0) ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; @@ -861,7 +868,8 @@ ieee80211_ba_move_window(struct ieee8021 ieee80211_input(ifp, ba->ba_buf[ba->ba_head].m, ni, &ba->ba_buf[ba->ba_head].rxi); ba->ba_buf[ba->ba_head].m = NULL; - } + } else + ic->ic_stats.is_ht_rx_ba_frame_lost++; ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ; } /* move window forward */ @@ -1580,6 +1588,7 @@ ieee80211_recv_probe_resp(struct ieee802 DPRINTF(("[%s] htprot change: was %d, now %d\n", ether_sprintf((u_int8_t *)wh->i_addr2), htprot_last, htprot)); + ic->ic_stats.is_ht_prot_change++; ic->ic_bss->ni_htop1 = ni->ni_htop1; ic->ic_update_htprot(ic, ic->ic_bss); } @@ -2491,6 +2500,7 @@ ieee80211_recv_addba_req(struct ieee8021 goto resp; } ba->ba_state = IEEE80211_BA_AGREED; + ic->ic_stats.is_ht_rx_ba_agreements++; /* start Block Ack inactivity timer */ if (ba->ba_timeout_val != 0) timeout_add_usec(&ba->ba_to, ba->ba_timeout_val); @@ -2561,6 +2571,7 @@ ieee80211_recv_addba_resp(struct ieee802 } /* MLME-ADDBA.confirm(Success) */ ba->ba_state = IEEE80211_BA_AGREED; + ic->ic_stats.is_ht_tx_ba_agreements++; /* notify drivers of this new Block Ack agreement */ if (ic->ic_ampdu_tx_start != NULL) Index: ieee80211_ioctl.h =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_ioctl.h,v retrieving revision 1.23 diff -u -p -r1.23 ieee80211_ioctl.h --- ieee80211_ioctl.h 12 Jan 2016 09:28:09 -0000 1.23 +++ ieee80211_ioctl.h 27 Apr 2016 11:19:38 -0000 @@ -95,6 +95,20 @@ struct ieee80211_stats { u_int32_t is_cmac_replays; u_int32_t is_cmac_icv_errs; u_int32_t is_pbac_errs; + u_int32_t is_ht_nego_no_mandatory_mcs; + u_int32_t is_ht_nego_no_basic_mcs; + u_int32_t is_ht_nego_bad_crypto; + u_int32_t is_ht_prot_change; + u_int32_t is_ht_rx_ba_agreements; + u_int32_t is_ht_tx_ba_agreements; + u_int32_t is_ht_rx_frame_below_ba_winstart; + u_int32_t is_ht_rx_frame_above_ba_winend; + u_int32_t is_ht_rx_ba_window_jump; + u_int32_t is_ht_rx_ba_no_buf; + u_int32_t is_ht_rx_ba_frame_lost; + u_int32_t is_ht_rx_ba_window_gap_timeout; + u_int32_t is_ht_rx_ba_timeout; + u_int32_t is_ht_tx_ba_timeout; }; #define SIOCG80211STATS _IOWR('i', 242, struct ifreq) Index: ieee80211_proto.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_proto.c,v retrieving revision 1.65 diff -u -p -r1.65 ieee80211_proto.c --- ieee80211_proto.c 12 Apr 2016 14:33:27 -0000 1.65 +++ ieee80211_proto.c 27 Apr 2016 10:42:05 -0000 @@ -560,15 +560,19 @@ ieee80211_ht_negotiate(struct ieee80211c return; /* Check if the peer supports HT. MCS 0-7 are mandatory. */ - if (ni->ni_rxmcs[0] != 0xff) + if (ni->ni_rxmcs[0] != 0xff) { + ic->ic_stats.is_ht_nego_no_mandatory_mcs++; return; + } if (ic->ic_opmode == IEEE80211_M_STA) { /* We must support the AP's basic MCS set. */ for (i = 0; i < IEEE80211_HT_NUM_MCS; i++) { if (isset(ni->ni_basic_mcs, i) && - !isset(ic->ic_sup_mcs, i)) + !isset(ic->ic_sup_mcs, i)) { + ic->ic_stats.is_ht_nego_no_basic_mcs++; return; + } } } @@ -576,12 +580,16 @@ ieee80211_ht_negotiate(struct ieee80211c * Don't allow group cipher (includes WEP) or TKIP * for pairwise encryption (see 802.11-2012 11.1.6). */ - if (ic->ic_flags & IEEE80211_F_WEPON) + if (ic->ic_flags & IEEE80211_F_WEPON) { + ic->ic_stats.is_ht_nego_bad_crypto++; return; + } if ((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnciphers & IEEE80211_CIPHER_USEGROUP || - ni->ni_rsnciphers & IEEE80211_CIPHER_TKIP)) + ni->ni_rsnciphers & IEEE80211_CIPHER_TKIP)) { + ic->ic_stats.is_ht_nego_bad_crypto++; return; + } ni->ni_flags |= IEEE80211_NODE_HT; } @@ -595,6 +603,8 @@ ieee80211_tx_ba_timeout(void *arg) u_int8_t tid; int s; + ic->ic_stats.is_ht_tx_ba_timeout++; + s = splnet(); if (ba->ba_state == IEEE80211_BA_REQUESTED) { /* MLME-ADDBA.confirm(TIMEOUT) */ @@ -618,6 +628,8 @@ ieee80211_rx_ba_timeout(void *arg) u_int8_t tid; int s; + ic->ic_stats.is_ht_rx_ba_timeout++; + s = splnet(); /* Block Ack inactivity timeout */ Index: net80211.c =================================================================== RCS file: /cvs/src/usr.bin/netstat/net80211.c,v retrieving revision 1.13 diff -u -p -r1.13 net80211.c --- net80211.c 16 Jan 2015 06:40:10 -0000 1.13 +++ net80211.c 27 Apr 2016 11:29:11 -0000 @@ -114,6 +114,30 @@ net80211_ifstats(char *ifname) p(is_cmac_replays, "\t%lu cmac replayed frame%s\n"); p(is_tkip_icv_errs, "\t%lu tkip icv error%s\n"); p(is_tkip_replays, "\t%lu tkip replay%s\n"); + p(is_pbac_errs, "\t%lu pbac error%s\n"); + p(is_ht_nego_no_mandatory_mcs, "\t%lu HT negotiation failure%s because " + "peer does not support MCS 0-7\n"); + p(is_ht_nego_no_mandatory_mcs, "\t%lu HT negotiation failure%s because " + "we do not support basic MCS set\n"); + p(is_ht_nego_bad_crypto, + "\t%lu HT negotiation failure%s because peer uses bad crypto\n"); + p(is_ht_prot_change, "\t%lu HT protection change%s\n"); + p(is_ht_rx_ba_agreements, "\t%lu new input block ack agreement%s\n"); + p(is_ht_tx_ba_agreements, "\t%lu new output block ack agreement%s\n"); + p(is_ht_rx_frame_below_ba_winstart, + "\t%lu input frame%s below block ack window start\n"); + p(is_ht_rx_frame_above_ba_winend, + "\t%lu input frame%s above block ack window end\n"); + p(is_ht_rx_ba_window_jump, "\t%lu input block ack window jump%s\n"); + p(is_ht_rx_ba_no_buf, "\t%lu duplicate input block ack frame%s\n"); + p(is_ht_rx_ba_frame_lost, + "\t%lu expected input block ack frame%s never arrived\n"); + p(is_ht_rx_ba_window_gap_timeout, + "\t%lu input block ack window gap%s timed out\n"); + p(is_ht_rx_ba_timeout, + "\t%lu input block ack agreement%s timed out\n"); + p(is_ht_tx_ba_timeout, + "\t%lu output block ack agreement%s timed out\n"); close(s);