Re: ieee80211_stats userland vs. kernel

2022-03-09 Thread Stefan Sperling
On Tue, Mar 08, 2022 at 02:38:39PM -0700, Theo de Raadt wrote:
> Stefan Sperling  wrote:
> > In this case it is not ifconfig, but netstat -W iwm0.
> > Which is a debugging tool, like netstat -s.
> 
> We don't care when netstat breaks

Alright, then this diff is indeed not necessary.



Re: ieee80211_stats userland vs. kernel

2022-03-08 Thread Theo de Raadt
Stefan Sperling  wrote:

> On Tue, Mar 08, 2022 at 12:58:27PM -0700, Theo de Raadt wrote:
> > Claudio Jeker  wrote:
> > 
> > > Honestly I think this is overkill. There is no stat struct where we do
> > > this dance. It is accepted that netstat needs to keep in sync for these
> > > structs to work. Why is it necessary to disconnect the kernel and userland
> > > for this?
> > 
> > Actually there is a major one: it is how ps works.
> > 
> > I think the problem is when this struct is changed, ifconfig becomes 
> > unusable?
> 
> In this case it is not ifconfig, but netstat -W iwm0.
> Which is a debugging tool, like netstat -s.

We don't care when netstat breaks

But we really care when ifconfig breaks, in particular in the area of the
"media" command related things.



Re: ieee80211_stats userland vs. kernel

2022-03-08 Thread Stefan Sperling
On Tue, Mar 08, 2022 at 12:58:27PM -0700, Theo de Raadt wrote:
> Claudio Jeker  wrote:
> 
> > Honestly I think this is overkill. There is no stat struct where we do
> > this dance. It is accepted that netstat needs to keep in sync for these
> > structs to work. Why is it necessary to disconnect the kernel and userland
> > for this?
> 
> Actually there is a major one: it is how ps works.
> 
> I think the problem is when this struct is changed, ifconfig becomes unusable?

In this case it is not ifconfig, but netstat -W iwm0.
Which is a debugging tool, like netstat -s.



Re: ieee80211_stats userland vs. kernel

2022-03-08 Thread Theo de Raadt
Claudio Jeker  wrote:

> Honestly I think this is overkill. There is no stat struct where we do
> this dance. It is accepted that netstat needs to keep in sync for these
> structs to work. Why is it necessary to disconnect the kernel and userland
> for this?

Actually there is a major one: it is how ps works.

I think the problem is when this struct is changed, ifconfig becomes unusable?

Making a different userland & kernel struct might not solve it, unless some
games are played.  For instance, append extra pads for future extension, so
that the ioctl can still get at the data when fields are used.  Discourage
changing the types/sizes of fields.  When a field is removed, change it into
a pad rather than shuffling the struct.  Eventually we'll hit a flag day.
But with this current design, I think we'll trip into kernel:userland ABI
breakage too easily, and it just needs some clever policy around the struct
to ensure it doesn't cause that breakage.



Re: ieee80211_stats userland vs. kernel

2022-03-08 Thread Claudio Jeker
On Tue, Mar 08, 2022 at 07:17:33PM +0100, Stefan Sperling wrote:
> On Tue, Mar 08, 2022 at 03:55:48PM +0100, Stefan Sperling wrote:
> > 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.
> 
> On second thought, avoiding the malloc/free dance is better.
> The struct is still small enough to fit on the stack.
> 
> diff refs/heads/master refs/heads/statsreq
> blob - 85d795d745eb21fd218056c2f3faf7fbc2c7fe49
> blob + 62938001ed22fc133a0c98e27ef5690c978e21f3
> --- sys/net80211/ieee80211_ioctl.c
> +++ sys/net80211/ieee80211_ioctl.c
> @@ -55,6 +55,8 @@ void ieee80211_node2req(struct ieee80211com *,
>   const struct ieee80211_node *, struct ieee80211_nodereq *);
>  void  ieee80211_req2node(struct ieee80211com *,
>   const struct ieee80211_nodereq *, struct ieee80211_node *);
> +void ieee80211_stats2req(struct ieee80211_statsreq *,
> + struct ieee80211_stats *);
>  
>  void
>  ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
> @@ -180,6 +182,89 @@ ieee80211_req2node(struct ieee80211com *ic, const stru
>  }
>  
>  void
> +ieee80211_stats2req(struct ieee80211_statsreq *req,
> +struct ieee80211_stats *stats)
> +{
> + memset(req, 0, sizeof(*req));
> +
> + 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 = 

Re: ieee80211_stats userland vs. kernel

2022-03-08 Thread Stefan Sperling
On Tue, Mar 08, 2022 at 03:55:48PM +0100, Stefan Sperling wrote:
> 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.

On second thought, avoiding the malloc/free dance is better.
The struct is still small enough to fit on the stack.

diff refs/heads/master refs/heads/statsreq
blob - 85d795d745eb21fd218056c2f3faf7fbc2c7fe49
blob + 62938001ed22fc133a0c98e27ef5690c978e21f3
--- sys/net80211/ieee80211_ioctl.c
+++ sys/net80211/ieee80211_ioctl.c
@@ -55,6 +55,8 @@ void   ieee80211_node2req(struct ieee80211com *,
const struct ieee80211_node *, struct ieee80211_nodereq *);
 voidieee80211_req2node(struct ieee80211com *,
const struct ieee80211_nodereq *, struct ieee80211_node *);
+void ieee80211_stats2req(struct ieee80211_statsreq *,
+   struct ieee80211_stats *);
 
 void
 ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
@@ -180,6 +182,89 @@ ieee80211_req2node(struct ieee80211com *ic, const stru
 }
 
 void
+ieee80211_stats2req(struct ieee80211_statsreq *req,
+struct ieee80211_stats *stats)
+{
+   memset(req, 0, sizeof(*req));
+
+   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 

Re: ieee80211_stats userland vs. kernel

2022-03-08 Thread Stefan Sperling
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 *);
 voidieee80211_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 =
+   

Re: ieee80211_stats userland vs. kernel

2022-03-07 Thread Theo de Raadt
> 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.



ieee80211_stats userland vs. kernel

2022-03-07 Thread Stefan Sperling
There is another net80211 ioctl which shares a struct between kernel
and userland: struct ieee80211_stats shown by the netstat -W command.

While it is trivial to recompile netstat when this struct is changed,
giving the kernel a separate struct type would allow us to add, change,
or remove counters in the kernel without impacting userland immediately.
Is this worth it?

For now, the structs are identical so the code copying data out is
kept simple.

The struct is quite large and we could probably get rid of some of these
counters without losing useful debugging information, but that is a
separate problem.

Warning: This diff seems to overflow miniroot71.img on amd64,
breaking 'make release' builds without further changes.

diff 7f506de28f9813c0e2213a45686e27166679219e 
64e5109ffcdce254aca22d4a8a40991e792c0738
blob - 85d795d745eb21fd218056c2f3faf7fbc2c7fe49
blob + a3a734d32123ff96870e24efeb30651bfd0b50be
--- sys/net80211/ieee80211_ioctl.c
+++ sys/net80211/ieee80211_ioctl.c
@@ -810,17 +810,11 @@ 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_stats, ifr->ifr_data,
-   sizeof(ic->ic_stats));
-#if 0
-   if (cmd == SIOCG80211ZSTATS)
-   memset(>ic_stats, 0, sizeof(ic->ic_stats));
-#endif
+   MIN(sizeof(struct ieee80211_statsreq),
+   sizeof(struct ieee80211_stats)));
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