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