add preliminary 2.6.32 support
[openwrt.git] / package / madwifi / patches / 416-wprobe.patch
1 --- /dev/null
2 +++ b/ath/ath_wprobe.c
3 @@ -0,0 +1,433 @@
4 +#include <net80211/ieee80211_node.h>
5 +#include <linux/wprobe.h>
6 +
7 +atomic_t cleanup_tasks = ATOMIC_INIT(0);
8 +
9 +enum wp_node_val {
10 +       WP_NODE_RSSI,
11 +       WP_NODE_SIGNAL,
12 +       WP_NODE_RX_RATE,
13 +       WP_NODE_TX_RATE,
14 +       WP_NODE_RETRANSMIT_200,
15 +       WP_NODE_RETRANSMIT_400,
16 +       WP_NODE_RETRANSMIT_800,
17 +       WP_NODE_RETRANSMIT_1600,
18 +};
19 +
20 +enum wp_global_val {
21 +       WP_GLOBAL_NOISE,
22 +       WP_GLOBAL_PHY_BUSY,
23 +       WP_GLOBAL_PHY_RX,
24 +       WP_GLOBAL_PHY_TX,
25 +       WP_GLOBAL_FRAMES,
26 +       WP_GLOBAL_PROBEREQ,
27 +};
28 +
29 +static struct wprobe_item ath_wprobe_globals[] = {
30 +       [WP_GLOBAL_NOISE] = {
31 +               .name = "noise",
32 +               .type = WPROBE_VAL_S16,
33 +               .flags = WPROBE_F_KEEPSTAT
34 +       },
35 +       [WP_GLOBAL_PHY_BUSY] = {
36 +               .name = "phy_busy",
37 +               .type = WPROBE_VAL_U8,
38 +               .flags = WPROBE_F_KEEPSTAT
39 +       },
40 +       [WP_GLOBAL_PHY_RX] = {
41 +               .name = "phy_rx",
42 +               .type = WPROBE_VAL_U8,
43 +               .flags = WPROBE_F_KEEPSTAT
44 +       },
45 +       [WP_GLOBAL_PHY_TX] = {
46 +               .name = "phy_tx",
47 +               .type = WPROBE_VAL_U8,
48 +               .flags = WPROBE_F_KEEPSTAT
49 +       },
50 +       [WP_GLOBAL_FRAMES] = {
51 +               .name = "frames",
52 +               .type = WPROBE_VAL_U32,
53 +       },
54 +       [WP_GLOBAL_PROBEREQ] = {
55 +               .name = "probereq",
56 +               .type = WPROBE_VAL_U32,
57 +       },
58 +};
59 +
60 +static struct wprobe_item ath_wprobe_link[] = {
61 +       [WP_NODE_RSSI] = {
62 +               .name = "rssi",
63 +               .type = WPROBE_VAL_U8,
64 +               .flags = WPROBE_F_KEEPSTAT
65 +       },
66 +       [WP_NODE_SIGNAL] = {
67 +               .name = "signal",
68 +               .type = WPROBE_VAL_S16,
69 +               .flags = WPROBE_F_KEEPSTAT
70 +       },
71 +       [WP_NODE_RX_RATE] = {
72 +               .name = "rx_rate",
73 +               .type = WPROBE_VAL_U16,
74 +               .flags = WPROBE_F_KEEPSTAT
75 +       },
76 +       [WP_NODE_TX_RATE] = {
77 +               .name = "tx_rate",
78 +               .type = WPROBE_VAL_U16,
79 +               .flags = WPROBE_F_KEEPSTAT
80 +       },
81 +       [WP_NODE_RETRANSMIT_200] = {
82 +               .name = "retransmit_200",
83 +               .type = WPROBE_VAL_U8,
84 +               .flags = WPROBE_F_KEEPSTAT
85 +       },
86 +       [WP_NODE_RETRANSMIT_400] = {
87 +               .name = "retransmit_400",
88 +               .type = WPROBE_VAL_U8,
89 +               .flags = WPROBE_F_KEEPSTAT
90 +       },
91 +       [WP_NODE_RETRANSMIT_800] = {
92 +               .name = "retransmit_800",
93 +               .type = WPROBE_VAL_U8,
94 +               .flags = WPROBE_F_KEEPSTAT
95 +       },
96 +       [WP_NODE_RETRANSMIT_1600] = {
97 +               .name = "retransmit_1600",
98 +               .type = WPROBE_VAL_U8,
99 +               .flags = WPROBE_F_KEEPSTAT
100 +       },
101 +};
102 +
103 +#define AR5K_MIBC       0x0040
104 +#define AR5K_MIBC_FREEZE       (1 << 1)
105 +#define AR5K_TXFC       0x80ec
106 +#define AR5K_RXFC       0x80f0
107 +#define AR5K_RXCLEAR    0x80f4
108 +#define AR5K_CYCLES     0x80f8
109 +
110 +#define READ_CLR(_ah, _reg) \
111 +       ({ u32 __val = OS_REG_READ(_ah, _reg); OS_REG_WRITE(_ah, _reg, 0); __val; })
112 +
113 +static bool
114 +wprobe_disabled(void)
115 +{
116 +       return (!wprobe_add_iface || IS_ERR(wprobe_add_iface));
117 +}
118 +
119 +static int
120 +ath_wprobe_sync(struct wprobe_iface *dev, struct wprobe_link *l, struct wprobe_value *val, bool measure)
121 +{
122 +       struct ath_vap *avp = container_of(dev, struct ath_vap, av_wpif);
123 +       struct ieee80211vap *vap = &avp->av_vap;
124 +       struct ieee80211com *ic = vap->iv_ic;
125 +       struct ath_softc *sc = ic->ic_dev->priv;
126 +       struct ath_hal *ah = sc->sc_ah;
127 +       u32 cc, busy, rx, tx;
128 +       s16 noise;
129 +
130 +       if (l)
131 +               goto out;
132 +
133 +       OS_REG_WRITE(ah, AR5K_MIBC, AR5K_MIBC_FREEZE);
134 +       cc = READ_CLR(ah, AR5K_CYCLES);
135 +       busy = READ_CLR(ah, AR5K_RXCLEAR);
136 +       rx = READ_CLR(ah, AR5K_RXFC);
137 +       tx = READ_CLR(ah, AR5K_TXFC);
138 +       OS_REG_WRITE(ah, AR5K_MIBC, 0);
139 +       noise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan));
140 +       ic->ic_channoise = noise;
141 +
142 +       WPROBE_FILL_BEGIN(val, ath_wprobe_globals);
143 +       if (cc & 0xf0000000) {
144 +               /* scale down if the counters are near max */
145 +               cc >>= 8;
146 +               busy >>= 8;
147 +               rx >>= 8;
148 +               tx >>= 8;
149 +       }
150 +       if (ah->ah_macType < 5212)
151 +               goto phy_skip;
152 +       if (!cc)
153 +               goto phy_skip;
154 +       if (busy > cc)
155 +               goto phy_skip;
156 +       if (rx > cc)
157 +               goto phy_skip;
158 +       if (tx > cc)
159 +               goto phy_skip;
160 +       busy = (busy * 100) / cc;
161 +       rx = (rx * 100) / cc;
162 +       tx = (tx * 100) / cc;
163 +       WPROBE_SET(WP_GLOBAL_PHY_BUSY, U8, busy);
164 +       WPROBE_SET(WP_GLOBAL_PHY_RX, U8, rx);
165 +       WPROBE_SET(WP_GLOBAL_PHY_TX, U8, tx);
166 +       WPROBE_SET(WP_GLOBAL_FRAMES, U32, avp->av_rxframes);
167 +       WPROBE_SET(WP_GLOBAL_PROBEREQ, U32, avp->av_rxprobereq);
168 +
169 +phy_skip:
170 +       WPROBE_SET(WP_GLOBAL_NOISE, S16, noise);
171 +       WPROBE_FILL_END();
172 +
173 +out:
174 +       return 0;
175 +}
176 +
177 +#undef AR5K_TXFC
178 +#undef AR5K_RXFC
179 +#undef AR5K_RXCLEAR
180 +#undef AR5K_CYCLES
181 +#undef AR5K_MIBC
182 +#undef AR5K_MIBC_FREEZE
183 +#undef READ_CLR
184 +
185 +static const struct wprobe_iface ath_wprobe_dev = {
186 +       .link_items = ath_wprobe_link,
187 +       .n_link_items = ARRAY_SIZE(ath_wprobe_link),
188 +       .global_items = ath_wprobe_globals,
189 +       .n_global_items = ARRAY_SIZE(ath_wprobe_globals),
190 +       .sync_data = ath_wprobe_sync,
191 +};
192 +
193 +static int
194 +ath_lookup_rateval(struct ieee80211_node *ni, int rate)
195 +{
196 +       struct ieee80211vap *vap = ni->ni_vap;
197 +       struct ieee80211com *ic = vap->iv_ic;
198 +       struct ath_softc *sc = ic->ic_dev->priv;
199 +       const HAL_RATE_TABLE *rt = sc->sc_currates;
200 +
201 +       if ((!rt) || (rate < 0) || (rate >= ARRAY_SIZE(sc->sc_hwmap)))
202 +               return -1;
203 +
204 +       rate = sc->sc_hwmap[rate].ieeerate;
205 +       rate = sc->sc_rixmap[rate & IEEE80211_RATE_VAL];
206 +       if ((rate < 0) || (rate >= rt->rateCount))
207 +               return -1;
208 +
209 +       return rt->info[rate].rateKbps;
210 +}
211 +
212 +static void
213 +ath_wprobe_report_rx(struct ieee80211vap *vap, struct ath_rx_status *rs, struct sk_buff *skb)
214 +{
215 +       const struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data;
216 +       struct wprobe_wlan_hdr hdr;
217 +       struct ath_vap *avp;
218 +       int hdrsize;
219 +
220 +       if (wprobe_disabled())
221 +               return;
222 +
223 +       avp = ATH_VAP(vap);
224 +       avp->av_rxframes++;
225 +       if (wh->i_fc[0] == (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ))
226 +               avp->av_rxprobereq++;
227 +
228 +       memset(&hdr, 0, sizeof(hdr));
229 +       hdr.len = skb->len;
230 +       hdr.snr = rs->rs_rssi;
231 +       hdr.type = WPROBE_PKT_RX;
232 +       if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
233 +               hdrsize = sizeof(struct ieee80211_ctlframe_addr2);
234 +       else
235 +               hdrsize = ieee80211_hdrsize(skb->data);
236 +       wprobe_add_frame(&avp->av_wpif, &hdr, skb->data, hdrsize + 0x42);
237 +}
238 +
239 +
240 +static void
241 +ath_node_sample_rx(struct ieee80211_node *ni, struct ath_rx_status *rs)
242 +{
243 +       struct ath_node *an = ATH_NODE(ni);
244 +       struct ieee80211vap *vap = ni->ni_vap;
245 +       struct ieee80211com *ic = vap->iv_ic;
246 +       struct wprobe_link *l = &an->an_wplink;
247 +       struct wprobe_value *v = l->val;
248 +       unsigned long flags;
249 +       int rate;
250 +
251 +       if (wprobe_disabled() || !an->an_wplink_active || !l->val)
252 +               return;
253 +
254 +       rate = ath_lookup_rateval(ni, rs->rs_rate);
255 +
256 +       spin_lock_irqsave(&l->iface->lock, flags);
257 +       WPROBE_FILL_BEGIN(v, ath_wprobe_link);
258 +       WPROBE_SET(WP_NODE_RSSI, U8, rs->rs_rssi);
259 +       WPROBE_SET(WP_NODE_SIGNAL, S16, ic->ic_channoise + rs->rs_rssi);
260 +       if ((rate > 0) && (rate <= 600000))
261 +               WPROBE_SET(WP_NODE_RX_RATE, U16, rate);
262 +       WPROBE_FILL_END();
263 +       wprobe_update_stats(l->iface, l);
264 +       spin_unlock_irqrestore(&l->iface->lock, flags);
265 +}
266 +
267 +static void
268 +ath_wprobe_report_tx(struct ieee80211vap *vap, struct ath_tx_status *ts, struct sk_buff *skb)
269 +{
270 +       const struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data;
271 +       struct wprobe_wlan_hdr hdr;
272 +       struct ath_vap *avp;
273 +       int hdrsize;
274 +
275 +       if (wprobe_disabled())
276 +               return;
277 +
278 +       avp = ATH_VAP(vap);
279 +
280 +       memset(&hdr, 0, sizeof(hdr));
281 +       hdr.len = skb->len;
282 +       hdr.snr = ts->ts_rssi;
283 +       hdr.type = WPROBE_PKT_TX;
284 +       if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
285 +               hdrsize = sizeof(struct ieee80211_ctlframe_addr2);
286 +       else
287 +               hdrsize = ieee80211_hdrsize(skb->data);
288 +       wprobe_add_frame(&avp->av_wpif, &hdr, skb->data, hdrsize + 0x42);
289 +}
290 +
291 +
292 +
293 +static void
294 +ath_node_sample_tx(struct ieee80211_node *ni, struct ath_tx_status *ts, struct sk_buff *skb)
295 +{
296 +       struct ath_node *an = ATH_NODE(ni);
297 +       struct ieee80211vap *vap = ni->ni_vap;
298 +       struct ieee80211com *ic = vap->iv_ic;
299 +       struct wprobe_link *l = &an->an_wplink;
300 +       struct wprobe_value *v = l->val;
301 +       unsigned long flags;
302 +       int rate, rexmit_counter;
303 +       int len = skb->len;
304 +
305 +       if (wprobe_disabled() || !an->an_wplink_active || !l->val)
306 +               return;
307 +
308 +       ath_wprobe_report_tx(vap, ts, skb);
309 +       rate = ath_lookup_rateval(ni, ts->ts_rate);
310 +
311 +       spin_lock_irqsave(&l->iface->lock, flags);
312 +       WPROBE_FILL_BEGIN(v, ath_wprobe_link);
313 +       WPROBE_SET(WP_NODE_RSSI, U8, ts->ts_rssi);
314 +       WPROBE_SET(WP_NODE_SIGNAL, S16, ic->ic_channoise + ts->ts_rssi);
315 +
316 +       if (len <= 200)
317 +               rexmit_counter = WP_NODE_RETRANSMIT_200;
318 +       else if (len <= 400)
319 +               rexmit_counter = WP_NODE_RETRANSMIT_400;
320 +       else if (len <= 800)
321 +               rexmit_counter = WP_NODE_RETRANSMIT_800;
322 +       else
323 +               rexmit_counter = WP_NODE_RETRANSMIT_1600;
324 +       WPROBE_SET(rexmit_counter, U8, ts->ts_longretry);
325 +
326 +       if ((rate > 0) && (rate <= 600000))
327 +               WPROBE_SET(WP_NODE_TX_RATE, U16, rate);
328 +       WPROBE_FILL_END();
329 +       wprobe_update_stats(l->iface, l);
330 +       spin_unlock_irqrestore(&l->iface->lock, flags);
331 +}
332 +
333 +static void
334 +ath_wprobe_node_join(struct ieee80211vap *vap, struct ieee80211_node *ni)
335 +{
336 +       struct wprobe_iface *dev;
337 +       struct wprobe_link *l;
338 +       struct ath_vap *avp;
339 +       struct ath_node *an = ATH_NODE(ni);
340 +
341 +       if (wprobe_disabled() || an->an_wplink_active)
342 +               return;
343 +
344 +       avp = ATH_VAP(vap);
345 +       dev = &avp->av_wpif;
346 +       l = &an->an_wplink;
347 +
348 +       ieee80211_ref_node(ni);
349 +       wprobe_add_link(dev, l, ni->ni_macaddr);
350 +       an->an_wplink_active = 1;
351 +}
352 +
353 +static void
354 +ath_wprobe_do_node_leave(struct work_struct *work)
355 +{
356 +       struct ath_node *an = container_of(work, struct ath_node, an_destroy);
357 +       struct ieee80211_node *ni = &an->an_node;
358 +       struct ieee80211vap *vap = ni->ni_vap;
359 +       struct wprobe_iface *dev;
360 +       struct wprobe_link *l;
361 +       struct ath_vap *avp;
362 +
363 +       avp = ATH_VAP(vap);
364 +       dev = &avp->av_wpif;
365 +       l = &an->an_wplink;
366 +
367 +       wprobe_remove_link(dev, l);
368 +       ieee80211_unref_node(&ni);
369 +       atomic_dec(&cleanup_tasks);
370 +}
371 +
372 +static void
373 +ath_wprobe_node_leave(struct ieee80211vap *vap, struct ieee80211_node *ni)
374 +{
375 +       struct ath_node *an = ATH_NODE(ni);
376 +
377 +       if (wprobe_disabled() || !an->an_wplink_active)
378 +               return;
379 +
380 +       atomic_inc(&cleanup_tasks);
381 +       an->an_wplink_active = 0;
382 +       IEEE80211_INIT_WORK(&an->an_destroy, ath_wprobe_do_node_leave);
383 +       schedule_work(&an->an_destroy);
384 +}
385 +
386 +static void
387 +ath_init_wprobe_dev(struct ath_vap *avp)
388 +{
389 +       struct ieee80211vap *vap = &avp->av_vap;
390 +       struct wprobe_iface *dev = &avp->av_wpif;
391 +
392 +       if (wprobe_disabled() || (vap->iv_opmode == IEEE80211_M_WDS))
393 +               return;
394 +
395 +       memcpy(dev, &ath_wprobe_dev, sizeof(struct wprobe_iface));
396 +       dev->addr = vap->iv_myaddr;
397 +       dev->name = vap->iv_dev->name;
398 +       wprobe_add_iface(dev);
399 +}
400 +
401 +static void
402 +ath_remove_wprobe_dev(struct ath_vap *avp)
403 +{
404 +       struct ieee80211vap *vap = &avp->av_vap;
405 +       struct ieee80211com *ic = vap->iv_ic;
406 +       struct ieee80211_node *ni;
407 +       struct wprobe_iface *dev = &avp->av_wpif;
408 +       struct wprobe_link *l;
409 +       struct ath_node *an;
410 +       unsigned long flags;
411 +
412 +       if (wprobe_disabled() || (vap->iv_opmode == IEEE80211_M_WDS))
413 +               return;
414 +
415 +restart:
416 +       rcu_read_lock();
417 +       list_for_each_entry_rcu(l, &dev->links, list) {
418 +               an = container_of(l, struct ath_node, an_wplink);
419 +
420 +               if (!an->an_wplink_active)
421 +                       continue;
422 +
423 +               ni = &an->an_node;
424 +               ath_wprobe_node_leave(vap, ni);
425 +               rcu_read_unlock();
426 +               goto restart;
427 +       }
428 +       rcu_read_unlock();
429 +
430 +       /* wait for the cleanup tasks to finish */
431 +       while (atomic_read(&cleanup_tasks) != 0) {
432 +               schedule();
433 +       }
434 +
435 +       wprobe_remove_iface(dev);
436 +}
437 --- a/ath/if_ath.c
438 +++ b/ath/if_ath.c
439 @@ -400,6 +400,7 @@ static int countrycode = -1;
440  static int maxvaps = -1;
441  static int outdoor = -1;
442  static int xchanmode = -1;
443 +#include "ath_wprobe.c"
444  static int beacon_cal = 1;
445  
446  static const struct ath_hw_detect generic_hw_info = {
447 @@ -1525,6 +1526,7 @@ ath_vap_create(struct ieee80211com *ic, 
448                 ath_hal_intrset(ah, sc->sc_imask);
449         }
450  
451 +       ath_init_wprobe_dev(avp);
452         return vap;
453  }
454  
455 @@ -1606,6 +1608,7 @@ ath_vap_delete(struct ieee80211vap *vap)
456                 decrease = 0;
457  
458         ieee80211_vap_detach(vap);
459 +       ath_remove_wprobe_dev(ATH_VAP(vap));
460         /* NB: memory is reclaimed through dev->destructor callback */
461         if (decrease)
462                 sc->sc_nvaps--;
463 @@ -5940,6 +5943,7 @@ ath_node_cleanup(struct ieee80211_node *
464         /* Clean up node-specific rate things - this currently appears to 
465          * always be a no-op */
466         sc->sc_rc->ops->node_cleanup(sc, ATH_NODE(ni));
467 +       ath_wprobe_node_leave(ni->ni_vap, ni);
468  
469         ATH_NODE_UAPSD_LOCK_IRQ(an);
470  #ifdef IEEE80211_DEBUG_REFCNT
471 @@ -7010,6 +7014,8 @@ drop_micfail:
472                                 goto lookup_slowpath;
473                         }
474                         ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
475 +                       ath_node_sample_rx(ni, rs);
476 +                       ath_wprobe_report_rx(ni->ni_vap, rs, skb);
477                         type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
478                         ieee80211_unref_node(&ni);
479                 } else {
480 @@ -7024,15 +7030,21 @@ lookup_slowpath:
481                         else
482                                 vap = ieee80211_find_rxvap(ic, wh->i_addr1);
483  
484 -                       if (vap)
485 +                       if (vap) {
486 +                               ath_wprobe_report_rx(vap, rs, skb);
487                                 ni = ieee80211_find_rxnode(ic, vap, wh);
488 -                       else
489 +                       } else {
490 +                               TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
491 +                                       ath_wprobe_report_rx(vap, rs, skb);
492 +                               }
493                                 ni = NULL;
494 +                       }
495  
496                         if (ni != NULL) {
497                                 ieee80211_keyix_t keyix;
498  
499                                 ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
500 +                               ath_node_sample_rx(ni, rs);
501                                 type = ieee80211_input(vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
502                                 /*
503                                  * If the station has a key cache slot assigned
504 @@ -8612,6 +8624,7 @@ ath_tx_processq(struct ath_softc *sc, st
505                                 sc->sc_stats.ast_tx_rssi = ts->ts_rssi;
506                                 ATH_RSSI_LPF(an->an_halstats.ns_avgtxrssi,
507                                         ts->ts_rssi);
508 +                                       ath_node_sample_tx(&an->an_node, ts, bf->bf_skb);
509                                 if (bf->bf_skb->priority == WME_AC_VO ||
510                                     bf->bf_skb->priority == WME_AC_VI)
511                                         ni->ni_ic->ic_wme.wme_hipri_traffic++;
512 @@ -10111,6 +10124,7 @@ ath_newassoc(struct ieee80211_node *ni, 
513         struct ath_softc *sc = ic->ic_dev->priv;
514  
515         sc->sc_rc->ops->newassoc(sc, ATH_NODE(ni), isnew);
516 +       ath_wprobe_node_join(ni->ni_vap, ni);
517  
518         /* are we supporting compression? */
519         if (!(vap->iv_ath_cap & ni->ni_ath_flags & IEEE80211_NODE_COMP))
520 --- a/ath/if_athvar.h
521 +++ b/ath/if_athvar.h
522 @@ -46,6 +46,7 @@
523  #include "ah_desc.h"
524  #include "ah_os.h"
525  #include "if_athioctl.h"
526 +#include <linux/wprobe.h>
527  #include "net80211/ieee80211.h"                /* XXX for WME_NUM_AC */
528  #include <asm/io.h>
529  #include <linux/list.h>
530 @@ -352,6 +353,9 @@ typedef STAILQ_HEAD(, ath_buf) ath_bufhe
531  /* driver-specific node state */
532  struct ath_node {
533         struct ieee80211_node an_node;          /* base class */
534 +       struct wprobe_link an_wplink;
535 +       uint8_t an_wplink_active;
536 +       struct work_struct an_destroy;
537         u_int16_t an_decomp_index;              /* decompression mask index */
538         u_int32_t an_avgrssi;                   /* average rssi over all rx frames */
539         u_int8_t  an_prevdatarix;               /* rate ix of last data frame */
540 @@ -521,6 +525,9 @@ struct ath_vap {
541  #else
542         unsigned int av_beacon_alloc;
543  #endif
544 +       struct wprobe_iface av_wpif;
545 +       u32 av_rxframes;
546 +       u32 av_rxprobereq;
547  };
548  #define        ATH_VAP(_v)     ((struct ath_vap *)(_v))
549