net80211_input.c revision 0ba2cbe97e0678a691742f98d2532caed0a2c4aa
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Use is subject to license terms.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Copyright (c) 2001 Atsushi Onoe
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * All rights reserved.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Redistribution and use in source and binary forms, with or without
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * modification, are permitted provided that the following conditions
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * are met:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * 1. Redistributions of source code must retain the above copyright
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * notice, this list of conditions and the following disclaimer.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * 2. Redistributions in binary form must reproduce the above copyright
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * notice, this list of conditions and the following disclaimer in the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * documentation and/or other materials provided with the distribution.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * 3. The name of the author may not be used to endorse or promote products
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * derived from this software without specific prior written permission.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Alternatively, this software may be distributed under the terms of the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * GNU General Public License ("GPL") version 2 as published by the Free
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Software Foundation.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc#pragma ident "%Z%%M% %I% %E% SMI"
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Process received frame
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc#include <sys/byteorder.h>
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc#include "net80211_impl.h"
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic mblk_t *ieee80211_defrag(ieee80211com_t *, ieee80211_node_t *,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mblk_t *, int);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Process a received frame. The node associated with the sender
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * should be supplied. If nothing was found in the node table then
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * the caller is assumed to supply a reference to ic_bss instead.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * The RSSI and a timestamp are also supplied. The RSSI data is used
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * during AP scanning to select a AP to associate with; it can have
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * any units so long as values have consistent units and higher values
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * mean ``better signal''. The receive timestamp is currently not used
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * by the 802.11 layer.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcint
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_input(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int32_t rssi, uint32_t rstamp)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_frame *wh;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_key *key;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t *bssid;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int hdrspace;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int len;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint16_t rxseq;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t dir;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t type;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t subtype;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t tid;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ASSERT(in != NULL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc type = (uint8_t)-1; /* undefined */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc len = mp->b_wptr - mp->b_rptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (len < sizeof (struct ieee80211_frame_min)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "too short (1): len %u", len);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Bit of a cheat here, we use a pointer for a 3-address
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * frame format but don't reference fields past outside
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * ieee80211_frame_min w/o first validating the data is
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * present.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh = (struct ieee80211_frame *)mp->b_rptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_FC0_VERSION_0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "discard pkt with wrong version %x", wh->i_fc[0]);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!(ic->ic_flags & IEEE80211_F_SCAN)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (ic->ic_opmode) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_STA:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bssid = wh->i_addr2;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!IEEE80211_ADDR_EQ(bssid, in->in_bssid))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_IBSS:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_AHDEMO:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (dir != IEEE80211_FC1_DIR_NODS) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bssid = wh->i_addr1;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else if (type == IEEE80211_FC0_TYPE_CTL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bssid = wh->i_addr1;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (len < sizeof (struct ieee80211_frame)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ANY,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_input: too short(2):"
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "len %u\n", len);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bssid = wh->i_addr3;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (type != IEEE80211_FC0_TYPE_DATA)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Data frame, validate the bssid.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->in_bssid) &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc !IEEE80211_ADDR_EQ(bssid, wifi_bcastaddr)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* not interested in */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_input: not to bss %s\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_macaddr_sprintf(bssid));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * For adhoc mode we cons up a node when it doesn't
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * exist. This should probably done after an ACL check.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == ic->ic_bss &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_opmode != IEEE80211_M_HOSTAP &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc !IEEE80211_ADDR_EQ(wh->i_addr2, in->in_macaddr)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Fake up a node for this newly
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * discovered member of the IBSS.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh->i_addr2);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* NB: stat kept for alloc failure */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rssi = (uint8_t)rssi;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rstamp = rstamp;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!(type & IEEE80211_FC0_TYPE_CTL)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc tid = 0;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rxseq = (*(uint16_t *)wh->i_seq);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (rxseq - in->in_rxseqs[tid]) <= 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* duplicate, discard */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_input: duplicate",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "seqno <%u,%u> fragno <%u,%u> tid %u",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rxseqs[tid] >>
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SEQ_SEQ_SHIFT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rxseq & IEEE80211_SEQ_FRAG_MASK,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rxseqs[tid] &
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SEQ_FRAG_MASK,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc tid);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_stats.is_rx_dups++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rxseqs[tid] = rxseq;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_inact = 0;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc hdrspace = ieee80211_hdrspace(wh);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (type) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_TYPE_DATA:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (len < hdrspace) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "data too short: expecting %u", hdrspace);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (ic->ic_opmode) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_STA:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (dir != IEEE80211_FC1_DIR_FROMDS) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_input: data ",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "unknown dir 0x%x", dir);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (IEEE80211_IS_MULTICAST(wh->i_addr1) &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_macaddr)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * In IEEE802.11 network, multicast packet
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * sent from me is broadcasted from AP.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * It should be silently discarded for
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * SIMPLEX interface.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_input: multicast echo\n");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_IBSS:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_AHDEMO:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (dir != IEEE80211_FC1_DIR_NODS) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_input: unknown dir 0x%x",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc dir);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_err("ieee80211_input: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "receive data, unknown opmode %u, skip\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_opmode);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Handle privacy requirements.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Discard encrypted frames when privacy off.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_input: ""WEP PRIVACY off");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_stats.is_wep_errors++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc key = ieee80211_crypto_decap(ic, mp, hdrspace);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (key == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* NB: stats+msgs handled in crypto_decap */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_stats.is_wep_errors++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh = (struct ieee80211_frame *)mp->b_rptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc key = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Next up, any fragmentation
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mp = ieee80211_defrag(ic, in, mp, hdrspace);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (mp == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* Fragment dropped or frame not complete yet */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh = NULL; /* no longer valid, catch any uses */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Next strip any MSDU crypto bits.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (key != NULL && !ieee80211_crypto_demic(ic, key, mp, 0)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_INPUT, "ieee80211_input: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "data demic error\n");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_stats.is_rx_frags++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_stats.is_rx_bytes += len;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mac_rx(ic->ic_mach, NULL, mp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (IEEE80211_FC0_TYPE_DATA);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_TYPE_MGT:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (dir != IEEE80211_FC1_DIR_NODS)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (len < sizeof (struct ieee80211_frame))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Only shared key auth frames with a challenge
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * should be encrypted, discard all others.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_input: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "%s WEP set but not permitted",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SUBTYPE_NAME(subtype));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_stats.is_wep_errors++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Discard encrypted frames when privacy off.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_input: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "mgt WEP set but PRIVACY off");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_stats.is_wep_errors++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc key = ieee80211_crypto_decap(ic, mp, hdrspace);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (key == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* NB: stats+msgs handled in crypto_decap */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out_exit_mutex;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh = (struct ieee80211_frame *)mp->b_rptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_recv_mgmt(ic, mp, in, subtype, rssi, rstamp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto out;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_TYPE_CTL:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "bad frame type 0x%x", type);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* should not come here */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcout_exit_mutex:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcout:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (mp != NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc freemsg(mp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (type);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * This function reassemble fragments.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * More fragments bit in the frame control means the packet is fragmented.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * While the sequence control field consists of 4-bit fragment number
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * field and a 12-bit sequence number field.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/* ARGSUSED */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic mblk_t *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_defrag(ieee80211com_t *ic, struct ieee80211_node *in, mblk_t *mp,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int hdrspace)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_frame *wh = (struct ieee80211_frame *)mp->b_rptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_frame *lwh;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mblk_t *mfrag;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint16_t rxseq;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t fragno;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t more_frag;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ASSERT(!IEEE80211_IS_MULTICAST(wh->i_addr1));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc more_frag = wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rxseq = LE_16(*(uint16_t *)wh->i_seq);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc fragno = rxseq & IEEE80211_SEQ_FRAG_MASK;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* Quick way out, if there's nothing to defragment */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!more_frag && fragno == 0 && in->in_rxfrag == NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (mp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Remove frag to insure it doesn't get reaped by timer.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_table == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Should never happen. If the node is orphaned (not in
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * the table) then input packets should not reach here.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Otherwise, a concurrent request that yanks the table
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * should be blocked by other interlocking and/or by first
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * shutting the driver down. Regardless, be defensive
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * here and just bail
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc freemsg(mp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (NULL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_LOCK(in->in_table);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mfrag = in->in_rxfrag;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rxfrag = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_NODE_UNLOCK(in->in_table);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Validate new fragment is in order and
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * related to the previous ones.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (mfrag != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint16_t last_rxseq;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc lwh = (struct ieee80211_frame *)mfrag->b_rptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc last_rxseq = LE_16(*(uint16_t *)lwh->i_seq);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Sequence control field contains 12-bit sequence no
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * and 4-bit fragment number. For fragemnts, the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * sequence no is not changed.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * NB: check seq # and frag together
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (rxseq != last_rxseq + 1 ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc !IEEE80211_ADDR_EQ(wh->i_addr1, lwh->i_addr1) ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc !IEEE80211_ADDR_EQ(wh->i_addr2, lwh->i_addr2)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Unrelated fragment or no space for it,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * clear current fragments.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc freemsg(mfrag);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mfrag = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (mfrag == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (fragno != 0) { /* !first fragment, discard */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc freemsg(mp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (NULL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mfrag = mp;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else { /* concatenate */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (void) adjmsg(mp, hdrspace);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc linkb(mfrag, mp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* track last seqnum and fragno */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc lwh = (struct ieee80211_frame *)mfrag->b_rptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *(uint16_t *)lwh->i_seq = *(uint16_t *)wh->i_seq;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (more_frag != 0) { /* more to come, save */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rxfragstamp = ddi_get_lbolt();
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rxfrag = mfrag;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mfrag = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (mfrag);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Install received rate set information in the node's state block.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcint
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_setup_rates(struct ieee80211_node *in, const uint8_t *rates,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc const uint8_t *xrates, int flags)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_rateset *rs = &in->in_rates;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bzero(rs, sizeof (*rs));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rs->ir_nrates = rates[1];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* skip 1 byte element ID and 1 byte length */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bcopy(rates + 2, rs->ir_rates, rs->ir_nrates);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (xrates != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t nxrates;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Tack on 11g extended supported rate element.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nxrates = xrates[1];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (rs->ir_nrates + nxrates > IEEE80211_RATE_MAXSIZE) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nxrates = IEEE80211_RATE_MAXSIZE - rs->ir_nrates;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_XRATE,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_setup_rates: %s",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "[%s] extended rate set too large;"
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc " only using %u of %u rates\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_macaddr_sprintf(in->in_macaddr),
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc nxrates, xrates[1]);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bcopy(xrates + 2, rs->ir_rates + rs->ir_nrates, nxrates);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rs->ir_nrates += nxrates;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (ieee80211_fix_rate(in, flags));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Process open-system authentication response frame and start
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * association if the authentication request is accepted.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_auth_open(ieee80211com_t *ic, struct ieee80211_frame *wh,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_node *in, uint16_t seq, uint16_t status)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK_ASSERT(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_authmode == IEEE80211_AUTH_SHARED) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "open auth: bad sta auth mode %u", in->in_authmode);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_STA) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_state != IEEE80211_S_AUTH ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc seq != IEEE80211_AUTH_OPEN_RESPONSE) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (status != 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "open auth failed (reason %d)\n", status);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != ic->ic_bss)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_fails++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* i_fc[0] - frame control's type & subtype field */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_ASSOC,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH, "ieee80211_auth_open: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "bad operating mode %u", ic->ic_opmode);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Allocate challenge text for use by shared-key authentication
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Return B_TRUE on success, B_FALST otherwise.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic boolean_t
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_alloc_challenge(struct ieee80211_node *in)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_challenge == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_challenge = kmem_alloc(IEEE80211_CHALLENGE_LEN,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc KM_NOSLEEP);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_challenge == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "[%s] shared key challenge alloc failed\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_macaddr_sprintf(in->in_macaddr));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return (in->in_challenge != NULL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Process shared-key authentication response frames. If authentication
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * succeeds, start association; otherwise, restart scan.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_auth_shared(ieee80211com_t *ic, struct ieee80211_frame *wh,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t *frm, uint8_t *efrm, struct ieee80211_node *in, uint16_t seq,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint16_t status)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t *challenge;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Pre-shared key authentication is evil; accept
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * it only if explicitly configured (it is supported
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * mainly for compatibility with clients like OS X).
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK_ASSERT(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_authmode != IEEE80211_AUTH_AUTO &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_authmode != IEEE80211_AUTH_SHARED) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH, "ieee80211_auth_shared: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "bad sta auth mode %u", in->in_authmode);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto bad;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc challenge = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (frm + 1 < efrm) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Challenge text information element
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * frm[0] - element ID
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * frm[1] - length
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * frm[2]... - challenge text
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((frm[1] + 2) > (efrm - frm)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_auth_shared: ie %d%d too long\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm[0], (frm[1] + 2) - (efrm - frm));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto bad;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (*frm == IEEE80211_ELEMID_CHALLENGE)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc challenge = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm += frm[1] + 2;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (seq) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_AUTH_SHARED_CHALLENGE:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_AUTH_SHARED_RESPONSE:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (challenge == NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_auth_shared: no challenge\n");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto bad;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (challenge[1] != IEEE80211_CHALLENGE_LEN) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_auth_shared: bad challenge len %d\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc challenge[1]);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc goto bad;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (ic->ic_opmode) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_STA:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_state != IEEE80211_S_AUTH)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (seq) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_AUTH_SHARED_PASS:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in->in_challenge != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc kmem_free(in->in_challenge,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_CHALLENGE_LEN);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_challenge = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (status != 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_DEBUG |
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_MSG_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "shared key auth failed (reason %d)\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc status);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != ic->ic_bss)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_fails++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_ASSOC,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_AUTH_SHARED_CHALLENGE:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!ieee80211_alloc_challenge(in))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bcopy(&challenge[2], in->in_challenge, challenge[1]);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SEND_MGMT(ic, in, IEEE80211_FC0_SUBTYPE_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc seq + 1);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH, "80211_auth_shared: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "shared key auth: bad seq %d", seq);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_auth_shared: bad opmode %u\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_opmode);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcbad:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_STA) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Kick the state machine. This short-circuits
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * using the mgt frame timeout to trigger the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * state transition.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_state == IEEE80211_S_AUTH) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Process a beacon/probe response frame.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * When the device is in station mode, create a node and add it
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * to the node database for a new ESS or update node info if it's
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * already there.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcstatic void
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_recv_beacon(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int subtype, int rssi, uint32_t rstamp)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_impl_t *im = ic->ic_private;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_frame *wh;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t *frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t *efrm; /* end of frame body */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_scanparams scan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh = (struct ieee80211_frame *)mp->b_rptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm = (uint8_t *)&wh[1];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc efrm = (uint8_t *)mp->b_wptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * We process beacon/probe response frames:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * o when scanning, or
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * o station mode when associated (to collect state
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * updates such as 802.11g slot time), or
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * o adhoc mode (to discover neighbors)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Frames otherwise received are discarded.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!((ic->ic_flags & IEEE80211_F_SCAN) ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (ic->ic_opmode == IEEE80211_M_STA && in->in_associd != 0) ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_opmode == IEEE80211_M_IBSS)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * beacon/probe response frame format
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [8] time stamp
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [2] beacon interval
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [2] capability information
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] ssid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] supported rates
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] country information
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] parameter set (FH/DS)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] erp information
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] extended supported rates
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] WME
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] WPA or RSN
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_LENGTH(efrm - frm, IEEE80211_BEACON_ELEM_MIN, return);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bzero(&scan, sizeof (scan));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.tstamp = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm += 8;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.bintval = (*(uint16_t *)frm);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm += 2;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.capinfo = (*(uint16_t *)frm);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm += 2;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.bchan = ieee80211_chan2ieee(ic, ic->ic_curchan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.chan = scan.bchan;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc while (frm < efrm) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* Agere element in beacon */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((*frm == IEEE80211_ELEMID_AGERE1) ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (*frm == IEEE80211_ELEMID_AGERE2)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm = efrm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1], return);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (*frm) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_SSID:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.ssid = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_RATES:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.rates = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_COUNTRY:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.country = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_FHPARMS:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_phytype == IEEE80211_T_FH) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.fhdwell = LE_16(*(uint16_t *)(frm + 2));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.fhindex = frm[6];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.phytype = IEEE80211_T_FH;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_DSPARMS:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_phytype != IEEE80211_T_FH) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.chan = frm[2];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.phytype = IEEE80211_T_DS;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_TIM:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.tim = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.timoff = frm - mp->b_rptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_IBSSPARMS:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_XRATES:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.xrates = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_ERP:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (frm[1] != 1) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ELEMID,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_recv_mgmt: ignore %s, "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "invalid ERP element; "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "length %u, expecting 1\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SUBTYPE_NAME(subtype),
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm[1]);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.erp = frm[2];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.phytype = IEEE80211_T_OFDM;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_RSN:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.wpa = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ELEMID,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_recv_mgmt: ignore %s,"
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "unhandled id %u, len %u, totallen %u",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SUBTYPE_NAME(subtype),
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *frm, frm[1],
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc mp->b_wptr - mp->b_rptr);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* frm[1] - component length */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm += IEEE80211_ELEM_LEN(frm[1]);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_ELEMENT(scan.rates, IEEE80211_RATE_MAXSIZE, return);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_ELEMENT(scan.ssid, IEEE80211_NWID_LEN, return);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ieee80211_isclr(ic->ic_chan_active, scan.chan)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_recv_mgmt: ignore %s ,"
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "invalid channel %u\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SUBTYPE_NAME(subtype), scan.chan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (scan.chan != scan.bchan &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_phytype != IEEE80211_T_FH) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Frame was received on a channel different from the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * one indicated in the DS params element id;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * silently discard it.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * NB: this can happen due to signal leakage.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * But we should take it for FH phy because
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * the rssi value should be correct even for
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * different hop pattern in FH.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ELEMID,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_recv_mgmt: ignore %s ,"
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "phytype %u channel %u marked for %u\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SUBTYPE_NAME(subtype),
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_phytype, scan.bchan, scan.chan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!(IEEE80211_BINTVAL_MIN <= scan.bintval &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc scan.bintval <= IEEE80211_BINTVAL_MAX)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_recv_mgmt: ignore %s ,"
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "bogus beacon interval %u\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SUBTYPE_NAME(subtype), scan.bintval);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * When operating in station mode, check for state updates.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Be careful to ignore beacons received while doing a
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * background scan. We consider only 11g/WMM stuff right now.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_STA &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_associd != 0 &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (!(ic->ic_flags & IEEE80211_F_SCAN) ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ADDR_EQ(wh->i_addr2, in->in_bssid))) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* record tsf of last beacon */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bcopy(scan.tstamp, in->in_tstamp.data,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc sizeof (in->in_tstamp));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /* count beacon frame for s/w bmiss handling */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc im->im_swbmiss_count++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc im->im_bmiss_count = 0;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((in->in_capinfo ^ scan.capinfo) &
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_CAPINFO_SHORT_SLOTTIME) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ASSOC,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_recv_mgmt: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "[%s] cap change: before 0x%x, now 0x%x\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_macaddr_sprintf(wh->i_addr2),
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_capinfo, scan.capinfo);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * NB: we assume short preamble doesn't
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * change dynamically
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_set_shortslottime(ic,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_curmode == IEEE80211_MODE_11A ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (scan.capinfo &
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_CAPINFO_SHORT_SLOTTIME));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_capinfo = scan.capinfo;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (scan.tim != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_tim_ie *ie;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ie = (struct ieee80211_tim_ie *)scan.tim;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_dtim_count = ie->tim_count;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_dtim_period = ie->tim_period;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_flags & IEEE80211_F_SCAN) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_add_scan(ic, &scan, wh, subtype, rssi,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rstamp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * If scanning, just pass information to the scan module.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_flags & IEEE80211_F_SCAN) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_add_scan(ic, &scan, wh, subtype, rssi, rstamp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (scan.capinfo & IEEE80211_CAPINFO_IBSS) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (!IEEE80211_ADDR_EQ(wh->i_addr2, in->in_macaddr)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Create a new entry in the neighbor table.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_add_neighbor(ic, wh, &scan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else if (in->in_capinfo == 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Update faked node created on transmit.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Note this also updates the tsf.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_init_neighbor(in, wh, &scan);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Record tsf for potential resync.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc bcopy(scan.tstamp, in->in_tstamp.data,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc sizeof (in->in_tstamp));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rssi = (uint8_t)rssi;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rstamp = rstamp;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc/*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Perform input processing for 802.11 management frames.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * It's the default ic_recv_mgmt callback function for the interface
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * softc, ic. Tipically ic_recv_mgmt is called within ieee80211_input()
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcvoid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcieee80211_recv_mgmt(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc int subtype, int rssi, uint32_t rstamp)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc{
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc struct ieee80211_frame *wh;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t *frm; /* pointer to start of the frame */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t *efrm; /* pointer to end of the frame */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t *ssid;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t *rates;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t *xrates; /* extended rates */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc boolean_t allocbs = B_FALSE;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint8_t rate;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint16_t algo; /* authentication algorithm */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint16_t seq; /* sequence no */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint16_t status;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint16_t capinfo;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc uint16_t associd; /* association ID */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh = (struct ieee80211_frame *)mp->b_rptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm = (uint8_t *)&wh[1];
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc efrm = (uint8_t *)mp->b_wptr;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (subtype) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_SUBTYPE_BEACON:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_recv_beacon(ic, mp, in, subtype, rssi, rstamp);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode == IEEE80211_M_STA ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_state != IEEE80211_S_RUN ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_IS_MULTICAST(wh->i_addr2)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * prreq frame format
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] ssid
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] supported rates
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] extended supported rates
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ssid = rates = xrates = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc while (frm < efrm) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1], goto out);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (*frm) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_SSID:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ssid = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_RATES:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rates = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_XRATES:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc xrates = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm += frm[1] + 2;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, break);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, break);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_SSID(ic->ic_bss, ssid, break);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((ic->ic_flags & IEEE80211_F_HIDESSID) && ssid[1] == 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_INPUT,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_recv_mgmt: ignore %s, "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "no ssid with ssid suppression enabled",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SUBTYPE_NAME(subtype));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == ic->ic_bss) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode != IEEE80211_M_IBSS) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_tmp_node(ic, wh->i_addr2);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc allocbs = B_TRUE;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else if (!IEEE80211_ADDR_EQ(wh->i_addr2,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_macaddr)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Cannot tell if the sender is operating
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * in ibss mode. But we need a new node to
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * send the response so blindly add them to the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * neighbor table.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh->i_addr2);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in == NULL)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ASSOC, "ieee80211_recv_mgmt: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "[%s] recv probe req\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_macaddr_sprintf(wh->i_addr2));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rssi = (uint8_t)rssi;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_rstamp = rstamp;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Adjust and check station's rate list with device's
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * supported rate. Send back response if there is at
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * least one rate or the fixed rate(if being set) is
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * supported by both station and the device
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rate = ieee80211_setup_rates(in, rates, xrates,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (rate & IEEE80211_RATE_BASIC) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_XRATE, "ieee80211_recv_mgmt"
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "%s recv'd rate set invalid",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SUBTYPE_NAME(subtype));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_SEND_MGMT(ic, in,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_LOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (allocbs) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Temporary node created just to send a
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * response, reclaim immediately.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_SUBTYPE_AUTH:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * auth frame format
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [2] algorithm
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [2] sequence
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [2] status
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv*] challenge
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_LENGTH(efrm - frm, IEEE80211_AUTH_ELEM_MIN,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc algo = (*(uint16_t *)frm);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc seq = (*(uint16_t *)(frm + 2));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc status = (*(uint16_t *)(frm + 4));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH, "ieee80211_recv_mgmt: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "[%s] recv auth frame with algorithm %d seq %d\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_macaddr_sprintf(wh->i_addr2), algo, seq);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_flags & IEEE80211_F_COUNTERM) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH | IEEE80211_MSG_CRYPTO,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ieee80211_recv_mgmt: ignore auth, %s\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "TKIP countermeasures enabled");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (algo) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_AUTH_ALG_SHARED:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_auth_shared(ic, wh, frm + 6, efrm, in,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc seq, status);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_AUTH_ALG_OPEN:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_auth_open(ic, wh, in, seq, status);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_recv_mgmt: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "ignore auth, unsupported alg %d", algo);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_opmode != IEEE80211_M_STA ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_state != IEEE80211_S_ASSOC)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * asresp frame format
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [2] capability information
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [2] status
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [2] association ID
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] supported rates
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] extended supported rates
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [tlv] WME
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_LENGTH(efrm - frm,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_ASSOC_RESP_ELEM_MIN, break);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ic->ic_bss;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc capinfo = (*(uint16_t *)frm);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm += 2;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc status = (*(uint16_t *)frm);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm += 2;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (status != 0) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ASSOC,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "assoc failed (reason %d)\n", status);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in = ieee80211_find_node(&ic->ic_scan, wh->i_addr2);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != NULL) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_fails++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_free_node(in);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc associd = (*(uint16_t *)frm);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm += 2;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rates = xrates = NULL;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc while (frm < efrm) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Do not discard frames containing proprietary Agere
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * elements 128 and 129, as the reported element length
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * is often wrong. Skip rest of the frame, since we can
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * not rely on the given element length making it
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * impossible to know where the next element starts
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if ((*frm == IEEE80211_ELEMID_AGERE1) ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (*frm == IEEE80211_ELEMID_AGERE2)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm = efrm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1], goto out);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (*frm) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_RATES:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rates = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_ELEMID_XRATES:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc xrates = frm;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc frm += frm[1] + 2;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, break);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Adjust and check AP's rate list with device's
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * supported rate. Re-start scan if no rate is or the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * fixed rate(if being set) cannot be supported by
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * either AP or the device.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc rate = ieee80211_setup_rates(in, rates, xrates,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (rate & IEEE80211_RATE_BASIC) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ASSOC,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "assoc failed (rate set mismatch)\n");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (in != ic->ic_bss)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_fails++;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_capinfo = capinfo;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_associd = associd;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_flags &= ~IEEE80211_NODE_QOS;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Configure state now that we are associated.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_curmode == IEEE80211_MODE_11A ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (in->in_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags &= ~IEEE80211_F_USEBARKER;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } else {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags |= IEEE80211_F_USEBARKER;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_set_shortslottime(ic,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_curmode == IEEE80211_MODE_11A ||
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (in->in_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * Honor ERP protection.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc *
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * NB: in_erp should zero for non-11g operation.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * check ic_curmode anyway
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_curmode == IEEE80211_MODE_11G &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc (in->in_erp & IEEE80211_ERP_USE_PROTECTION))
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags |= IEEE80211_F_USEPROT;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc else
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags &= ~IEEE80211_F_USEPROT;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ASSOC,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "assoc success: %s preamble, %s slot time%s%s\n",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "",
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc in->in_flags & IEEE80211_NODE_QOS ? ", QoS" : "");
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_RUN, subtype);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_SUBTYPE_DEAUTH:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_state == IEEE80211_S_SCAN)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * deauth frame format
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [2] reason
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_LENGTH(efrm - frm, 2, break);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc status = (*(uint16_t *)frm);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "recv deauthenticate (reason %d)\n", status);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (ic->ic_opmode) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_STA:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_AUTH,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_FC0_SUBTYPE_DISASSOC:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if (ic->ic_state != IEEE80211_S_RUN &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_state != IEEE80211_S_ASSOC &&
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ic->ic_state != IEEE80211_S_AUTH)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc /*
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * disassoc frame format
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc * [2] reason
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_VERIFY_LENGTH(efrm - frm, 2, break);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc status = (*(uint16_t *)frm);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ASSOC,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "recv disassociate (reason %d)\n", status);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc switch (ic->ic_opmode) {
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc case IEEE80211_M_STA:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_new_state(ic, IEEE80211_S_ASSOC,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc }
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc default:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_recv_mgmt: "
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc "subtype 0x%x not handled\n", subtype);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc break;
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc } /* switch subtype */
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcout:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc IEEE80211_UNLOCK(ic);
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc}