2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 2001 Atsushi Onoe
8 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * Alternatively, this software may be distributed under the terms of the
23 * GNU General Public License ("GPL") version 2 as published by the Free
24 * Software Foundation.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * Process received frame
42 #include <sys/mac_provider.h>
43 #include <sys/byteorder.h>
44 #include <sys/strsun.h>
45 #include "net80211_impl.h"
47 static mblk_t
*ieee80211_defrag(ieee80211com_t
*, ieee80211_node_t
*,
51 * Process a received frame. The node associated with the sender
52 * should be supplied. If nothing was found in the node table then
53 * the caller is assumed to supply a reference to ic_bss instead.
54 * The RSSI and a timestamp are also supplied. The RSSI data is used
55 * during AP scanning to select a AP to associate with; it can have
56 * any units so long as values have consistent units and higher values
57 * mean ``better signal''. The receive timestamp is currently not used
58 * by the 802.11 layer.
61 ieee80211_input(ieee80211com_t
*ic
, mblk_t
*mp
, struct ieee80211_node
*in
,
62 int32_t rssi
, uint32_t rstamp
)
64 struct ieee80211_frame
*wh
;
65 struct ieee80211_key
*key
;
76 if (mp
->b_flag
& M_AMPDU
) {
78 * Fastpath for A-MPDU reorder q resubmission. Frames
79 * w/ M_AMPDU marked have already passed through here
80 * but were received out of order and been held on the
81 * reorder queue. When resubmitted they are marked
82 * with the M_AMPDU flag and we can bypass most of the
86 wh
= (struct ieee80211_frame
*)mp
->b_rptr
;
87 type
= IEEE80211_FC0_TYPE_DATA
;
88 dir
= wh
->i_fc
[1] & IEEE80211_FC1_DIR_MASK
;
89 subtype
= IEEE80211_FC0_SUBTYPE_QOS
;
90 hdrspace
= ieee80211_hdrspace(ic
, wh
); /* optimize */
91 /* clear driver/net80211 flags before passing up */
92 mp
->b_flag
&= ~M_AMPDU
;
97 in
->in_inact
= in
->in_inact_reload
;
98 type
= (uint8_t)-1; /* undefined */
100 if (len
< sizeof (struct ieee80211_frame_min
)) {
101 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_input: "
102 "too short (1): len %u", len
);
106 * Bit of a cheat here, we use a pointer for a 3-address
107 * frame format but don't reference fields past outside
108 * ieee80211_frame_min w/o first validating the data is
111 wh
= (struct ieee80211_frame
*)mp
->b_rptr
;
112 if ((wh
->i_fc
[0] & IEEE80211_FC0_VERSION_MASK
) !=
113 IEEE80211_FC0_VERSION_0
) {
114 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_input: "
115 "discard pkt with wrong version %x", wh
->i_fc
[0]);
119 dir
= wh
->i_fc
[1] & IEEE80211_FC1_DIR_MASK
;
120 type
= wh
->i_fc
[0] & IEEE80211_FC0_TYPE_MASK
;
121 subtype
= wh
->i_fc
[0] & IEEE80211_FC0_SUBTYPE_MASK
;
124 if (!(ic
->ic_flags
& IEEE80211_F_SCAN
)) {
125 switch (ic
->ic_opmode
) {
126 case IEEE80211_M_STA
:
128 if (!IEEE80211_ADDR_EQ(bssid
, in
->in_bssid
))
131 case IEEE80211_M_IBSS
:
132 case IEEE80211_M_AHDEMO
:
133 if (dir
!= IEEE80211_FC1_DIR_NODS
) {
135 } else if (type
== IEEE80211_FC0_TYPE_CTL
) {
138 if (len
< sizeof (struct ieee80211_frame
)) {
139 ieee80211_dbg(IEEE80211_MSG_ANY
,
140 "ieee80211_input: too short(2):"
146 if (type
!= IEEE80211_FC0_TYPE_DATA
)
149 * Data frame, validate the bssid.
151 if (!IEEE80211_ADDR_EQ(bssid
, ic
->ic_bss
->in_bssid
) &&
152 !IEEE80211_ADDR_EQ(bssid
, wifi_bcastaddr
)) {
153 /* not interested in */
154 ieee80211_dbg(IEEE80211_MSG_INPUT
,
155 "ieee80211_input: not to bss %s\n",
156 ieee80211_macaddr_sprintf(bssid
));
160 * For adhoc mode we cons up a node when it doesn't
161 * exist. This should probably done after an ACL check.
163 if (in
== ic
->ic_bss
&&
164 ic
->ic_opmode
!= IEEE80211_M_HOSTAP
&&
165 !IEEE80211_ADDR_EQ(wh
->i_addr2
, in
->in_macaddr
)) {
167 * Fake up a node for this newly
168 * discovered member of the IBSS.
170 in
= ieee80211_fakeup_adhoc_node(&ic
->ic_sta
,
173 /* NB: stat kept for alloc failure */
181 in
->in_rssi
= (uint8_t)rssi
;
182 in
->in_rstamp
= rstamp
;
183 if (!(type
& IEEE80211_FC0_TYPE_CTL
)) {
184 if (IEEE80211_QOS_HAS_SEQ(wh
)) {
185 tid
= ((struct ieee80211_qosframe
*)wh
)->
186 i_qos
[0] & IEEE80211_QOS_TID
;
187 if (TID_TO_WME_AC(tid
) >= WME_AC_VI
)
188 ic
->ic_wme
.wme_hipri_traffic
++;
191 tid
= IEEE80211_NONQOS_TID
;
193 rxseq
= LE_16(*(uint16_t *)wh
->i_seq
);
194 if ((in
->in_flags
& IEEE80211_NODE_HT
) == 0 &&
195 (wh
->i_fc
[1] & IEEE80211_FC1_RETRY
) &&
196 (rxseq
- in
->in_rxseqs
[tid
]) <= 0) {
197 /* duplicate, discard */
198 ieee80211_dbg(IEEE80211_MSG_INPUT
,
199 "ieee80211_input: duplicate",
200 "seqno <%u,%u> fragno <%u,%u> tid %u",
201 rxseq
>> IEEE80211_SEQ_SEQ_SHIFT
,
202 in
->in_rxseqs
[tid
] >>
203 IEEE80211_SEQ_SEQ_SHIFT
,
204 rxseq
& IEEE80211_SEQ_FRAG_MASK
,
206 IEEE80211_SEQ_FRAG_MASK
,
208 ic
->ic_stats
.is_rx_dups
++;
211 in
->in_rxseqs
[tid
] = rxseq
;
216 case IEEE80211_FC0_TYPE_DATA
:
217 hdrspace
= ieee80211_hdrspace(ic
, wh
);
218 if (len
< hdrspace
) {
219 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_input: "
220 "data too short: expecting %u", hdrspace
);
223 switch (ic
->ic_opmode
) {
224 case IEEE80211_M_STA
:
225 if (dir
!= IEEE80211_FC1_DIR_FROMDS
) {
226 ieee80211_dbg(IEEE80211_MSG_INPUT
,
227 "ieee80211_input: data ",
228 "unknown dir 0x%x", dir
);
231 if (IEEE80211_IS_MULTICAST(wh
->i_addr1
) &&
232 IEEE80211_ADDR_EQ(wh
->i_addr3
, ic
->ic_macaddr
)) {
234 * In IEEE802.11 network, multicast packet
235 * sent from me is broadcasted from AP.
236 * It should be silently discarded for
239 ieee80211_dbg(IEEE80211_MSG_INPUT
,
240 "ieee80211_input: multicast echo\n");
244 case IEEE80211_M_IBSS
:
245 case IEEE80211_M_AHDEMO
:
246 if (dir
!= IEEE80211_FC1_DIR_NODS
) {
247 ieee80211_dbg(IEEE80211_MSG_INPUT
,
248 "ieee80211_input: unknown dir 0x%x",
254 ieee80211_err("ieee80211_input: "
255 "receive data, unknown opmode %u, skip\n",
261 * Handle A-MPDU re-ordering. The station must be
262 * associated and negotiated HT. The frame must be
263 * a QoS frame (not QoS null data) and not previously
264 * processed for A-MPDU re-ordering. If the frame is
265 * to be processed directly then ieee80211_ampdu_reorder
266 * will return 0; otherwise it has consumed the mbuf
267 * and we should do nothing more with it.
269 if ((in
->in_flags
& IEEE80211_NODE_HT
) &&
270 (subtype
== IEEE80211_FC0_SUBTYPE_QOS
)) {
271 IEEE80211_UNLOCK(ic
);
272 if (ieee80211_ampdu_reorder(in
, mp
) != 0) {
273 mp
= NULL
; /* CONSUMED */
281 * Handle privacy requirements.
283 if (wh
->i_fc
[1] & IEEE80211_FC1_WEP
) {
284 if ((ic
->ic_flags
& IEEE80211_F_PRIVACY
) == 0) {
286 * Discard encrypted frames when privacy off.
288 ieee80211_dbg(IEEE80211_MSG_INPUT
,
289 "ieee80211_input: ""WEP PRIVACY off");
290 ic
->ic_stats
.is_wep_errors
++;
293 key
= ieee80211_crypto_decap(ic
, mp
, hdrspace
);
295 /* NB: stats+msgs handled in crypto_decap */
296 ic
->ic_stats
.is_wep_errors
++;
299 wh
= (struct ieee80211_frame
*)mp
->b_rptr
;
300 wh
->i_fc
[1] &= ~IEEE80211_FC1_WEP
;
306 * Save QoS bits for use below--before we strip the header.
308 if (subtype
== IEEE80211_FC0_SUBTYPE_QOS
) {
309 qos
= (dir
== IEEE80211_FC1_DIR_DSTODS
) ?
310 ((struct ieee80211_qosframe_addr4
*)wh
)->i_qos
[0] :
311 ((struct ieee80211_qosframe
*)wh
)->i_qos
[0];
317 * Next up, any fragmentation
319 if (!IEEE80211_IS_MULTICAST(wh
->i_addr1
)) {
320 mp
= ieee80211_defrag(ic
, in
, mp
, hdrspace
);
322 /* Fragment dropped or frame not complete yet */
326 wh
= NULL
; /* no longer valid, catch any uses */
329 * Next strip any MSDU crypto bits.
331 if (key
!= NULL
&& !ieee80211_crypto_demic(ic
, key
, mp
, 0)) {
332 ieee80211_dbg(IEEE80211_MSG_INPUT
, "ieee80211_input: "
333 "data demic error\n");
337 if (qos
& IEEE80211_QOS_AMSDU
) {
338 ieee80211_dbg(IEEE80211_MSG_INPUT
| IEEE80211_MSG_HT
,
339 "ieee80211_input: QOS_AMSDU (%x)\n", qos
);
341 mp
= ieee80211_decap_amsdu(in
, mp
);
342 if (mp
== NULL
) /* MSDU processed by HT */
346 ic
->ic_stats
.is_rx_frags
++;
347 ic
->ic_stats
.is_rx_bytes
+= len
;
348 IEEE80211_UNLOCK(ic
);
349 mac_rx(ic
->ic_mach
, NULL
, mp
);
350 return (IEEE80211_FC0_TYPE_DATA
);
352 case IEEE80211_FC0_TYPE_MGT
:
353 if (dir
!= IEEE80211_FC1_DIR_NODS
)
355 if (len
< sizeof (struct ieee80211_frame
))
357 if (wh
->i_fc
[1] & IEEE80211_FC1_WEP
) {
358 if (subtype
!= IEEE80211_FC0_SUBTYPE_AUTH
) {
360 * Only shared key auth frames with a challenge
361 * should be encrypted, discard all others.
363 ieee80211_dbg(IEEE80211_MSG_INPUT
,
365 "%s WEP set but not permitted",
366 IEEE80211_SUBTYPE_NAME(subtype
));
367 ic
->ic_stats
.is_wep_errors
++;
370 if ((ic
->ic_flags
& IEEE80211_F_PRIVACY
) == 0) {
372 * Discard encrypted frames when privacy off.
374 ieee80211_dbg(IEEE80211_MSG_INPUT
,
376 "mgt WEP set but PRIVACY off");
377 ic
->ic_stats
.is_wep_errors
++;
380 hdrspace
= ieee80211_hdrspace(ic
, wh
);
381 key
= ieee80211_crypto_decap(ic
, mp
, hdrspace
);
383 /* NB: stats+msgs handled in crypto_decap */
386 wh
= (struct ieee80211_frame
*)mp
->b_rptr
;
387 wh
->i_fc
[1] &= ~IEEE80211_FC1_WEP
;
389 IEEE80211_UNLOCK(ic
);
390 ic
->ic_recv_mgmt(ic
, mp
, in
, subtype
, rssi
, rstamp
);
393 case IEEE80211_FC0_TYPE_CTL
:
394 if (ic
->ic_opmode
== IEEE80211_M_HOSTAP
) {
396 case IEEE80211_FC0_SUBTYPE_BAR
:
397 ieee80211_recv_bar(in
, mp
);
404 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_input: "
405 "bad frame type 0x%x", type
);
406 /* should not come here */
410 IEEE80211_UNLOCK(ic
);
419 * This function reassemble fragments.
420 * More fragments bit in the frame control means the packet is fragmented.
421 * While the sequence control field consists of 4-bit fragment number
422 * field and a 12-bit sequence number field.
426 ieee80211_defrag(ieee80211com_t
*ic
, struct ieee80211_node
*in
, mblk_t
*mp
,
429 struct ieee80211_frame
*wh
= (struct ieee80211_frame
*)mp
->b_rptr
;
430 struct ieee80211_frame
*lwh
;
436 ASSERT(!IEEE80211_IS_MULTICAST(wh
->i_addr1
));
437 more_frag
= wh
->i_fc
[1] & IEEE80211_FC1_MORE_FRAG
;
438 rxseq
= LE_16(*(uint16_t *)wh
->i_seq
);
439 fragno
= rxseq
& IEEE80211_SEQ_FRAG_MASK
;
441 /* Quick way out, if there's nothing to defragment */
442 if (!more_frag
&& fragno
== 0 && in
->in_rxfrag
== NULL
)
446 * Remove frag to insure it doesn't get reaped by timer.
448 if (in
->in_table
== NULL
) {
450 * Should never happen. If the node is orphaned (not in
451 * the table) then input packets should not reach here.
452 * Otherwise, a concurrent request that yanks the table
453 * should be blocked by other interlocking and/or by first
454 * shutting the driver down. Regardless, be defensive
460 IEEE80211_NODE_LOCK(in
->in_table
);
461 mfrag
= in
->in_rxfrag
;
462 in
->in_rxfrag
= NULL
;
463 IEEE80211_NODE_UNLOCK(in
->in_table
);
466 * Validate new fragment is in order and
467 * related to the previous ones.
472 lwh
= (struct ieee80211_frame
*)mfrag
->b_rptr
;
473 last_rxseq
= LE_16(*(uint16_t *)lwh
->i_seq
);
475 * Sequence control field contains 12-bit sequence no
476 * and 4-bit fragment number. For fragemnts, the
477 * sequence no is not changed.
478 * NB: check seq # and frag together
480 if (rxseq
!= last_rxseq
+ 1 ||
481 !IEEE80211_ADDR_EQ(wh
->i_addr1
, lwh
->i_addr1
) ||
482 !IEEE80211_ADDR_EQ(wh
->i_addr2
, lwh
->i_addr2
)) {
484 * Unrelated fragment or no space for it,
485 * clear current fragments.
493 if (fragno
!= 0) { /* !first fragment, discard */
498 } else { /* concatenate */
499 (void) adjmsg(mp
, hdrspace
);
501 /* track last seqnum and fragno */
502 lwh
= (struct ieee80211_frame
*)mfrag
->b_rptr
;
503 *(uint16_t *)lwh
->i_seq
= *(uint16_t *)wh
->i_seq
;
505 if (more_frag
!= 0) { /* more to come, save */
506 in
->in_rxfragstamp
= ddi_get_lbolt();
507 in
->in_rxfrag
= mfrag
;
515 * Install received rate set information in the node's state block.
518 ieee80211_setup_rates(struct ieee80211_node
*in
, const uint8_t *rates
,
519 const uint8_t *xrates
, int flags
)
521 struct ieee80211_rateset
*rs
= &in
->in_rates
;
523 bzero(rs
, sizeof (*rs
));
524 rs
->ir_nrates
= rates
[1];
525 /* skip 1 byte element ID and 1 byte length */
526 bcopy(rates
+ 2, rs
->ir_rates
, rs
->ir_nrates
);
527 if (xrates
!= NULL
) {
531 * Tack on 11g extended supported rate element.
534 if (rs
->ir_nrates
+ nxrates
> IEEE80211_RATE_MAXSIZE
) {
535 nxrates
= IEEE80211_RATE_MAXSIZE
- rs
->ir_nrates
;
536 ieee80211_dbg(IEEE80211_MSG_XRATE
,
537 "ieee80211_setup_rates: %s",
538 "[%s] extended rate set too large;"
539 " only using %u of %u rates\n",
540 ieee80211_macaddr_sprintf(in
->in_macaddr
),
543 bcopy(xrates
+ 2, rs
->ir_rates
+ rs
->ir_nrates
, nxrates
);
544 rs
->ir_nrates
+= nxrates
;
546 return (ieee80211_fix_rate(in
, &in
->in_rates
, flags
));
550 * Process open-system authentication response frame and start
551 * association if the authentication request is accepted.
554 ieee80211_auth_open(ieee80211com_t
*ic
, struct ieee80211_frame
*wh
,
555 struct ieee80211_node
*in
, uint16_t seq
, uint16_t status
)
557 IEEE80211_LOCK_ASSERT(ic
);
558 if (in
->in_authmode
== IEEE80211_AUTH_SHARED
) {
559 ieee80211_dbg(IEEE80211_MSG_AUTH
,
560 "open auth: bad sta auth mode %u", in
->in_authmode
);
563 if (ic
->ic_opmode
== IEEE80211_M_STA
) {
564 if (ic
->ic_state
!= IEEE80211_S_AUTH
||
565 seq
!= IEEE80211_AUTH_OPEN_RESPONSE
) {
568 IEEE80211_UNLOCK(ic
);
570 ieee80211_dbg(IEEE80211_MSG_DEBUG
| IEEE80211_MSG_AUTH
,
571 "open auth failed (reason %d)\n", status
);
572 if (in
!= ic
->ic_bss
)
574 ieee80211_new_state(ic
, IEEE80211_S_SCAN
, 0);
576 /* i_fc[0] - frame control's type & subtype field */
577 ieee80211_new_state(ic
, IEEE80211_S_ASSOC
,
578 wh
->i_fc
[0] & IEEE80211_FC0_SUBTYPE_MASK
);
582 ieee80211_dbg(IEEE80211_MSG_AUTH
, "ieee80211_auth_open: "
583 "bad operating mode %u", ic
->ic_opmode
);
588 * Allocate challenge text for use by shared-key authentication
589 * Return B_TRUE on success, B_FALST otherwise.
592 ieee80211_alloc_challenge(struct ieee80211_node
*in
)
594 if (in
->in_challenge
== NULL
) {
595 in
->in_challenge
= kmem_alloc(IEEE80211_CHALLENGE_LEN
,
598 if (in
->in_challenge
== NULL
) {
599 ieee80211_dbg(IEEE80211_MSG_DEBUG
| IEEE80211_MSG_AUTH
,
600 "[%s] shared key challenge alloc failed\n",
601 ieee80211_macaddr_sprintf(in
->in_macaddr
));
603 return (in
->in_challenge
!= NULL
);
607 * Process shared-key authentication response frames. If authentication
608 * succeeds, start association; otherwise, restart scan.
611 ieee80211_auth_shared(ieee80211com_t
*ic
, struct ieee80211_frame
*wh
,
612 uint8_t *frm
, uint8_t *efrm
, struct ieee80211_node
*in
, uint16_t seq
,
618 * Pre-shared key authentication is evil; accept
619 * it only if explicitly configured (it is supported
620 * mainly for compatibility with clients like OS X).
622 IEEE80211_LOCK_ASSERT(ic
);
623 if (in
->in_authmode
!= IEEE80211_AUTH_AUTO
&&
624 in
->in_authmode
!= IEEE80211_AUTH_SHARED
) {
625 ieee80211_dbg(IEEE80211_MSG_AUTH
, "ieee80211_auth_shared: "
626 "bad sta auth mode %u", in
->in_authmode
);
631 if (frm
+ 1 < efrm
) {
633 * Challenge text information element
634 * frm[0] - element ID
636 * frm[2]... - challenge text
638 if ((frm
[1] + 2) > (_PTRDIFF(efrm
, frm
))) {
639 ieee80211_dbg(IEEE80211_MSG_AUTH
,
640 "ieee80211_auth_shared: ie %d%d too long\n",
641 frm
[0], (frm
[1] + 2) - (_PTRDIFF(efrm
, frm
)));
644 if (*frm
== IEEE80211_ELEMID_CHALLENGE
)
649 case IEEE80211_AUTH_SHARED_CHALLENGE
:
650 case IEEE80211_AUTH_SHARED_RESPONSE
:
651 if (challenge
== NULL
) {
652 ieee80211_dbg(IEEE80211_MSG_AUTH
,
653 "ieee80211_auth_shared: no challenge\n");
656 if (challenge
[1] != IEEE80211_CHALLENGE_LEN
) {
657 ieee80211_dbg(IEEE80211_MSG_AUTH
,
658 "ieee80211_auth_shared: bad challenge len %d\n",
665 switch (ic
->ic_opmode
) {
666 case IEEE80211_M_STA
:
667 if (ic
->ic_state
!= IEEE80211_S_AUTH
)
670 case IEEE80211_AUTH_SHARED_PASS
:
671 if (in
->in_challenge
!= NULL
) {
672 kmem_free(in
->in_challenge
,
673 IEEE80211_CHALLENGE_LEN
);
674 in
->in_challenge
= NULL
;
677 ieee80211_dbg(IEEE80211_MSG_DEBUG
|
679 "shared key auth failed (reason %d)\n",
681 if (in
!= ic
->ic_bss
)
685 IEEE80211_UNLOCK(ic
);
686 ieee80211_new_state(ic
, IEEE80211_S_ASSOC
,
687 wh
->i_fc
[0] & IEEE80211_FC0_SUBTYPE_MASK
);
690 case IEEE80211_AUTH_SHARED_CHALLENGE
:
691 if (!ieee80211_alloc_challenge(in
))
693 bcopy(&challenge
[2], in
->in_challenge
, challenge
[1]);
694 IEEE80211_UNLOCK(ic
);
695 IEEE80211_SEND_MGMT(ic
, in
, IEEE80211_FC0_SUBTYPE_AUTH
,
700 ieee80211_dbg(IEEE80211_MSG_AUTH
, "80211_auth_shared: "
701 "shared key auth: bad seq %d", seq
);
707 ieee80211_dbg(IEEE80211_MSG_AUTH
,
708 "ieee80211_auth_shared: bad opmode %u\n",
714 if (ic
->ic_opmode
== IEEE80211_M_STA
) {
716 * Kick the state machine. This short-circuits
717 * using the mgt frame timeout to trigger the
720 if (ic
->ic_state
== IEEE80211_S_AUTH
) {
721 IEEE80211_UNLOCK(ic
);
722 ieee80211_new_state(ic
, IEEE80211_S_SCAN
, 0);
729 iswpaoui(const uint8_t *frm
)
732 bcopy(frm
+ 2, &c
, 4);
733 return (frm
[1] > 3 && LE_32(c
) == ((WPA_OUI_TYPE
<< 24) | WPA_OUI
));
736 #define LE_READ_4(p) \
738 ((((uint8_t *)(p))[0]) | (((uint8_t *)(p))[1] << 8) | \
739 (((uint8_t *)(p))[2] << 16) | (((uint8_t *)(p))[3] << 24)))
741 #define LE_READ_2(p) \
743 (((uint8_t *)(p))[0]) | (((uint8_t *)(p))[1] << 8))
746 iswmeoui(const uint8_t *frm
)
748 return (frm
[1] > 3 && LE_READ_4(frm
+2) == ((WME_OUI_TYPE
<<24)|WME_OUI
));
752 iswmeparam(const uint8_t *frm
)
754 return (frm
[1] > 5 &&
755 LE_READ_4(frm
+2) == ((WME_OUI_TYPE
<<24)|WME_OUI
) &&
756 frm
[6] == WME_PARAM_OUI_SUBTYPE
);
760 iswmeinfo(const uint8_t *frm
)
762 return (frm
[1] > 5 &&
763 LE_READ_4(frm
+2) == ((WME_OUI_TYPE
<<24)|WME_OUI
) &&
764 frm
[6] == WME_INFO_OUI_SUBTYPE
);
768 ishtcapoui(const uint8_t *frm
)
770 return (frm
[1] > 3 &&
771 LE_READ_4(frm
+2) == ((BCM_OUI_HTCAP
<<24)|BCM_OUI
));
775 ishtinfooui(const uint8_t *frm
)
777 return (frm
[1] > 3 &&
778 LE_READ_4(frm
+2) == ((BCM_OUI_HTINFO
<<24)|BCM_OUI
));
783 ieee80211_parse_wmeparams(struct ieee80211com
*ic
, uint8_t *frm
,
784 const struct ieee80211_frame
*wh
)
786 #define MS(_v, _f) (((_v) & _f) >> _f##_S)
787 struct ieee80211_wme_state
*wme
= &ic
->ic_wme
;
792 if (len
< sizeof (struct ieee80211_wme_param
) - 2) {
793 ieee80211_dbg(IEEE80211_MSG_ELEMID
| IEEE80211_MSG_WME
,
794 "WME too short, len %u", len
);
797 qosinfo
= frm
[offsetof(struct ieee80211_wme_param
, wme_qosInfo
)];
798 qosinfo
&= WME_QOSINFO_COUNT
;
799 /* do proper check for wraparound */
800 if (qosinfo
== wme
->wme_wmeChanParams
.cap_info
)
802 frm
+= offsetof(struct ieee80211_wme_param
, wme_acParams
);
803 for (i
= 0; i
< WME_NUM_AC
; i
++) {
804 struct wmeParams
*wmep
=
805 &wme
->wme_wmeChanParams
.cap_wmeParams
[i
];
806 /* NB: ACI not used */
807 wmep
->wmep_acm
= MS(frm
[0], WME_PARAM_ACM
);
808 wmep
->wmep_aifsn
= MS(frm
[0], WME_PARAM_AIFSN
);
809 wmep
->wmep_logcwmin
= MS(frm
[1], WME_PARAM_LOGCWMIN
);
810 wmep
->wmep_logcwmax
= MS(frm
[1], WME_PARAM_LOGCWMAX
);
811 wmep
->wmep_txopLimit
= LE_READ_2(frm
+2);
814 wme
->wme_wmeChanParams
.cap_info
= qosinfo
;
820 * Process a beacon/probe response frame.
821 * When the device is in station mode, create a node and add it
822 * to the node database for a new ESS or update node info if it's
826 ieee80211_recv_beacon(ieee80211com_t
*ic
, mblk_t
*mp
, struct ieee80211_node
*in
,
827 int subtype
, int rssi
, uint32_t rstamp
)
829 ieee80211_impl_t
*im
= ic
->ic_private
;
830 struct ieee80211_frame
*wh
;
832 uint8_t *efrm
; /* end of frame body */
833 struct ieee80211_scanparams scan
;
835 wh
= (struct ieee80211_frame
*)mp
->b_rptr
;
836 frm
= (uint8_t *)&wh
[1];
837 efrm
= (uint8_t *)mp
->b_wptr
;
839 ic
->ic_beaconmiss
= 0; /* clear beacon miss counter */
842 * We process beacon/probe response frames:
843 * o when scanning, or
844 * o station mode when associated (to collect state
845 * updates such as 802.11g slot time), or
846 * o adhoc mode (to discover neighbors)
847 * Frames otherwise received are discarded.
849 if (!((ic
->ic_flags
& IEEE80211_F_SCAN
) ||
850 (ic
->ic_opmode
== IEEE80211_M_STA
&& in
->in_associd
!= 0) ||
851 ic
->ic_opmode
== IEEE80211_M_IBSS
)) {
856 * beacon/probe response frame format
858 * [2] beacon interval
859 * [2] capability information
861 * [tlv] supported rates
862 * [tlv] country information
863 * [tlv] parameter set (FH/DS)
864 * [tlv] erp information
865 * [tlv] extended supported rates
868 * [tlv] HT capabilities
869 * [tlv] HT information
871 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
),
872 IEEE80211_BEACON_ELEM_MIN
, return);
873 bzero(&scan
, sizeof (scan
));
876 scan
.bintval
= LE_16(*(uint16_t *)frm
);
878 scan
.capinfo
= LE_16(*(uint16_t *)frm
);
880 scan
.bchan
= ieee80211_chan2ieee(ic
, ic
->ic_curchan
);
881 scan
.chan
= scan
.bchan
;
884 /* Agere element in beacon */
885 if ((*frm
== IEEE80211_ELEMID_AGERE1
) ||
886 (*frm
== IEEE80211_ELEMID_AGERE2
)) {
891 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
), frm
[1], return);
893 case IEEE80211_ELEMID_SSID
:
896 case IEEE80211_ELEMID_RATES
:
899 case IEEE80211_ELEMID_COUNTRY
:
902 case IEEE80211_ELEMID_FHPARMS
:
903 if (ic
->ic_phytype
== IEEE80211_T_FH
) {
904 scan
.fhdwell
= LE_16(*(uint16_t *)(frm
+ 2));
905 scan
.chan
= IEEE80211_FH_CHAN(frm
[4], frm
[5]);
906 scan
.fhindex
= frm
[6];
907 scan
.phytype
= IEEE80211_T_FH
;
910 case IEEE80211_ELEMID_DSPARMS
:
911 if (ic
->ic_phytype
!= IEEE80211_T_FH
) {
913 scan
.phytype
= IEEE80211_T_DS
;
916 case IEEE80211_ELEMID_TIM
:
918 scan
.timoff
= _PTRDIFF(frm
, mp
->b_rptr
);
920 case IEEE80211_ELEMID_IBSSPARMS
:
922 case IEEE80211_ELEMID_XRATES
:
925 case IEEE80211_ELEMID_ERP
:
927 ieee80211_dbg(IEEE80211_MSG_ELEMID
,
928 "ieee80211_recv_mgmt: ignore %s, "
929 "invalid ERP element; "
930 "length %u, expecting 1\n",
931 IEEE80211_SUBTYPE_NAME(subtype
),
936 scan
.phytype
= IEEE80211_T_OFDM
;
938 case IEEE80211_ELEMID_HTCAP
:
941 case IEEE80211_ELEMID_RSN
:
944 case IEEE80211_ELEMID_HTINFO
:
947 case IEEE80211_ELEMID_VENDOR
:
949 scan
.wpa
= frm
; /* IEEE802.11i D3.0 */
950 else if (iswmeparam(frm
) || iswmeinfo(frm
))
952 else if (ic
->ic_flags_ext
& IEEE80211_FEXT_HTCOMPAT
) {
954 * Accept pre-draft HT ie's if the
955 * standard ones have not been seen.
957 if (ishtcapoui(frm
)) {
958 if (scan
.htcap
== NULL
)
960 } else if (ishtinfooui(frm
)) {
961 if (scan
.htinfo
== NULL
)
967 ieee80211_dbg(IEEE80211_MSG_ELEMID
,
968 "ieee80211_recv_mgmt: ignore %s,"
969 "unhandled id %u, len %u, totallen %u",
970 IEEE80211_SUBTYPE_NAME(subtype
),
975 /* frm[1] - component length */
976 frm
+= IEEE80211_ELEM_LEN(frm
[1]);
978 IEEE80211_VERIFY_ELEMENT(scan
.rates
, IEEE80211_RATE_MAXSIZE
, return);
979 IEEE80211_VERIFY_ELEMENT(scan
.ssid
, IEEE80211_NWID_LEN
, return);
980 if (ieee80211_isclr(ic
->ic_chan_active
, scan
.chan
)) {
981 ieee80211_dbg(IEEE80211_MSG_ELEMID
| IEEE80211_MSG_INPUT
,
982 "ieee80211_recv_mgmt: ignore %s ,"
983 "invalid channel %u\n",
984 IEEE80211_SUBTYPE_NAME(subtype
), scan
.chan
);
987 if (scan
.chan
!= scan
.bchan
&&
988 ic
->ic_phytype
!= IEEE80211_T_FH
) {
990 * Frame was received on a channel different from the
991 * one indicated in the DS params element id;
992 * silently discard it.
994 * NB: this can happen due to signal leakage.
995 * But we should take it for FH phy because
996 * the rssi value should be correct even for
997 * different hop pattern in FH.
999 ieee80211_dbg(IEEE80211_MSG_ELEMID
,
1000 "ieee80211_recv_mgmt: ignore %s ,"
1001 "phytype %u channel %u marked for %u\n",
1002 IEEE80211_SUBTYPE_NAME(subtype
),
1003 ic
->ic_phytype
, scan
.bchan
, scan
.chan
);
1006 if (!(IEEE80211_BINTVAL_MIN
<= scan
.bintval
&&
1007 scan
.bintval
<= IEEE80211_BINTVAL_MAX
)) {
1008 ieee80211_dbg(IEEE80211_MSG_ELEMID
| IEEE80211_MSG_INPUT
,
1009 "ieee80211_recv_mgmt: ignore %s ,"
1010 "bogus beacon interval %u\n",
1011 IEEE80211_SUBTYPE_NAME(subtype
), scan
.bintval
);
1015 * Process HT ie's. This is complicated by our
1016 * accepting both the standard ie's and the pre-draft
1017 * vendor OUI ie's that some vendors still use/require.
1019 if (scan
.htcap
!= NULL
) {
1020 IEEE80211_VERIFY_LENGTH(scan
.htcap
[1],
1021 scan
.htcap
[0] == IEEE80211_ELEMID_VENDOR
?
1022 4 + sizeof (struct ieee80211_ie_htcap
) - 2 :
1023 sizeof (struct ieee80211_ie_htcap
) - 2,
1026 if (scan
.htinfo
!= NULL
) {
1027 IEEE80211_VERIFY_LENGTH(scan
.htinfo
[1],
1028 scan
.htinfo
[0] == IEEE80211_ELEMID_VENDOR
?
1029 4 + sizeof (struct ieee80211_ie_htinfo
) - 2 :
1030 sizeof (struct ieee80211_ie_htinfo
) - 2,
1031 scan
.htinfo
= NULL
);
1035 * When operating in station mode, check for state updates.
1036 * Be careful to ignore beacons received while doing a
1037 * background scan. We consider only 11g/WMM stuff right now.
1039 if (ic
->ic_opmode
== IEEE80211_M_STA
&&
1040 in
->in_associd
!= 0 &&
1041 (!(ic
->ic_flags
& IEEE80211_F_SCAN
) ||
1042 IEEE80211_ADDR_EQ(wh
->i_addr2
, in
->in_bssid
))) {
1043 /* record tsf of last beacon */
1044 bcopy(scan
.tstamp
, in
->in_tstamp
.data
,
1045 sizeof (in
->in_tstamp
));
1046 /* count beacon frame for s/w bmiss handling */
1047 im
->im_swbmiss_count
++;
1048 im
->im_bmiss_count
= 0;
1050 if ((in
->in_capinfo
^ scan
.capinfo
) &
1051 IEEE80211_CAPINFO_SHORT_SLOTTIME
) {
1052 ieee80211_dbg(IEEE80211_MSG_ASSOC
,
1053 "ieee80211_recv_mgmt: "
1054 "[%s] cap change: before 0x%x, now 0x%x\n",
1055 ieee80211_macaddr_sprintf(wh
->i_addr2
),
1056 in
->in_capinfo
, scan
.capinfo
);
1058 * NB: we assume short preamble doesn't
1059 * change dynamically
1061 ieee80211_set_shortslottime(ic
,
1062 ic
->ic_curmode
== IEEE80211_MODE_11A
||
1064 IEEE80211_CAPINFO_SHORT_SLOTTIME
));
1065 in
->in_capinfo
= scan
.capinfo
;
1067 if (scan
.wme
!= NULL
&&
1068 (in
->in_flags
& IEEE80211_NODE_QOS
) &&
1069 ieee80211_parse_wmeparams(ic
, scan
.wme
, wh
) > 0) {
1070 ieee80211_wme_updateparams(ic
);
1072 if (scan
.htcap
!= NULL
)
1073 ieee80211_parse_htcap(in
, scan
.htcap
);
1074 if (scan
.htinfo
!= NULL
) {
1075 ieee80211_parse_htinfo(in
, scan
.htinfo
);
1076 if (in
->in_chan
!= ic
->ic_curchan
) {
1078 * Channel has been adjusted based on
1079 * negotiated HT parameters; force the
1080 * channel state to follow.
1082 ieee80211_setcurchan(ic
, in
->in_chan
);
1085 if (scan
.tim
!= NULL
) {
1086 struct ieee80211_tim_ie
*ie
;
1088 ie
= (struct ieee80211_tim_ie
*)scan
.tim
;
1089 in
->in_dtim_count
= ie
->tim_count
;
1090 in
->in_dtim_period
= ie
->tim_period
;
1092 if (ic
->ic_flags
& IEEE80211_F_SCAN
) {
1093 ieee80211_add_scan(ic
, &scan
, wh
, subtype
, rssi
,
1099 * If scanning, just pass information to the scan module.
1101 if (ic
->ic_flags
& IEEE80211_F_SCAN
) {
1102 ieee80211_add_scan(ic
, &scan
, wh
, subtype
, rssi
, rstamp
);
1106 if (ic
->ic_opmode
== IEEE80211_M_IBSS
&&
1107 scan
.capinfo
& IEEE80211_CAPINFO_IBSS
) {
1108 if (!IEEE80211_ADDR_EQ(wh
->i_addr2
, in
->in_macaddr
)) {
1110 * Create a new entry in the neighbor table.
1112 in
= ieee80211_add_neighbor(ic
, wh
, &scan
);
1115 * Copy data from beacon to neighbor table.
1116 * Some of this information might change after
1117 * ieee80211_add_neighbor(), so we just copy
1118 * everything over to be safe.
1120 ieee80211_init_neighbor(in
, wh
, &scan
);
1123 in
->in_rssi
= (uint8_t)rssi
;
1124 in
->in_rstamp
= rstamp
;
1130 * Perform input processing for 802.11 management frames.
1131 * It's the default ic_recv_mgmt callback function for the interface
1132 * softc, ic. Tipically ic_recv_mgmt is called within ieee80211_input()
1135 ieee80211_recv_mgmt(ieee80211com_t
*ic
, mblk_t
*mp
, struct ieee80211_node
*in
,
1136 int subtype
, int rssi
, uint32_t rstamp
)
1138 struct ieee80211_frame
*wh
;
1139 uint8_t *frm
; /* pointer to start of the frame */
1140 uint8_t *efrm
; /* pointer to end of the frame */
1143 uint8_t *xrates
; /* extended rates */
1145 uint8_t *htcap
, *htinfo
;
1146 boolean_t allocbs
= B_FALSE
;
1148 uint16_t algo
; /* authentication algorithm */
1149 uint16_t seq
; /* sequence no */
1152 uint16_t associd
; /* association ID */
1153 const struct ieee80211_action
*ia
;
1156 wh
= (struct ieee80211_frame
*)mp
->b_rptr
;
1157 frm
= (uint8_t *)&wh
[1];
1158 efrm
= (uint8_t *)mp
->b_wptr
;
1160 case IEEE80211_FC0_SUBTYPE_PROBE_RESP
:
1161 case IEEE80211_FC0_SUBTYPE_BEACON
:
1162 ieee80211_recv_beacon(ic
, mp
, in
, subtype
, rssi
, rstamp
);
1165 case IEEE80211_FC0_SUBTYPE_PROBE_REQ
:
1166 if (ic
->ic_opmode
== IEEE80211_M_STA
||
1167 ic
->ic_state
!= IEEE80211_S_RUN
||
1168 IEEE80211_IS_MULTICAST(wh
->i_addr2
)) {
1173 * prreq frame format
1175 * [tlv] supported rates
1176 * [tlv] extended supported rates
1178 ssid
= rates
= xrates
= NULL
;
1179 while (frm
< efrm
) {
1180 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
),
1183 case IEEE80211_ELEMID_SSID
:
1186 case IEEE80211_ELEMID_RATES
:
1189 case IEEE80211_ELEMID_XRATES
:
1195 IEEE80211_VERIFY_ELEMENT(rates
, IEEE80211_RATE_MAXSIZE
, break);
1196 if (xrates
!= NULL
) {
1197 IEEE80211_VERIFY_ELEMENT(xrates
,
1198 IEEE80211_RATE_MAXSIZE
- rates
[1], break);
1200 IEEE80211_VERIFY_ELEMENT(ssid
, IEEE80211_NWID_LEN
, break);
1201 IEEE80211_VERIFY_SSID(ic
->ic_bss
, ssid
, break);
1202 if (ic
->ic_flags
& IEEE80211_F_HIDESSID
) {
1203 if (ssid
== NULL
|| ssid
[1] == 0) {
1204 ieee80211_dbg(IEEE80211_MSG_INPUT
,
1205 "ieee80211_recv_mgmt: ignore %s, "
1206 "no ssid with ssid suppression enabled",
1207 IEEE80211_SUBTYPE_NAME(subtype
));
1212 if (in
== ic
->ic_bss
) {
1213 if (ic
->ic_opmode
!= IEEE80211_M_IBSS
) {
1214 in
= ieee80211_tmp_node(ic
, wh
->i_addr2
);
1216 } else if (!IEEE80211_ADDR_EQ(wh
->i_addr2
,
1219 * Cannot tell if the sender is operating
1220 * in ibss mode. But we need a new node to
1221 * send the response so blindly add them to the
1224 in
= ieee80211_fakeup_adhoc_node(&ic
->ic_sta
,
1230 ieee80211_dbg(IEEE80211_MSG_ASSOC
, "ieee80211_recv_mgmt: "
1231 "[%s] recv probe req\n",
1232 ieee80211_macaddr_sprintf(wh
->i_addr2
));
1233 in
->in_rssi
= (uint8_t)rssi
;
1234 in
->in_rstamp
= rstamp
;
1236 * Adjust and check station's rate list with device's
1237 * supported rate. Send back response if there is at
1238 * least one rate or the fixed rate(if being set) is
1239 * supported by both station and the device
1241 rate
= ieee80211_setup_rates(in
, rates
, xrates
,
1242 IEEE80211_F_DOSORT
| IEEE80211_F_DOFRATE
|
1243 IEEE80211_F_DONEGO
| IEEE80211_F_DODEL
);
1244 if (rate
& IEEE80211_RATE_BASIC
) {
1245 ieee80211_dbg(IEEE80211_MSG_XRATE
, "ieee80211_recv_mgmt"
1246 "%s recv'd rate set invalid",
1247 IEEE80211_SUBTYPE_NAME(subtype
));
1249 IEEE80211_UNLOCK(ic
);
1250 IEEE80211_SEND_MGMT(ic
, in
,
1251 IEEE80211_FC0_SUBTYPE_PROBE_RESP
, 0);
1256 * Temporary node created just to send a
1257 * response, reclaim immediately.
1259 ieee80211_free_node(in
);
1263 case IEEE80211_FC0_SUBTYPE_AUTH
:
1271 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
),
1272 IEEE80211_AUTH_ELEM_MIN
, break);
1273 algo
= LE_16(*(uint16_t *)frm
);
1274 seq
= LE_16(*(uint16_t *)(frm
+ 2));
1275 status
= LE_16(*(uint16_t *)(frm
+ 4));
1276 ieee80211_dbg(IEEE80211_MSG_AUTH
, "ieee80211_recv_mgmt: "
1277 "[%s] recv auth frame with algorithm %d seq %d\n",
1278 ieee80211_macaddr_sprintf(wh
->i_addr2
), algo
, seq
);
1280 if (ic
->ic_flags
& IEEE80211_F_COUNTERM
) {
1281 ieee80211_dbg(IEEE80211_MSG_AUTH
| IEEE80211_MSG_CRYPTO
,
1282 "ieee80211_recv_mgmt: ignore auth, %s\n",
1283 "TKIP countermeasures enabled");
1287 case IEEE80211_AUTH_ALG_SHARED
:
1288 ieee80211_auth_shared(ic
, wh
, frm
+ 6, efrm
, in
,
1291 case IEEE80211_AUTH_ALG_OPEN
:
1292 ieee80211_auth_open(ic
, wh
, in
, seq
, status
);
1295 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_recv_mgmt: "
1296 "ignore auth, unsupported alg %d", algo
);
1301 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP
:
1302 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP
:
1303 if (ic
->ic_opmode
!= IEEE80211_M_STA
||
1304 ic
->ic_state
!= IEEE80211_S_ASSOC
)
1308 * asresp frame format
1309 * [2] capability information
1311 * [2] association ID
1312 * [tlv] supported rates
1313 * [tlv] extended supported rates
1315 * [tlv] HT capabilities
1318 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
),
1319 IEEE80211_ASSOC_RESP_ELEM_MIN
, break);
1321 capinfo
= LE_16(*(uint16_t *)frm
);
1323 status
= LE_16(*(uint16_t *)frm
);
1326 ieee80211_dbg(IEEE80211_MSG_ASSOC
,
1327 "assoc failed (reason %d)\n", status
);
1328 in
= ieee80211_find_node(&ic
->ic_scan
, wh
->i_addr2
);
1331 ieee80211_free_node(in
);
1335 associd
= LE_16(*(uint16_t *)frm
);
1338 rates
= xrates
= wme
= htcap
= htinfo
= NULL
;
1339 while (frm
< efrm
) {
1341 * Do not discard frames containing proprietary Agere
1342 * elements 128 and 129, as the reported element length
1343 * is often wrong. Skip rest of the frame, since we can
1344 * not rely on the given element length making it
1345 * impossible to know where the next element starts
1347 if ((*frm
== IEEE80211_ELEMID_AGERE1
) ||
1348 (*frm
== IEEE80211_ELEMID_AGERE2
)) {
1353 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
),
1356 case IEEE80211_ELEMID_RATES
:
1359 case IEEE80211_ELEMID_XRATES
:
1362 case IEEE80211_ELEMID_HTCAP
:
1365 case IEEE80211_ELEMID_HTINFO
:
1368 case IEEE80211_ELEMID_VENDOR
:
1371 else if (ic
->ic_flags_ext
&
1372 IEEE80211_FEXT_HTCOMPAT
) {
1374 * Accept pre-draft HT ie's if the
1375 * standard ones have not been seen.
1377 if (ishtcapoui(frm
)) {
1380 } else if (ishtinfooui(frm
)) {
1390 IEEE80211_VERIFY_ELEMENT(rates
, IEEE80211_RATE_MAXSIZE
, break);
1392 * Adjust and check AP's rate list with device's
1393 * supported rate. Re-start scan if no rate is or the
1394 * fixed rate(if being set) cannot be supported by
1395 * either AP or the device.
1397 rate
= ieee80211_setup_rates(in
, rates
, xrates
,
1398 IEEE80211_F_DOSORT
| IEEE80211_F_DOFRATE
|
1399 IEEE80211_F_DONEGO
| IEEE80211_F_DODEL
);
1400 if (rate
& IEEE80211_RATE_BASIC
) {
1401 ieee80211_dbg(IEEE80211_MSG_ASSOC
,
1402 "assoc failed (rate set mismatch)\n");
1403 if (in
!= ic
->ic_bss
)
1405 IEEE80211_UNLOCK(ic
);
1406 ieee80211_new_state(ic
, IEEE80211_S_SCAN
, 0);
1410 in
->in_capinfo
= capinfo
;
1411 in
->in_associd
= associd
;
1413 ieee80211_parse_wmeparams(ic
, wme
, wh
) >= 0) {
1414 in
->in_flags
|= IEEE80211_NODE_QOS
;
1415 ieee80211_wme_updateparams(ic
);
1417 in
->in_flags
&= ~IEEE80211_NODE_QOS
;
1420 * Setup HT state according to the negotiation.
1422 if ((ic
->ic_htcaps
& IEEE80211_HTC_HT
) &&
1423 htcap
!= NULL
&& htinfo
!= NULL
) {
1424 ieee80211_ht_node_init(in
, htcap
);
1425 ieee80211_parse_htinfo(in
, htinfo
);
1426 (void) ieee80211_setup_htrates(in
,
1427 htcap
, IEEE80211_F_JOIN
| IEEE80211_F_DOBRS
);
1428 ieee80211_setup_basic_htrates(in
, htinfo
);
1429 if (in
->in_chan
!= ic
->ic_curchan
) {
1431 * Channel has been adjusted based on
1432 * negotiated HT parameters; force the
1433 * channel state to follow.
1435 ieee80211_setcurchan(ic
, in
->in_chan
);
1439 * Configure state now that we are associated.
1441 if (ic
->ic_curmode
== IEEE80211_MODE_11A
||
1442 (in
->in_capinfo
& IEEE80211_CAPINFO_SHORT_PREAMBLE
)) {
1443 ic
->ic_flags
|= IEEE80211_F_SHPREAMBLE
;
1444 ic
->ic_flags
&= ~IEEE80211_F_USEBARKER
;
1446 ic
->ic_flags
&= ~IEEE80211_F_SHPREAMBLE
;
1447 ic
->ic_flags
|= IEEE80211_F_USEBARKER
;
1449 ieee80211_set_shortslottime(ic
,
1450 ic
->ic_curmode
== IEEE80211_MODE_11A
||
1451 (in
->in_capinfo
& IEEE80211_CAPINFO_SHORT_SLOTTIME
));
1453 * Honor ERP protection.
1455 * NB: in_erp should zero for non-11g operation.
1456 * check ic_curmode anyway
1458 if (ic
->ic_curmode
== IEEE80211_MODE_11G
&&
1459 (in
->in_erp
& IEEE80211_ERP_USE_PROTECTION
))
1460 ic
->ic_flags
|= IEEE80211_F_USEPROT
;
1462 ic
->ic_flags
&= ~IEEE80211_F_USEPROT
;
1463 ieee80211_dbg(IEEE80211_MSG_ASSOC
,
1464 "assoc success: %s preamble, %s slot time%s%s\n",
1465 ic
->ic_flags
&IEEE80211_F_SHPREAMBLE
? "short" : "long",
1466 ic
->ic_flags
&IEEE80211_F_SHSLOT
? "short" : "long",
1467 ic
->ic_flags
&IEEE80211_F_USEPROT
? ", protection" : "",
1468 in
->in_flags
& IEEE80211_NODE_QOS
? ", QoS" : "");
1469 IEEE80211_UNLOCK(ic
);
1470 ieee80211_new_state(ic
, IEEE80211_S_RUN
, subtype
);
1473 case IEEE80211_FC0_SUBTYPE_DEAUTH
:
1474 if (ic
->ic_state
== IEEE80211_S_SCAN
)
1478 * deauth frame format
1481 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
), 2, break);
1482 status
= LE_16(*(uint16_t *)frm
);
1484 ieee80211_dbg(IEEE80211_MSG_AUTH
,
1485 "recv deauthenticate (reason %d)\n", status
);
1486 switch (ic
->ic_opmode
) {
1487 case IEEE80211_M_STA
:
1488 IEEE80211_UNLOCK(ic
);
1489 ieee80211_new_state(ic
, IEEE80211_S_AUTH
,
1490 wh
->i_fc
[0] & IEEE80211_FC0_SUBTYPE_MASK
);
1497 case IEEE80211_FC0_SUBTYPE_DISASSOC
:
1498 if (ic
->ic_state
!= IEEE80211_S_RUN
&&
1499 ic
->ic_state
!= IEEE80211_S_ASSOC
&&
1500 ic
->ic_state
!= IEEE80211_S_AUTH
)
1503 * disassoc frame format
1506 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
), 2, break);
1507 status
= LE_16(*(uint16_t *)frm
);
1509 ieee80211_dbg(IEEE80211_MSG_ASSOC
,
1510 "recv disassociate (reason %d)\n", status
);
1511 switch (ic
->ic_opmode
) {
1512 case IEEE80211_M_STA
:
1513 IEEE80211_UNLOCK(ic
);
1514 ieee80211_new_state(ic
, IEEE80211_S_ASSOC
,
1515 wh
->i_fc
[0] & IEEE80211_FC0_SUBTYPE_MASK
);
1522 case IEEE80211_FC0_SUBTYPE_ACTION
:
1523 if (ic
->ic_state
!= IEEE80211_S_RUN
&&
1524 ic
->ic_state
!= IEEE80211_S_ASSOC
&&
1525 ic
->ic_state
!= IEEE80211_S_AUTH
)
1529 * action frame format:
1534 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
),
1535 sizeof (struct ieee80211_action
), break);
1536 ia
= (const struct ieee80211_action
*) frm
;
1538 /* verify frame payloads but defer processing */
1539 /* maybe push this to method */
1540 switch (ia
->ia_category
) {
1541 case IEEE80211_ACTION_CAT_BA
:
1542 switch (ia
->ia_action
) {
1543 case IEEE80211_ACTION_BA_ADDBA_REQUEST
:
1544 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
),
1545 sizeof (struct ieee80211_action_ba_addbarequest
),
1548 case IEEE80211_ACTION_BA_ADDBA_RESPONSE
:
1549 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
),
1550 sizeof (struct ieee80211_action_ba_addbaresponse
),
1553 case IEEE80211_ACTION_BA_DELBA
:
1554 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
),
1555 sizeof (struct ieee80211_action_ba_delba
),
1560 case IEEE80211_ACTION_CAT_HT
:
1561 switch (ia
->ia_action
) {
1562 case IEEE80211_ACTION_HT_TXCHWIDTH
:
1563 IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm
, frm
),
1564 sizeof (struct ieee80211_action_ht_txchwidth
),
1570 ic
->ic_recv_action(in
, frm
, efrm
);
1574 ieee80211_dbg(IEEE80211_MSG_ANY
, "ieee80211_recv_mgmt: "
1575 "subtype 0x%x not handled\n", subtype
);
1577 } /* switch subtype */
1579 IEEE80211_UNLOCK(ic
);