wlan - Rip out all wlan locks part 1/2
[dragonfly.git] / sys / netproto / 802_11 / wlan / ieee80211_input.c
1 /*-
2  * Copyright (c) 2001 Atsushi Onoe
3  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD: head/sys/net80211/ieee80211_input.c 205986 2010-03-31 16:07:36Z rpaulo $
27  * $DragonFly$
28  */
29
30 #include "opt_wlan.h"
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/mbuf.h>   
35 #include <sys/malloc.h>
36 #include <sys/endian.h>
37 #include <sys/kernel.h>
38  
39 #include <sys/socket.h>
40  
41 #include <net/ethernet.h>
42 #include <net/if.h>
43 #include <net/if_llc.h>
44 #include <net/if_media.h>
45 #include <net/route.h>
46
47 #include <netproto/802_11/ieee80211_var.h>
48 #include <netproto/802_11/ieee80211_input.h>
49 #ifdef IEEE80211_SUPPORT_MESH
50 #include <netproto/802_11/ieee80211_mesh.h>
51 #endif
52
53 #include <net/bpf.h>
54
55 #ifdef INET
56 #include <netinet/in.h>
57 #include <net/ethernet.h>
58 #endif
59
60 int
61 ieee80211_input_all(struct ieee80211com *ic, struct mbuf *m, int rssi, int nf)
62 {
63         struct ieee80211vap *vap;
64         int type = -1;
65
66         m->m_flags |= M_BCAST;          /* NB: mark for bpf tap'ing */
67
68         /* XXX locking */
69         TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
70                 struct ieee80211_node *ni;
71                 struct mbuf *mcopy;
72
73                 /* NB: could check for IFF_UP but this is cheaper */
74                 if (vap->iv_state == IEEE80211_S_INIT)
75                         continue;
76                 /*
77                  * WDS vap's only receive directed traffic from the
78                  * station at the ``far end''.  That traffic should
79                  * be passed through the AP vap the station is associated
80                  * to--so don't spam them with mcast frames.
81                  */
82                 if (vap->iv_opmode == IEEE80211_M_WDS)
83                         continue;
84                 if (TAILQ_NEXT(vap, iv_next) != NULL) {
85                         /*
86                          * Packet contents are changed by ieee80211_decap
87                          * so do a deep copy of the packet.
88                          */
89                         mcopy = m_dup(m, MB_DONTWAIT);
90                         if (mcopy == NULL) {
91                                 /* XXX stat+msg */
92                                 continue;
93                         }
94                 } else {
95                         mcopy = m;
96                         m = NULL;
97                 }
98                 ni = ieee80211_ref_node(vap->iv_bss);
99                 type = ieee80211_input(ni, mcopy, rssi, nf);
100                 ieee80211_free_node(ni);
101         }
102         if (m != NULL)                  /* no vaps, reclaim mbuf */
103                 m_freem(m);
104         return type;
105 }
106
107 /*
108  * This function reassembles fragments.
109  *
110  * XXX should handle 3 concurrent reassemblies per-spec.
111  */
112 struct mbuf *
113 ieee80211_defrag(struct ieee80211_node *ni, struct mbuf *m, int hdrspace)
114 {
115         struct ieee80211vap *vap = ni->ni_vap;
116         struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
117         struct ieee80211_frame *lwh;
118         uint16_t rxseq;
119         uint8_t fragno;
120         uint8_t more_frag = wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG;
121         struct mbuf *mfrag;
122
123         KASSERT(!IEEE80211_IS_MULTICAST(wh->i_addr1), ("multicast fragm?"));
124
125         rxseq = le16toh(*(uint16_t *)wh->i_seq);
126         fragno = rxseq & IEEE80211_SEQ_FRAG_MASK;
127
128         /* Quick way out, if there's nothing to defragment */
129         if (!more_frag && fragno == 0 && ni->ni_rxfrag[0] == NULL)
130                 return m;
131
132         /*
133          * Remove frag to insure it doesn't get reaped by timer.
134          */
135         if (ni->ni_table == NULL) {
136                 /*
137                  * Should never happen.  If the node is orphaned (not in
138                  * the table) then input packets should not reach here.
139                  * Otherwise, a concurrent request that yanks the table
140                  * should be blocked by other interlocking and/or by first
141                  * shutting the driver down.  Regardless, be defensive
142                  * here and just bail
143                  */
144                 /* XXX need msg+stat */
145                 m_freem(m);
146                 return NULL;
147         }
148         mfrag = ni->ni_rxfrag[0];
149         ni->ni_rxfrag[0] = NULL;
150
151         /*
152          * Validate new fragment is in order and
153          * related to the previous ones.
154          */
155         if (mfrag != NULL) {
156                 uint16_t last_rxseq;
157
158                 lwh = mtod(mfrag, struct ieee80211_frame *);
159                 last_rxseq = le16toh(*(uint16_t *)lwh->i_seq);
160                 /* NB: check seq # and frag together */
161                 if (rxseq != last_rxseq+1 ||
162                     !IEEE80211_ADDR_EQ(wh->i_addr1, lwh->i_addr1) ||
163                     !IEEE80211_ADDR_EQ(wh->i_addr2, lwh->i_addr2)) {
164                         /*
165                          * Unrelated fragment or no space for it,
166                          * clear current fragments.
167                          */
168                         m_freem(mfrag);
169                         mfrag = NULL;
170                 }
171         }
172
173         if (mfrag == NULL) {
174                 if (fragno != 0) {              /* !first fragment, discard */
175                         vap->iv_stats.is_rx_defrag++;
176                         IEEE80211_NODE_STAT(ni, rx_defrag);
177                         m_freem(m);
178                         return NULL;
179                 }
180                 mfrag = m;
181         } else {                                /* concatenate */
182                 m_adj(m, hdrspace);             /* strip header */
183                 m_cat(mfrag, m);
184                 /* NB: m_cat doesn't update the packet header */
185                 mfrag->m_pkthdr.len += m->m_pkthdr.len;
186                 /* track last seqnum and fragno */
187                 lwh = mtod(mfrag, struct ieee80211_frame *);
188                 *(uint16_t *) lwh->i_seq = *(uint16_t *) wh->i_seq;
189         }
190         if (more_frag) {                        /* more to come, save */
191                 ni->ni_rxfragstamp = ticks;
192                 ni->ni_rxfrag[0] = mfrag;
193                 mfrag = NULL;
194         }
195         return mfrag;
196 }
197
198 void
199 ieee80211_deliver_data(struct ieee80211vap *vap,
200         struct ieee80211_node *ni, struct mbuf *m)
201 {
202         struct ether_header *eh = mtod(m, struct ether_header *);
203         struct ifnet *ifp = vap->iv_ifp;
204
205         /* clear driver/net80211 flags before passing up */
206         m->m_flags &= ~(M_80211_RX | M_MCAST | M_BCAST);
207
208         /* NB: see hostap_deliver_data, this path doesn't handle hostap */
209         KASSERT(vap->iv_opmode != IEEE80211_M_HOSTAP, ("gack, hostap"));
210         /*
211          * Do accounting.
212          */
213         ifp->if_ipackets++;
214         IEEE80211_NODE_STAT(ni, rx_data);
215         IEEE80211_NODE_STAT_ADD(ni, rx_bytes, m->m_pkthdr.len);
216         if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
217                 m->m_flags |= M_MCAST;          /* XXX M_BCAST? */
218                 IEEE80211_NODE_STAT(ni, rx_mcast);
219         } else
220                 IEEE80211_NODE_STAT(ni, rx_ucast);
221         m->m_pkthdr.rcvif = ifp;
222
223         if (ni->ni_vlan != 0) {
224                 /* attach vlan tag */
225                 m->m_pkthdr.ether_vlantag = ni->ni_vlan;
226                 m->m_flags |= M_VLANTAG;
227         }
228         ifp->if_input(ifp, m);
229 }
230
231 struct mbuf *
232 ieee80211_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen)
233 {
234         struct ieee80211_qosframe_addr4 wh;
235         struct ether_header *eh;
236         struct llc *llc;
237
238         KASSERT(hdrlen <= sizeof(wh),
239             ("hdrlen %d > max %zd", hdrlen, sizeof(wh)));
240
241         if (m->m_len < hdrlen + sizeof(*llc) &&
242             (m = m_pullup(m, hdrlen + sizeof(*llc))) == NULL) {
243                 vap->iv_stats.is_rx_tooshort++;
244                 /* XXX msg */
245                 return NULL;
246         }
247         memcpy(&wh, mtod(m, caddr_t), hdrlen);
248         llc = (struct llc *)(mtod(m, caddr_t) + hdrlen);
249         if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP &&
250             llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 &&
251             llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0 &&
252             /* NB: preserve AppleTalk frames that have a native SNAP hdr */
253             !(llc->llc_snap.ether_type == htons(ETHERTYPE_AARP) ||
254               llc->llc_snap.ether_type == htons(ETHERTYPE_IPX))) {
255                 m_adj(m, hdrlen + sizeof(struct llc) - sizeof(*eh));
256                 llc = NULL;
257         } else {
258                 m_adj(m, hdrlen - sizeof(*eh));
259         }
260         eh = mtod(m, struct ether_header *);
261         switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
262         case IEEE80211_FC1_DIR_NODS:
263                 IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1);
264                 IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2);
265                 break;
266         case IEEE80211_FC1_DIR_TODS:
267                 IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr3);
268                 IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2);
269                 break;
270         case IEEE80211_FC1_DIR_FROMDS:
271                 IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1);
272                 IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr3);
273                 break;
274         case IEEE80211_FC1_DIR_DSTODS:
275                 IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr3);
276                 IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr4);
277                 break;
278         }
279 #ifdef ALIGNED_POINTER
280         if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), uint32_t)) {
281                 m = ieee80211_realign(vap, m, sizeof(*eh));
282                 if (m == NULL)
283                         return NULL;
284         }
285 #endif /* ALIGNED_POINTER */
286         if (llc != NULL) {
287                 eh = mtod(m, struct ether_header *);
288                 eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
289         }
290         return m;
291 }
292
293 /*
294  * Decap a frame encapsulated in a fast-frame/A-MSDU.
295  */
296 struct mbuf *
297 ieee80211_decap1(struct mbuf *m, int *framelen)
298 {
299 #define FF_LLC_SIZE     (sizeof(struct ether_header) + sizeof(struct llc))
300         struct ether_header *eh;
301         struct llc *llc;
302
303         /*
304          * The frame has an 802.3 header followed by an 802.2
305          * LLC header.  The encapsulated frame length is in the
306          * first header type field; save that and overwrite it 
307          * with the true type field found in the second.  Then
308          * copy the 802.3 header up to where it belongs and
309          * adjust the mbuf contents to remove the void.
310          */
311         if (m->m_len < FF_LLC_SIZE && (m = m_pullup(m, FF_LLC_SIZE)) == NULL)
312                 return NULL;
313         eh = mtod(m, struct ether_header *);    /* 802.3 header is first */
314         llc = (struct llc *)&eh[1];             /* 802.2 header follows */
315         *framelen = ntohs(eh->ether_type)       /* encap'd frame size */
316                   + sizeof(struct ether_header) - sizeof(struct llc);
317         eh->ether_type = llc->llc_un.type_snap.ether_type;
318         ovbcopy(eh, mtod(m, uint8_t *) + sizeof(struct llc),
319                 sizeof(struct ether_header));
320         m_adj(m, sizeof(struct llc));
321         return m;
322 #undef FF_LLC_SIZE
323 }
324
325 /*
326  * Install received rate set information in the node's state block.
327  */
328 int
329 ieee80211_setup_rates(struct ieee80211_node *ni,
330         const uint8_t *rates, const uint8_t *xrates, int flags)
331 {
332         struct ieee80211vap *vap = ni->ni_vap;
333         struct ieee80211_rateset *rs = &ni->ni_rates;
334
335         memset(rs, 0, sizeof(*rs));
336         rs->rs_nrates = rates[1];
337         memcpy(rs->rs_rates, rates + 2, rs->rs_nrates);
338         if (xrates != NULL) {
339                 uint8_t nxrates;
340                 /*
341                  * Tack on 11g extended supported rate element.
342                  */
343                 nxrates = xrates[1];
344                 if (rs->rs_nrates + nxrates > IEEE80211_RATE_MAXSIZE) {
345                         nxrates = IEEE80211_RATE_MAXSIZE - rs->rs_nrates;
346                         IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE, ni,
347                             "extended rate set too large; only using "
348                             "%u of %u rates", nxrates, xrates[1]);
349                         vap->iv_stats.is_rx_rstoobig++;
350                 }
351                 memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates);
352                 rs->rs_nrates += nxrates;
353         }
354         return ieee80211_fix_rate(ni, rs, flags);
355 }
356
357 /*
358  * Send a management frame error response to the specified
359  * station.  If ni is associated with the station then use
360  * it; otherwise allocate a temporary node suitable for
361  * transmitting the frame and then free the reference so
362  * it will go away as soon as the frame has been transmitted.
363  */
364 void
365 ieee80211_send_error(struct ieee80211_node *ni,
366         const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg)
367 {
368         struct ieee80211vap *vap = ni->ni_vap;
369         int istmp;
370
371         if (ni == vap->iv_bss) {
372                 if (vap->iv_state != IEEE80211_S_RUN) {
373                         /*
374                          * XXX hack until we get rid of this routine.
375                          * We can be called prior to the vap reaching
376                          * run state under certain conditions in which
377                          * case iv_bss->ni_chan will not be setup.
378                          * Check for this explicitly and and just ignore
379                          * the request.
380                          */
381                         return;
382                 }
383                 ni = ieee80211_tmp_node(vap, mac);
384                 if (ni == NULL) {
385                         /* XXX msg */
386                         return;
387                 }
388                 istmp = 1;
389         } else
390                 istmp = 0;
391         IEEE80211_SEND_MGMT(ni, subtype, arg);
392         if (istmp)
393                 ieee80211_free_node(ni);
394 }
395
396 int
397 ieee80211_alloc_challenge(struct ieee80211_node *ni)
398 {
399         if (ni->ni_challenge == NULL)
400                 ni->ni_challenge = (uint32_t *) kmalloc(IEEE80211_CHALLENGE_LEN,
401                     M_80211_NODE, M_INTWAIT);
402         if (ni->ni_challenge == NULL) {
403                 IEEE80211_NOTE(ni->ni_vap,
404                     IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, ni,
405                     "%s", "shared key challenge alloc failed");
406                 /* XXX statistic */
407         }
408         return (ni->ni_challenge != NULL);
409 }
410
411 /*
412  * Parse a Beacon or ProbeResponse frame and return the
413  * useful information in an ieee80211_scanparams structure.
414  * Status is set to 0 if no problems were found; otherwise
415  * a bitmask of IEEE80211_BPARSE_* items is returned that
416  * describes the problems detected.
417  */
418 int
419 ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
420         struct ieee80211_scanparams *scan)
421 {
422         struct ieee80211vap *vap = ni->ni_vap;
423         struct ieee80211com *ic = ni->ni_ic;
424         struct ieee80211_frame *wh;
425         uint8_t *frm, *efrm;
426
427         wh = mtod(m, struct ieee80211_frame *);
428         frm = (uint8_t *)&wh[1];
429         efrm = mtod(m, uint8_t *) + m->m_len;
430         scan->status = 0;
431         /*
432          * beacon/probe response frame format
433          *      [8] time stamp
434          *      [2] beacon interval
435          *      [2] capability information
436          *      [tlv] ssid
437          *      [tlv] supported rates
438          *      [tlv] country information
439          *      [tlv] channel switch announcement (CSA)
440          *      [tlv] parameter set (FH/DS)
441          *      [tlv] erp information
442          *      [tlv] extended supported rates
443          *      [tlv] WME
444          *      [tlv] WPA or RSN
445          *      [tlv] HT capabilities
446          *      [tlv] HT information
447          *      [tlv] Atheros capabilities
448          *      [tlv] Mesh ID
449          *      [tlv] Mesh Configuration
450          */
451         IEEE80211_VERIFY_LENGTH(efrm - frm, 12,
452             return (scan->status = IEEE80211_BPARSE_BADIELEN));
453         memset(scan, 0, sizeof(*scan));
454         scan->tstamp  = frm;                            frm += 8;
455         scan->bintval = le16toh(*(uint16_t *)frm);      frm += 2;
456         scan->capinfo = le16toh(*(uint16_t *)frm);      frm += 2;
457         scan->bchan = ieee80211_chan2ieee(ic, ic->ic_curchan);
458         scan->chan = scan->bchan;
459         scan->ies = frm;
460         scan->ies_len = efrm - frm;
461
462         while (efrm - frm > 1) {
463                 IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2,
464                     return (scan->status = IEEE80211_BPARSE_BADIELEN));
465                 switch (*frm) {
466                 case IEEE80211_ELEMID_SSID:
467                         scan->ssid = frm;
468                         break;
469                 case IEEE80211_ELEMID_RATES:
470                         scan->rates = frm;
471                         break;
472                 case IEEE80211_ELEMID_COUNTRY:
473                         scan->country = frm;
474                         break;
475                 case IEEE80211_ELEMID_CSA:
476                         scan->csa = frm;
477                         break;
478                 case IEEE80211_ELEMID_FHPARMS:
479                         if (ic->ic_phytype == IEEE80211_T_FH) {
480                                 scan->fhdwell = LE_READ_2(&frm[2]);
481                                 scan->chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
482                                 scan->fhindex = frm[6];
483                         }
484                         break;
485                 case IEEE80211_ELEMID_DSPARMS:
486                         /*
487                          * XXX hack this since depending on phytype
488                          * is problematic for multi-mode devices.
489                          */
490                         if (ic->ic_phytype != IEEE80211_T_FH)
491                                 scan->chan = frm[2];
492                         break;
493                 case IEEE80211_ELEMID_TIM:
494                         /* XXX ATIM? */
495                         scan->tim = frm;
496                         scan->timoff = frm - mtod(m, uint8_t *);
497                         break;
498                 case IEEE80211_ELEMID_IBSSPARMS:
499                 case IEEE80211_ELEMID_CFPARMS:
500                 case IEEE80211_ELEMID_PWRCNSTR:
501                         /* NB: avoid debugging complaints */
502                         break;
503                 case IEEE80211_ELEMID_XRATES:
504                         scan->xrates = frm;
505                         break;
506                 case IEEE80211_ELEMID_ERP:
507                         if (frm[1] != 1) {
508                                 IEEE80211_DISCARD_IE(vap,
509                                     IEEE80211_MSG_ELEMID, wh, "ERP",
510                                     "bad len %u", frm[1]);
511                                 vap->iv_stats.is_rx_elem_toobig++;
512                                 break;
513                         }
514                         scan->erp = frm[2] | 0x100;
515                         break;
516                 case IEEE80211_ELEMID_HTCAP:
517                         scan->htcap = frm;
518                         break;
519                 case IEEE80211_ELEMID_RSN:
520                         scan->rsn = frm;
521                         break;
522                 case IEEE80211_ELEMID_HTINFO:
523                         scan->htinfo = frm;
524                         break;
525 #ifdef IEEE80211_SUPPORT_MESH
526                 case IEEE80211_ELEMID_MESHID:
527                         scan->meshid = frm;
528                         break;
529                 case IEEE80211_ELEMID_MESHCONF:
530                         scan->meshconf = frm;
531                         break;
532 #endif
533                 case IEEE80211_ELEMID_VENDOR:
534                         if (iswpaoui(frm))
535                                 scan->wpa = frm;
536                         else if (iswmeparam(frm) || iswmeinfo(frm))
537                                 scan->wme = frm;
538 #ifdef IEEE80211_SUPPORT_SUPERG
539                         else if (isatherosoui(frm))
540                                 scan->ath = frm;
541 #endif
542 #ifdef IEEE80211_SUPPORT_TDMA
543                         else if (istdmaoui(frm))
544                                 scan->tdma = frm;
545 #endif
546                         else if (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) {
547                                 /*
548                                  * Accept pre-draft HT ie's if the
549                                  * standard ones have not been seen.
550                                  */
551                                 if (ishtcapoui(frm)) {
552                                         if (scan->htcap == NULL)
553                                                 scan->htcap = frm;
554                                 } else if (ishtinfooui(frm)) {
555                                         if (scan->htinfo == NULL)
556                                                 scan->htcap = frm;
557                                 }
558                         }
559                         break;
560                 default:
561                         IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID,
562                             wh, "unhandled",
563                             "id %u, len %u", *frm, frm[1]);
564                         vap->iv_stats.is_rx_elem_unknown++;
565                         break;
566                 }
567                 frm += frm[1] + 2;
568         }
569         IEEE80211_VERIFY_ELEMENT(scan->rates, IEEE80211_RATE_MAXSIZE,
570             scan->status |= IEEE80211_BPARSE_RATES_INVALID);
571         if (scan->rates != NULL && scan->xrates != NULL) {
572                 /*
573                  * NB: don't process XRATES if RATES is missing.  This
574                  * avoids a potential null ptr deref and should be ok
575                  * as the return code will already note RATES is missing
576                  * (so callers shouldn't otherwise process the frame).
577                  */
578                 IEEE80211_VERIFY_ELEMENT(scan->xrates,
579                     IEEE80211_RATE_MAXSIZE - scan->rates[1],
580                     scan->status |= IEEE80211_BPARSE_XRATES_INVALID);
581         }
582         IEEE80211_VERIFY_ELEMENT(scan->ssid, IEEE80211_NWID_LEN,
583             scan->status |= IEEE80211_BPARSE_SSID_INVALID);
584         if (scan->chan != scan->bchan && ic->ic_phytype != IEEE80211_T_FH) {
585                 /*
586                  * Frame was received on a channel different from the
587                  * one indicated in the DS params element id;
588                  * silently discard it.
589                  *
590                  * NB: this can happen due to signal leakage.
591                  *     But we should take it for FH phy because
592                  *     the rssi value should be correct even for
593                  *     different hop pattern in FH.
594                  */
595                 IEEE80211_DISCARD(vap,
596                     IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
597                     wh, NULL, "for off-channel %u", scan->chan);
598                 vap->iv_stats.is_rx_chanmismatch++;
599                 scan->status |= IEEE80211_BPARSE_OFFCHAN;
600         }
601         if (!(IEEE80211_BINTVAL_MIN <= scan->bintval &&
602               scan->bintval <= IEEE80211_BINTVAL_MAX)) {
603                 IEEE80211_DISCARD(vap,
604                     IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
605                     wh, NULL, "bogus beacon interval", scan->bintval);
606                 vap->iv_stats.is_rx_badbintval++;
607                 scan->status |= IEEE80211_BPARSE_BINTVAL_INVALID;
608         }
609         if (scan->country != NULL) {
610                 /*
611                  * Validate we have at least enough data to extract
612                  * the country code.  Not sure if we should return an
613                  * error instead of discarding the IE; consider this
614                  * being lenient as we don't depend on the data for
615                  * correct operation.
616                  */
617                 IEEE80211_VERIFY_LENGTH(scan->country[1], 3 * sizeof(uint8_t),
618                     scan->country = NULL);
619         }
620         if (scan->csa != NULL) {
621                 /*
622                  * Validate Channel Switch Announcement; this must
623                  * be the correct length or we toss the frame.
624                  */
625                 IEEE80211_VERIFY_LENGTH(scan->csa[1], 3 * sizeof(uint8_t),
626                     scan->status |= IEEE80211_BPARSE_CSA_INVALID);
627         }
628         /*
629          * Process HT ie's.  This is complicated by our
630          * accepting both the standard ie's and the pre-draft
631          * vendor OUI ie's that some vendors still use/require.
632          */
633         if (scan->htcap != NULL) {
634                 IEEE80211_VERIFY_LENGTH(scan->htcap[1],
635                      scan->htcap[0] == IEEE80211_ELEMID_VENDOR ?
636                          4 + sizeof(struct ieee80211_ie_htcap)-2 :
637                          sizeof(struct ieee80211_ie_htcap)-2,
638                      scan->htcap = NULL);
639         }
640         if (scan->htinfo != NULL) {
641                 IEEE80211_VERIFY_LENGTH(scan->htinfo[1],
642                      scan->htinfo[0] == IEEE80211_ELEMID_VENDOR ?
643                          4 + sizeof(struct ieee80211_ie_htinfo)-2 :
644                          sizeof(struct ieee80211_ie_htinfo)-2,
645                      scan->htinfo = NULL);
646         }
647         return scan->status;
648 }
649
650 /*
651  * Parse an Action frame.  Return 0 on success, non-zero on failure.
652  */
653 int
654 ieee80211_parse_action(struct ieee80211_node *ni, struct mbuf *m)
655 {
656         struct ieee80211vap *vap = ni->ni_vap;
657         const struct ieee80211_action *ia;
658         struct ieee80211_frame *wh;
659         uint8_t *frm, *efrm;
660
661         /*
662          * action frame format:
663          *      [1] category
664          *      [1] action
665          *      [tlv] parameters
666          */
667         wh = mtod(m, struct ieee80211_frame *);
668         frm = (u_int8_t *)&wh[1];
669         efrm = mtod(m, u_int8_t *) + m->m_len;
670         IEEE80211_VERIFY_LENGTH(efrm - frm,
671                 sizeof(struct ieee80211_action), return EINVAL);
672         ia = (const struct ieee80211_action *) frm;
673
674         vap->iv_stats.is_rx_action++;
675         IEEE80211_NODE_STAT(ni, rx_action);
676
677         /* verify frame payloads but defer processing */
678         /* XXX maybe push this to method */
679         switch (ia->ia_category) {
680         case IEEE80211_ACTION_CAT_BA:
681                 switch (ia->ia_action) {
682                 case IEEE80211_ACTION_BA_ADDBA_REQUEST:
683                         IEEE80211_VERIFY_LENGTH(efrm - frm,
684                             sizeof(struct ieee80211_action_ba_addbarequest),
685                             return EINVAL);
686                         break;
687                 case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
688                         IEEE80211_VERIFY_LENGTH(efrm - frm,
689                             sizeof(struct ieee80211_action_ba_addbaresponse),
690                             return EINVAL);
691                         break;
692                 case IEEE80211_ACTION_BA_DELBA:
693                         IEEE80211_VERIFY_LENGTH(efrm - frm,
694                             sizeof(struct ieee80211_action_ba_delba),
695                             return EINVAL);
696                         break;
697                 }
698                 break;
699         case IEEE80211_ACTION_CAT_HT:
700                 switch (ia->ia_action) {
701                 case IEEE80211_ACTION_HT_TXCHWIDTH:
702                         IEEE80211_VERIFY_LENGTH(efrm - frm,
703                             sizeof(struct ieee80211_action_ht_txchwidth),
704                             return EINVAL);
705                         break;
706                 case IEEE80211_ACTION_HT_MIMOPWRSAVE:
707                         IEEE80211_VERIFY_LENGTH(efrm - frm,
708                             sizeof(struct ieee80211_action_ht_mimopowersave),
709                             return EINVAL);
710                         break;
711                 }
712                 break;
713         }
714         return 0;
715 }
716
717 #ifdef IEEE80211_DEBUG
718 /*
719  * Debugging support.
720  */
721 void
722 ieee80211_ssid_mismatch(struct ieee80211vap *vap, const char *tag,
723         uint8_t mac[IEEE80211_ADDR_LEN], uint8_t *ssid)
724 {
725         kprintf("[%6D] discard %s frame, ssid mismatch: ",
726                 mac, ":", tag);
727         ieee80211_print_essid(ssid + 2, ssid[1]);
728         kprintf("\n");
729 }
730
731 /*
732  * Return the bssid of a frame.
733  */
734 static const uint8_t *
735 ieee80211_getbssid(const struct ieee80211vap *vap, const struct ieee80211_frame *wh)
736 {
737         if (vap->iv_opmode == IEEE80211_M_STA)
738                 return wh->i_addr2;
739         if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != IEEE80211_FC1_DIR_NODS)
740                 return wh->i_addr1;
741         if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
742                 return wh->i_addr1;
743         return wh->i_addr3;
744 }
745
746 #include <machine/stdarg.h>
747
748 void
749 ieee80211_note(const struct ieee80211vap *vap, const char *fmt, ...)
750 {
751         char buf[128];          /* XXX */
752         __va_list ap;
753
754         __va_start(ap, fmt);
755         kvsnprintf(buf, sizeof(buf), fmt, ap);
756         __va_end(ap);
757
758         if_printf(vap->iv_ifp, "%s", buf);      /* NB: no \n */
759 }
760
761 void
762 ieee80211_note_frame(const struct ieee80211vap *vap,
763         const struct ieee80211_frame *wh,
764         const char *fmt, ...)
765 {
766         char buf[128];          /* XXX */
767         __va_list ap;
768
769         __va_start(ap, fmt);
770         kvsnprintf(buf, sizeof(buf), fmt, ap);
771         __va_end(ap);
772         if_printf(vap->iv_ifp, "[%6D] %s\n",
773                 ieee80211_getbssid(vap, wh), ":", buf);
774 }
775
776 void
777 ieee80211_note_mac(const struct ieee80211vap *vap,
778         const uint8_t mac[IEEE80211_ADDR_LEN],
779         const char *fmt, ...)
780 {
781         char buf[128];          /* XXX */
782         __va_list ap;
783
784         __va_start(ap, fmt);
785         kvsnprintf(buf, sizeof(buf), fmt, ap);
786         __va_end(ap);
787         if_printf(vap->iv_ifp, "[%6D] %s\n", mac, ":", buf);
788 }
789
790 void
791 ieee80211_discard_frame(const struct ieee80211vap *vap,
792         const struct ieee80211_frame *wh,
793         const char *type, const char *fmt, ...)
794 {
795         __va_list ap;
796
797         if_printf(vap->iv_ifp, "[%6D] discard ",
798                 ieee80211_getbssid(vap, wh), ":");
799         if (type == NULL) {
800                 kprintf("%s frame, ", ieee80211_mgt_subtype_name[
801                         (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >>
802                         IEEE80211_FC0_SUBTYPE_SHIFT]);
803         } else
804                 kprintf("%s frame, ", type);
805         __va_start(ap, fmt);
806         kvprintf(fmt, ap);
807         __va_end(ap);
808         kprintf("\n");
809 }
810
811 void
812 ieee80211_discard_ie(const struct ieee80211vap *vap,
813         const struct ieee80211_frame *wh,
814         const char *type, const char *fmt, ...)
815 {
816         __va_list ap;
817
818         if_printf(vap->iv_ifp, "[%6D] discard ",
819                 ieee80211_getbssid(vap, wh), ":");
820         if (type != NULL)
821                 kprintf("%s information element, ", type);
822         else
823                 kprintf("information element, ");
824         __va_start(ap, fmt);
825         kvprintf(fmt, ap);
826         __va_end(ap);
827         kprintf("\n");
828 }
829
830 void
831 ieee80211_discard_mac(const struct ieee80211vap *vap,
832         const uint8_t mac[IEEE80211_ADDR_LEN],
833         const char *type, const char *fmt, ...)
834 {
835         __va_list ap;
836
837         if_printf(vap->iv_ifp, "[%6D] discard ", mac, ":");
838         if (type != NULL)
839                 kprintf("%s frame, ", type);
840         else
841                 kprintf("frame, ");
842         __va_start(ap, fmt);
843         kvprintf(fmt, ap);
844         __va_end(ap);
845         kprintf("\n");
846 }
847 #endif /* IEEE80211_DEBUG */