On Mon, Mar 07, 2022 at 03:04:06PM -0700, Theo de Raadt wrote:
> > For now, the structs are identical so the code copying data out is
> > kept simple.
>
> I think this is unwise, and you should write the field-by-field copying
> function at the same time, otherwise this is just asking for trouble.
> You really cannot wait until an intentional change.
Sure, here it is.
diff 0ed925b6612724f216b84360a04117aad1c6df9b
6615def0a9e782a7fd930d75fda1ae4ec0f90dd2
blob - 85d795d745eb21fd218056c2f3faf7fbc2c7fe49
blob + d4f6b536b2eb2165f85f9df7c08a1cee36a428a4
--- sys/net80211/ieee80211_ioctl.c
+++ sys/net80211/ieee80211_ioctl.c
@@ -55,6 +55,7 @@ void ieee80211_node2req(struct ieee80211com *,
const struct ieee80211_node *, struct ieee80211_nodereq *);
void ieee80211_req2node(struct ieee80211com *,
const struct ieee80211_nodereq *, struct ieee80211_node *);
+struct ieee80211_statsreq *ieee80211_stats2req(struct ieee80211_stats *);
void
ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
@@ -179,6 +180,94 @@ ieee80211_req2node(struct ieee80211com *ic, const stru
ni->ni_state = nr->nr_state;
}
+struct ieee80211_statsreq *
+ieee80211_stats2req(struct ieee80211_stats *stats)
+{
+ struct ieee80211_statsreq *req;
+
+ req = malloc(sizeof(*req), M_DEVBUF, M_ZERO | M_WAITOK | M_CANFAIL);
+ if (req == NULL)
+ return NULL;
+
+ req->is_rx_badversion = stats->is_rx_badversion;
+ req->is_rx_tooshort = stats->is_rx_tooshort;
+ req->is_rx_wrongbss = stats->is_rx_wrongbss;
+ req->is_rx_dup = stats->is_rx_dup;
+ req->is_rx_wrongdir = stats->is_rx_wrongdir;
+ req->is_rx_mcastecho = stats->is_rx_mcastecho;
+ req->is_rx_notassoc = stats->is_rx_notassoc;
+ req->is_rx_nowep = stats->is_rx_nowep;
+ req->is_rx_unencrypted = stats->is_rx_unencrypted;
+ req->is_rx_wepfail = stats->is_rx_wepfail;
+ req->is_rx_decap = stats->is_rx_decap;
+ req->is_rx_mgtdiscard = stats->is_rx_mgtdiscard;
+ req->is_rx_ctl = stats->is_rx_ctl;
+ req->is_rx_rstoobig = stats->is_rx_rstoobig;
+ req->is_rx_elem_missing = stats->is_rx_elem_missing;
+ req->is_rx_elem_toobig = stats->is_rx_elem_toobig;
+ req->is_rx_elem_toosmall = stats->is_rx_elem_toosmall;
+ req->is_rx_badchan = stats->is_rx_badchan;
+ req->is_rx_chanmismatch = stats->is_rx_chanmismatch;
+ req->is_rx_nodealloc = stats->is_rx_nodealloc;
+ req->is_rx_ssidmismatch = stats->is_rx_ssidmismatch;
+ req->is_rx_auth_unsupported = stats->is_rx_auth_unsupported;
+ req->is_rx_auth_fail = stats->is_rx_auth_fail;
+ req->is_rx_assoc_bss = stats->is_rx_assoc_bss;
+ req->is_rx_assoc_notauth = stats->is_rx_assoc_notauth;
+ req->is_rx_assoc_capmismatch = stats->is_rx_assoc_capmismatch;
+ req->is_rx_assoc_norate = stats->is_rx_assoc_norate;
+ req->is_rx_deauth = stats->is_rx_deauth;
+ req->is_rx_disassoc = stats->is_rx_disassoc;
+ req->is_rx_badsubtype = stats->is_rx_badsubtype;
+ req->is_rx_nombuf = stats->is_rx_nombuf;
+ req->is_rx_decryptcrc = stats->is_rx_decryptcrc;
+ req->is_rx_ahdemo_mgt = stats->is_rx_ahdemo_mgt;
+ req->is_rx_bad_auth = stats->is_rx_bad_auth;
+ req->is_tx_nombuf = stats->is_tx_nombuf;
+ req->is_tx_nonode = stats->is_tx_nonode;
+ req->is_tx_unknownmgt = stats->is_tx_unknownmgt;
+ req->is_scan_active = stats->is_scan_active;
+ req->is_scan_passive = stats->is_scan_passive;
+ req->is_node_timeout = stats->is_node_timeout;
+ req->is_crypto_nomem = stats->is_crypto_nomem;
+ req->is_rx_assoc_badrsnie = stats->is_rx_assoc_badrsnie;
+ req->is_rx_unauth = stats->is_rx_unauth;
+ req->is_tx_noauth = stats->is_tx_noauth;
+ req->is_rx_eapol_key = stats->is_rx_eapol_key;
+ req->is_rx_eapol_replay = stats->is_rx_eapol_replay;
+ req->is_rx_eapol_badmic = stats->is_rx_eapol_badmic;
+ req->is_rx_remmicfail = stats->is_rx_remmicfail;
+ req->is_rx_locmicfail = stats->is_rx_locmicfail;
+ req->is_tkip_replays = stats->is_tkip_replays;
+ req->is_tkip_icv_errs = stats->is_tkip_icv_errs;
+ req->is_ccmp_replays = stats->is_ccmp_replays;
+ req->is_ccmp_dec_errs = stats->is_ccmp_dec_errs;
+ req->is_cmac_replays = stats->is_cmac_replays;
+ req->is_cmac_icv_errs = stats->is_cmac_icv_errs;
+ req->is_pbac_errs = stats->is_pbac_errs;
+ req->is_ht_nego_no_mandatory_mcs = stats->is_ht_nego_no_mandatory_mcs;
+ req->is_ht_nego_no_basic_mcs = stats->is_ht_nego_no_basic_mcs;
+ req->is_ht_nego_bad_crypto = stats->is_ht_nego_bad_crypto;
+ req->is_ht_prot_change = stats->is_ht_prot_change;
+ req->is_ht_rx_ba_agreements = stats->is_ht_rx_ba_agreements;
+ req->is_ht_tx_ba_agreements = stats->is_ht_tx_ba_agreements;
+ req->is_ht_rx_frame_below_ba_winstart =
+ stats->is_ht_rx_frame_below_ba_winstart;
+ req->is_ht_rx_frame_above_ba_winend =
+ stats->is_ht_rx_frame_above_ba_winend;
+ req->is_ht_rx_ba_window_slide = stats->is_ht_rx_ba_window_slide;
+ req->is_ht_rx_ba_window_jump = stats->is_ht_rx_ba_window_jump;
+ req->is_ht_rx_ba_no_buf = stats->is_ht_rx_ba_no_buf;
+ req->is_ht_rx_ba_frame_lost = stats->is_ht_rx_ba_frame_lost;
+ req->is_ht_rx_ba_window_gap_timeout =
+ stats->is_ht_rx_ba_window_gap_timeout;
+ req->is_ht_rx_ba_timeout = stats->is_ht_rx_ba_timeout;
+ req->is_ht_tx_ba_timeout = stats->is_ht_tx_ba_timeout;
+
+ return req;
+}
+
+
void
ieee80211_disable_wep(struct ieee80211com *ic)
{
@@ -471,6 +560,7 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t
struct ieee80211_node *ni;
struct ieee80211_chaninfo chaninfo;
struct ieee80211_chanreq_all *allchans;
+ struct ieee80211_statsreq *statsreq;
u_int32_t flags;
switch (cmd) {
@@ -810,17 +900,15 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t
break;
}
break;
-#if 0
- case SIOCG80211ZSTATS:
-#endif
case SIOCG80211STATS:
ifr = (struct ifreq *)data;
- error = copyout(&ic->ic_stats, ifr->ifr_data,
- sizeof(ic->ic_stats));
-#if 0
- if (cmd == SIOCG80211ZSTATS)
- memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
-#endif
+ statsreq = ieee80211_stats2req(&ic->ic_stats);
+ if (statsreq == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ error = copyout(statsreq, ifr->ifr_data, sizeof(*statsreq));
+ free(statsreq, M_DEVBUF, sizeof(*statsreq));
break;
case SIOCS80211TXPOWER:
if ((error = suser(curproc)) != 0)
blob - 65e93c23da2d86c0ad259f77b7c9affc85d9038b
blob + fa95ad15b809e16868e2eba4dba66568b5a66cfe
--- sys/net80211/ieee80211_ioctl.h
+++ sys/net80211/ieee80211_ioctl.h
@@ -37,8 +37,8 @@
* IEEE 802.11 ioctls.
*/
-/* per-interface statistics */
-struct ieee80211_stats {
+/* per-interface statistics, corresponds to struct ieee80211_stats */
+struct ieee80211_statsreq {
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 */
blob - 161853a629887a1aa997480d605d4febd66dd2db
blob + d8845bfc6aa1331110ca22ec949a00932645907e
--- sys/net80211/ieee80211_var.h
+++ sys/net80211/ieee80211_var.h
@@ -214,6 +214,81 @@ struct ieee80211_defrag {
struct ieee80211_node_switch_bss_arg;
+/* per-interface statistics */
+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_unencrypted; /* rx w/o 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_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 */
+ u_int32_t is_rx_assoc_badrsnie; /* rx assoc w/ bad RSN IE */
+ u_int32_t is_rx_unauth; /* rx port not valid */
+ u_int32_t is_tx_noauth; /* tx port not valid */
+ u_int32_t is_rx_eapol_key; /* rx eapol-key frames */
+ u_int32_t is_rx_eapol_replay; /* rx replayed eapol frames */
+ u_int32_t is_rx_eapol_badmic; /* rx eapol frames w/ bad mic */
+ u_int32_t is_rx_remmicfail; /* rx tkip remote mic fails */
+ u_int32_t is_rx_locmicfail; /* rx tkip local mic fails */
+ u_int32_t is_tkip_replays;
+ u_int32_t is_tkip_icv_errs;
+ u_int32_t is_ccmp_replays;
+ u_int32_t is_ccmp_dec_errs;
+ 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_slide;
+ 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;
+};
+
struct ieee80211com {
struct arpcom ic_ac;
LIST_ENTRY(ieee80211com) ic_list; /* chain of all ieee80211com */
blob - de136e4dd7a5da0f5a38c7de42fd2d646592fcd8
blob + e2076ffeae43eb877108e997828b5481bef0a4e7
--- usr.bin/netstat/net80211.c
+++ usr.bin/netstat/net80211.c
@@ -41,7 +41,7 @@ void
net80211_ifstats(char *ifname)
{
struct ifreq ifr;
- struct ieee80211_stats stats;
+ struct ieee80211_statsreq stats;
int s;
#define p(f, m) printf(m, (unsigned long)stats.f, plural(stats.f))