summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/ath/ath_ieee80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/io/ath/ath_ieee80211.c')
-rw-r--r--usr/src/uts/common/io/ath/ath_ieee80211.c2899
1 files changed, 0 insertions, 2899 deletions
diff --git a/usr/src/uts/common/io/ath/ath_ieee80211.c b/usr/src/uts/common/io/ath/ath_ieee80211.c
deleted file mode 100644
index 29c0c25fd2..0000000000
--- a/usr/src/uts/common/io/ath/ath_ieee80211.c
+++ /dev/null
@@ -1,2899 +0,0 @@
-/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
- * redistribution must be conditioned upon including a substantially
- * similar Disclaimer requirement for further binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGES.
- *
- */
-
-/*
- * IEEE 802.11 generic handler
- *
- * This code is derived from NetBSD code; their copyright notice follows.
- */
-
-/*
- * Copyright (c) 2001 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Atsushi Onoe.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/signal.h>
-#include <sys/stream.h>
-#include <sys/termio.h>
-#include <sys/errno.h>
-#include <sys/file.h>
-#include <sys/cmn_err.h>
-#include <sys/stropts.h>
-#include <sys/strsubr.h>
-#include <sys/strtty.h>
-#include <sys/kbio.h>
-#include <sys/cred.h>
-#include <sys/stat.h>
-#include <sys/consdev.h>
-#include <sys/kmem.h>
-#include <sys/modctl.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/pci.h>
-#include <sys/errno.h>
-#include <sys/gld.h>
-#include <sys/dlpi.h>
-#include <sys/ethernet.h>
-#include <sys/byteorder.h>
-#include <sys/proc.h>
-#include <sys/note.h>
-#include <sys/strsun.h>
-#include <sys/list.h>
-#include <sys/byteorder.h>
-#include <inet/common.h>
-#include <inet/nd.h>
-#include <inet/mi.h>
-#include <inet/wifi_ioctl.h>
-#include "ath_ieee80211.h"
-#include "ath_impl.h"
-
-#define list_empty(a) ((a)->list_head.list_next == &(a)->list_head)
-
-static const char *ieee80211_mgt_subtype_name[] = {
- "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp",
- "probe_req", "probe_resp", "reserved#6", "reserved#7",
- "beacon", "atim", "disassoc", "auth",
- "deauth", "reserved#13", "reserved#14", "reserved#15"
-};
-
-extern pri_t minclsyspri;
-
-static void
-ieee80211_unref_node(struct ieee80211_node **in)
-{
- *in = NULL;
-}
-
-static uint8_t
-ieee80211_get_rssi(struct ieee80211_node *in)
-{
- /* no recent samples, use last known value */
- return (in->in_recv_hist[in->in_hist_cur].irh_rssi);
-}
-
-static void
-ieee80211_reset_recvhist(struct ieee80211_node *in)
-{
- int i;
-
- for (i = 0; i < IEEE80211_RECV_HIST_LEN; ++i) {
- in->in_recv_hist[i].irh_jiffies = IEEE80211_JIFFIES_NONE;
- in->in_recv_hist[i].irh_rssi = 0;
- in->in_recv_hist[i].irh_rstamp = 0;
- in->in_recv_hist[i].irh_rantenna = 0;
- }
- in->in_hist_cur = IEEE80211_RECV_HIST_LEN - 1;
-}
-
-
-static void
-ieee80211_add_recvhist(struct ieee80211_node *in, uint8_t rssi,
- uint32_t rstamp, uint8_t rantenna)
-{
- if (++in->in_hist_cur >= IEEE80211_RECV_HIST_LEN)
- in->in_hist_cur = 0;
- in->in_recv_hist[in->in_hist_cur].irh_rssi = rssi;
- in->in_recv_hist[in->in_hist_cur].irh_rstamp = rstamp;
- in->in_recv_hist[in->in_hist_cur].irh_rantenna = rantenna;
-}
-
-/*
- * Convert MHz frequency to IEEE channel number.
- */
-uint32_t
-ieee80211_mhz2ieee(uint32_t freq, uint32_t flags)
-{
- if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */
- if (freq == 2484)
- return (14);
- if (freq < 2484)
- return ((freq - 2407) / 5);
- else
- return (15 + ((freq - 2512) / 20));
- } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */
- return ((freq - 5000) / 5);
- } else { /* either, guess */
- if (freq == 2484)
- return (14);
- if (freq < 2484)
- return ((freq - 2407) / 5);
- if (freq < 5000)
- return (15 + ((freq - 2512) / 20));
- return ((freq - 5000) / 5);
- }
-}
-
-/*
- * Convert channel to IEEE channel number.
- */
-uint32_t
-ieee80211_chan2ieee(ieee80211com_t *isc, struct ieee80211channel *ch)
-{
- if (isc->isc_channels <= ch &&
- ch <= &isc->isc_channels[IEEE80211_CHAN_MAX])
- return (ch - isc->isc_channels);
- else if (ch == IEEE80211_CHAN_ANYC)
- return (IEEE80211_CHAN_ANY);
- else {
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_chan2ieee(): "
- "invalid channel freq %u flags %x\n",
- ch->ich_freq, ch->ich_flags));
- return (0);
- }
-}
-
-/*
- * Convert IEEE channel number to MHz frequency.
- */
-uint32_t
-ieee80211_ieee2mhz(uint32_t chan, uint32_t flags)
-{
- if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */
- if (chan == 14)
- return (2484);
- if (chan < 14)
- return (2407 + chan * 5);
- else
- return (2512 + ((chan-15) * 20));
- } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */
- return (5000 + (chan * 5));
- } else { /* either, guess */
- if (chan == 14)
- return (2484);
- if (chan < 14) /* 0-13 */
- return (2407 + chan * 5);
- if (chan < 27) /* 15-26 */
- return (2512 + ((chan-15) * 20));
- return (5000 + (chan * 5));
- }
-}
-
-static void
-ieee80211_free_node(ieee80211com_t *isc, struct ieee80211_node *in)
-{
- int32_t i, done;
- struct ieee80211_node *in1;
-
- /* remove in from list of isc->isc_in_list */
- list_remove(&isc->isc_in_list, in);
-
- /* remove in from list of isc->isc_inhash_list */
- done = 0;
- for (i = 0; i < IEEE80211_NODE_HASHSIZE; i++) {
- in1 = list_head(&isc->isc_inhash_list[i]);
- while (in1 != NULL) {
- if (in1 == in) {
- list_remove(&isc->isc_inhash_list[i], in);
- done = 1;
- break;
- }
- in1 = list_next(&isc->isc_inhash_list[i], in1);
- }
- if (done)
- break;
- }
-
- if (list_empty(&isc->isc_in_list))
- isc->isc_inact_timeout = 0;
- if (isc->isc_node_free != NULL)
- (*isc->isc_node_free)(isc, in);
-}
-
-/*
- * This function is only running in software interrupt thread,
- * and it will probably call back to LLD by isc_mgmt_send() or isc_new_state(),
- * to avoid recursive mutex entry, we must make sure that
- * the callers have release all LLD mutexs before calling ieee80211_input().
- */
-void
-ieee80211_input(ieee80211com_t *isc, mblk_t *mp,
- int32_t rssi, uint32_t rstamp, uint32_t rantenna)
-{
- struct ieee80211_node *in;
- gld_mac_info_t *gld_p = isc->isc_dev;
- struct ieee80211_frame *wh;
- void (*rh)(ieee80211com_t *, mblk_t *, int32_t, uint32_t, uint32_t);
- uint8_t dir, subtype;
- uint8_t *bssid;
- uint16_t rxseq;
-
- wh = (struct ieee80211_frame *)mp->b_rptr;
- if ((wh->ifrm_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
- IEEE80211_FC0_VERSION_0) {
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_input(): "
- "discard pkt with wrong version"));
- goto out;
- }
-
- dir = wh->ifrm_fc[1] & IEEE80211_FC1_DIR_MASK;
-
- mutex_enter(&isc->isc_genlock);
- if (isc->isc_state != IEEE80211_S_SCAN) {
- switch (isc->isc_opmode) {
- case IEEE80211_M_STA:
- in = isc->isc_bss;
- if (!IEEE80211_ADDR_EQ(wh->ifrm_addr2, in->in_bssid))
- goto out_with_mutex;
- break;
- case IEEE80211_M_IBSS:
- case IEEE80211_M_AHDEMO:
- case IEEE80211_M_HOSTAP:
- if (dir == IEEE80211_FC1_DIR_NODS)
- bssid = wh->ifrm_addr3;
- else
- bssid = wh->ifrm_addr1;
- if (!IEEE80211_ADDR_EQ(bssid, isc->isc_bss->in_bssid) &&
- !IEEE80211_ADDR_EQ(bssid,
- gld_p->gldm_broadcast_addr)) {
- /* not interested in */
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_input(): other bss %s\n",
- ieee80211_ether_sprintf(wh->ifrm_addr3)));
- goto out_with_mutex;
- }
- in = ieee80211_find_node(isc, wh->ifrm_addr2);
- if (in == NULL) {
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_input(): unknown src %s\n",
- ieee80211_ether_sprintf(wh->ifrm_addr2)));
- /*
- * NB: Node allocation is handled in the
- * management handling routines. Just fake
- * up a reference to the hosts's node to do
- * the stuff below.
- */
- in = isc->isc_bss;
- }
- break;
- default:
- /* catch bad values */
- break;
- }
- ieee80211_add_recvhist(in, rssi, rstamp, rantenna);
- rxseq = in->in_rxseq;
- in->in_rxseq = LE_16(*(uint16_t *)wh->ifrm_seq)
- >> IEEE80211_SEQ_SEQ_SHIFT;
- /* fragment */
- if ((wh->ifrm_fc[1] & IEEE80211_FC1_RETRY) &&
- rxseq == in->in_rxseq) {
- /* duplicate, silently discarded */
- goto out_with_mutex;
- }
- in->in_inact = 0;
- }
-
- switch (wh->ifrm_fc[0] & IEEE80211_FC0_TYPE_MASK) {
- case IEEE80211_FC0_TYPE_DATA:
- switch (isc->isc_opmode) {
- case IEEE80211_M_STA:
- if (dir != IEEE80211_FC1_DIR_FROMDS) {
- ATH_DEBUG((ATH_DBG_80211, "ath: ",
- "ieee80211_input(): discard frame "
- "with invalid direction %x\n", dir));
- goto out_with_mutex;
- }
- if (IEEE80211_IS_MULTICAST(wh->ifrm_addr1) &&
- IEEE80211_ADDR_EQ(wh->ifrm_addr3,
- gld_p->gldm_vendor_addr)) {
- /*
- * In IEEE802.11 network, multicast packet
- * sent from me is broadcasted from AP.
- * It should be silently discarded for
- * SIMPLEX interface.
- */
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_input(): "
- "discard multicast echo\n"));
- goto out_with_mutex;
- }
- break;
- case IEEE80211_M_IBSS:
- case IEEE80211_M_AHDEMO:
- if (dir != IEEE80211_FC1_DIR_NODS)
- goto out_with_mutex;
- break;
- case IEEE80211_M_HOSTAP:
- /* need more work to support HOSTAP */
- break;
- }
-
- mutex_exit(&isc->isc_genlock);
- /* copy to listener after decrypt */
- mp = ieee80211_decap(mp);
- if (mp == NULL) {
- ATH_DEBUG((ATH_DBG_80211, "ath: ",
- "ieee80211_input(): decapsulation failed\n"));
- goto out;
- }
- gld_recv(gld_p, mp);
- return;
-
- case IEEE80211_FC0_TYPE_MGT:
- if (dir != IEEE80211_FC1_DIR_NODS)
- goto out_with_mutex;
- if (isc->isc_opmode == IEEE80211_M_AHDEMO)
- goto out_with_mutex;
- subtype = wh->ifrm_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
-
- /* drop uninteresting frames */
- if (isc->isc_state == IEEE80211_S_SCAN) {
- if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
- subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
- goto out_with_mutex;
- } else {
- if (isc->isc_opmode != IEEE80211_M_IBSS &&
- subtype == IEEE80211_FC0_SUBTYPE_BEACON)
- goto out_with_mutex;
- }
-
- rh = isc->isc_recv_mgmt[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT];
- if (rh != NULL)
- (*rh)(isc, mp, rssi, rstamp, rantenna);
- goto out_with_mutex;
-
- case IEEE80211_FC0_TYPE_CTL:
- default:
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_input(): "
- "bad type %x\n", wh->ifrm_fc[0]));
- break;
- }
-out_with_mutex:
- mutex_exit(&isc->isc_genlock);
-out:
- if (mp != NULL)
- freemsg(mp); /* free the buffer alloced in ath_rx_handler */
-}
-
-static void
-ieee80211_free_allnodes(ieee80211com_t *isc)
-{
- struct ieee80211_node *in;
-
- in = list_head(&isc->isc_in_list);
- while (in != NULL) {
- ieee80211_free_node(isc, in);
- in = list_head(&isc->isc_in_list);
- }
-}
-
-/*
- * Begin an active scan.
- */
-static void
-ieee80211_begin_scan(ieee80211com_t *isc, struct ieee80211_node *in)
-{
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_begin_scan(): begin %s scan\n",
- isc->isc_opmode != IEEE80211_M_HOSTAP ? "active" : "passive"));
-
- /*
- * Initialize the active channel set based on the set
- * of available channels and the current PHY mode.
- */
- bcopy(isc->isc_chan_active, isc->isc_chan_scan,
- sizeof (isc->isc_chan_active));
-
- /*
- * Flush any previously seen AP's. Note that this
- * assumes we don't act as both an AP and a station,
- * otherwise we'll potentially flush state of stations
- * associated with us.
- */
- ieee80211_free_allnodes(isc);
-
- clrbit(isc->isc_chan_scan, ieee80211_chan2ieee(isc, in->in_chan));
- if (isc->isc_opmode != IEEE80211_M_HOSTAP) {
- isc->isc_flags |= IEEE80211_F_ASCAN;
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0);
- }
-}
-
-static void
-ieee80211_create_ibss(ieee80211com_t *isc, struct ieee80211channel *chan)
-{
- struct ieee80211_node *in;
-
- in = isc->isc_bss;
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_create_ibss(): creating ibss\n"));
- isc->isc_flags |= IEEE80211_F_SIBSS;
- in->in_chan = chan;
- in->in_rates = isc->isc_sup_rates[
- ieee80211_chan2mode(isc, in->in_chan)];
- IEEE80211_ADDR_COPY(in->in_macaddr, isc->isc_macaddr);
- IEEE80211_ADDR_COPY(in->in_bssid, isc->isc_macaddr);
-
- if (isc->isc_opmode == IEEE80211_M_IBSS)
- in->in_bssid[0] |= 0x02; /* local bit for IBSS */
- in->in_esslen = isc->isc_des_esslen;
- bcopy(isc->isc_des_essid, in->in_essid, in->in_esslen);
- ieee80211_reset_recvhist(in);
- bzero(in->in_tstamp, sizeof (in->in_tstamp));
- in->in_intval = isc->isc_lintval;
- in->in_capinfo = IEEE80211_CAPINFO_IBSS;
- if (isc->isc_flags & IEEE80211_F_WEPON)
- in->in_capinfo |= IEEE80211_CAPINFO_PRIVACY;
- if (isc->isc_phytype == IEEE80211_T_FH) {
- in->in_fhdwell = 200;
- in->in_fhindex = 1;
- }
- (void) _ieee80211_new_state(isc, IEEE80211_S_RUN, -1);
-}
-
-
-/*
- * The difference between _ieee80211_new_state() and ieee80211_new_state()
- * is the former asserts isc_genlock is already held.
- * _ieee80211_new_state() is called from Multi-func thread and GLD thread,
- * because ic_genlock is already owned at its entry in those 2 types of thread.
- * ieee80211_new_state() is just for software interrupt thread in LLD.
- *
- * Because of the reason to avoid recursive mutex entry, the caller can't hold
- * any other LLD mutexs before calling ieee80211_new_state().
- */
-int
-_ieee80211_new_state(ieee80211com_t *isc, enum ieee80211_state nstate,
- int32_t mgt)
-{
- gld_mac_info_t *gld_p = isc->isc_dev;
- struct ieee80211_node *in;
- int error, ostate;
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- ostate = isc->isc_state;
- if (isc->isc_new_state) {
- error = (*isc->isc_new_state)(isc, nstate);
- if (error == EINPROGRESS)
- return (0);
- if (error != 0)
- return (error);
- }
-
- isc->isc_state = nstate;
- in = isc->isc_bss;
-
- /* state transition */
- switch (nstate) {
- case IEEE80211_S_INIT:
- switch (ostate) {
- case IEEE80211_S_INIT:
- break;
- case IEEE80211_S_RUN:
- switch (isc->isc_opmode) {
- case IEEE80211_M_STA:
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_DISASSOC,
- IEEE80211_REASON_ASSOC_LEAVE);
- break;
- default:
- break;
- }
- case IEEE80211_S_ASSOC:
- switch (isc->isc_opmode) {
- case IEEE80211_M_STA:
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_AUTH_LEAVE);
- break;
- default:
- break;
- }
- case IEEE80211_S_AUTH:
- case IEEE80211_S_SCAN:
- break;
- }
- isc->isc_mgt_timeout = 0;
- isc->isc_inact_timeout = 0;
- break;
- case IEEE80211_S_SCAN:
- isc->isc_flags &= ~IEEE80211_F_SIBSS;
- /* initialize bss for probe request */
- IEEE80211_ADDR_COPY(in->in_macaddr, gld_p->gldm_broadcast_addr);
- IEEE80211_ADDR_COPY(in->in_bssid, gld_p->gldm_broadcast_addr);
- in->in_rates = isc->isc_sup_rates[
- ieee80211_chan2mode(isc, in->in_chan)];
- in->in_associd = 0;
- ieee80211_reset_recvhist(in);
- switch (ostate) {
- case IEEE80211_S_INIT:
- if ((isc->isc_opmode == IEEE80211_M_HOSTAP ||
- isc->isc_opmode == IEEE80211_M_IBSS) &&
- isc->isc_des_chan != IEEE80211_CHAN_ANYC) {
- /*
- * AP operation and we already have a channel;
- * bypass the scan and startup immediately.
- * Same applies to ad-hoc mode.
- */
- ieee80211_create_ibss(isc, isc->isc_des_chan);
- } else {
- ieee80211_begin_scan(isc, in);
- }
- break;
- case IEEE80211_S_SCAN:
- /* scan next */
- if (isc->isc_flags & IEEE80211_F_ASCAN) {
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0);
- }
- break;
- case IEEE80211_S_RUN:
- /* beacon miss */
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "_ieee80211_new_state(): no recent beacons"
- " from %s; rescanning\n",
- ieee80211_ether_sprintf(isc->isc_bss->in_bssid)));
- ieee80211_free_allnodes(isc);
- break;
- case IEEE80211_S_AUTH:
- case IEEE80211_S_ASSOC:
- /* timeout, restart scan */
- in = ieee80211_find_node(isc, isc->isc_bss->in_macaddr);
- if (in != NULL) {
- in->in_fails++;
- }
- ieee80211_begin_scan(isc, isc->isc_bss);
- break;
- default:
- break;
- }
- break;
- case IEEE80211_S_AUTH:
- switch (ostate) {
- case IEEE80211_S_INIT:
- ATH_DEBUG((ATH_DBG_80211, "ath(): "
- "_ieee80211_new_state(): invalid transition\n"));
- break;
- case IEEE80211_S_SCAN:
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_AUTH, 1);
- break;
- case IEEE80211_S_AUTH:
- case IEEE80211_S_ASSOC:
- switch (mgt) {
- case IEEE80211_FC0_SUBTYPE_AUTH:
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_AUTH, 2);
- break;
- case IEEE80211_FC0_SUBTYPE_DEAUTH:
- /* ignore and retry scan on timeout */
- break;
- }
- break;
- case IEEE80211_S_RUN:
- switch (mgt) {
- case IEEE80211_FC0_SUBTYPE_AUTH:
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_AUTH, 2);
- isc->isc_state = ostate; /* stay RUN */
- break;
- case IEEE80211_FC0_SUBTYPE_DEAUTH:
- /* try to reauth */
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_AUTH, 1);
- break;
- }
- break;
- }
- break;
- case IEEE80211_S_ASSOC:
- switch (ostate) {
- case IEEE80211_S_INIT:
- case IEEE80211_S_SCAN:
- case IEEE80211_S_ASSOC:
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "_ieee80211_new_state(): invalid transition\n"));
- break;
- case IEEE80211_S_AUTH:
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
- break;
- case IEEE80211_S_RUN:
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1);
- break;
- }
- break;
- case IEEE80211_S_RUN:
- switch (ostate) {
- case IEEE80211_S_INIT:
- case IEEE80211_S_AUTH:
- case IEEE80211_S_RUN:
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "_ieee80211_new_state(): invalid transition\n"));
- break;
- case IEEE80211_S_SCAN: /* adhoc/hostap mode */
- case IEEE80211_S_ASSOC: /* infra mode */
- if (isc->isc_opmode == IEEE80211_M_STA)
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "_ieee80211_new_state(): "
- "associated with %s\n",
- ieee80211_ether_sprintf(in->in_bssid)));
- else
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "_ieee80211_new_state(): "
- "asynchronized with %s\n",
- ieee80211_ether_sprintf(in->in_bssid)));
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "_ieee80211_new_state(): "
- "essid %s, channel %d, start %uMb\n",
- ieee80211_essid_sprintf(in->in_essid,
- in->in_esslen),
- ieee80211_chan2ieee(isc, in->in_chan),
- IEEE80211_RATE2MBS(in->in_rates.ir_rates[
- in->in_txrate])));
- isc->isc_mgt_timeout = 0;
- break;
- }
- break;
- }
- return (0);
-}
-
-int
-ieee80211_new_state(ieee80211com_t *isc, enum ieee80211_state nstate,
- int32_t mgt)
-{
- int result;
-
- mutex_enter(&isc->isc_genlock);
- result = _ieee80211_new_state(isc, nstate, mgt);
- mutex_exit(&isc->isc_genlock);
-
- return (result);
-}
-
-static void
-ieee80211_timeout_nodes(ieee80211com_t *isc)
-{
- struct ieee80211_node *in, *nextbs;
-
- for (in = list_head(&isc->isc_in_list); in != NULL; ) {
- if (++in->in_inact <= IEEE80211_INACT_MAX) {
- in = list_next(&isc->isc_in_list, in);
- continue;
- }
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "station %s timed out due to inactivity"
- " (%u secs)\n", ieee80211_ether_sprintf(in->in_macaddr),
- in->in_inact));
- nextbs = list_next(&isc->isc_in_list, in);
- IEEE80211_SEND_MGMT(isc, in,
- IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_AUTH_EXPIRE);
- ieee80211_free_node(isc, in);
- in = nextbs;
- }
- if (!list_empty(&isc->isc_in_list))
- isc->isc_inact_timeout = IEEE80211_INACT_WAIT;
-}
-
-int
-ieee80211_mgmt_output(ieee80211com_t *isc, struct ieee80211_node *in,
- mblk_t *mp, int type)
-{
- struct ieee80211_frame *wh;
-
- ASSERT(mutex_owned(&isc->isc_genlock));
- ASSERT(in != NULL);
-
- in->in_inact = 0;
- mp->b_rptr -= sizeof (struct ieee80211_frame);
- wh = (struct ieee80211_frame *)mp->b_rptr;
- wh->ifrm_fc[0] = IEEE80211_FC0_VERSION_0 |
- IEEE80211_FC0_TYPE_MGT | type;
- wh->ifrm_fc[1] = IEEE80211_FC1_DIR_NODS;
- *(uint16_t *)wh->ifrm_dur = 0;
- *(uint16_t *)wh->ifrm_seq =
- LE_16(in->in_txseq << IEEE80211_SEQ_SEQ_SHIFT);
- in->in_txseq++;
- IEEE80211_ADDR_COPY(wh->ifrm_addr1, in->in_macaddr);
- IEEE80211_ADDR_COPY(wh->ifrm_addr2, isc->isc_macaddr);
- IEEE80211_ADDR_COPY(wh->ifrm_addr3, in->in_bssid);
-
- (void) (*isc->isc_mgmt_send)(isc, mp);
- return (0);
-}
-
-mblk_t *
-ieee80211_fill_header(ieee80211com_t *isc, mblk_t *mp_gld,
- int32_t wep_txkey, struct ieee80211_node *in)
-{
- struct ieee80211_frame *wh;
- struct ieee80211_llc *llc;
- struct ether_header *eh;
- mblk_t *mp_header;
- uint32_t iv;
- uint8_t *ivp;
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- /*
- * Alloc a new mblk struct for the whole IEEE80211 header.
- */
- if ((mp_header = allocb(HEADERSPACE, BPRI_MED)) == NULL) {
- ath_problem("ath: ieee80211_encap(): can't alloc mblk!\n");
- return (NULL);
- }
- mp_header->b_wptr = mp_header->b_rptr +
- sizeof (struct ieee80211_frame);
-
- eh = (struct ether_header *)mp_gld->b_rptr;
-
- /*
- * Fill 802.11 field.
- */
- wh = (struct ieee80211_frame *)mp_header->b_rptr;
- wh->ifrm_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
- *(uint16_t *)wh->ifrm_dur = 0;
- *(uint16_t *)wh->ifrm_seq =
- LE_16(in->in_txseq << IEEE80211_SEQ_SEQ_SHIFT);
- in->in_txseq++;
- switch (isc->isc_opmode) {
- case IEEE80211_M_STA:
- wh->ifrm_fc[1] = IEEE80211_FC1_DIR_TODS;
- IEEE80211_ADDR_COPY(wh->ifrm_addr1, in->in_bssid);
- IEEE80211_ADDR_COPY(wh->ifrm_addr2,
- eh->ether_shost.ether_addr_octet);
- IEEE80211_ADDR_COPY(wh->ifrm_addr3,
- eh->ether_dhost.ether_addr_octet);
- break;
- case IEEE80211_M_IBSS:
- case IEEE80211_M_AHDEMO:
- wh->ifrm_fc[1] = IEEE80211_FC1_DIR_NODS;
- IEEE80211_ADDR_COPY(wh->ifrm_addr1,
- eh->ether_dhost.ether_addr_octet);
- IEEE80211_ADDR_COPY(wh->ifrm_addr2,
- eh->ether_shost.ether_addr_octet);
- IEEE80211_ADDR_COPY(wh->ifrm_addr3, in->in_bssid);
- break;
- case IEEE80211_M_HOSTAP:
- wh->ifrm_fc[1] = IEEE80211_FC1_DIR_FROMDS;
- IEEE80211_ADDR_COPY(wh->ifrm_addr1,
- eh->ether_dhost.ether_addr_octet);
- IEEE80211_ADDR_COPY(wh->ifrm_addr2, in->in_bssid);
- IEEE80211_ADDR_COPY(wh->ifrm_addr3,
- eh->ether_shost.ether_addr_octet);
- break;
- }
-
- if (isc->isc_flags & IEEE80211_F_WEPON) {
- wh->ifrm_fc[1] |= IEEE80211_FC1_WEP;
- ivp = mp_header->b_rptr + sizeof (struct ieee80211_frame);
- /*
- * IV must not duplicate during the lifetime of the key.
- * But no mechanism to renew keys is defined in IEEE 802.11
- * WEP. And IV may be duplicated between other stations
- * because of the session key itself is shared.
- * So we use pseudo random IV for now, though it is not the
- * right way.
- */
- iv = isc->isc_iv;
- /*
- * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
- * (B, 255, N) with 3 <= B < 8
- */
- if ((iv & 0xff00) == 0xff00) {
- int B = (iv & 0xff0000) >> 16;
- if (3 <= B && B < 16)
- iv = (B+1) << 16;
- }
- isc->isc_iv = iv + 1;
-
-#ifdef ATH_HOST_BIG_ENDIAN
- ivp[0] = iv >> 0;
- ivp[1] = iv >> 8;
- ivp[2] = iv >> 16;
-#else
- ivp[2] = iv >> 0;
- ivp[1] = iv >> 8;
- ivp[0] = iv >> 16;
-#endif /* ATH_HOST_BIG_ENDIAN */
-
- /* Key ID and pad */
- ivp[IEEE80211_WEP_IVLEN] = wep_txkey << 6;
- /*
- * The ICV length must be included into hdrlen and pktlen.
- */
- mp_header->b_wptr +=
- IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
- }
-
- /*
- * CRC are added by H/W, not encaped by driver,
- * but we must count it in pkt length.
- */
-
- /*
- * fill LLC and SNAP fields.
- */
- llc = (struct ieee80211_llc *)mp_header->b_wptr;
- llc->illc_dsap = LLC_DSAP;
- llc->illc_ssap = LLC_SSAP;
- llc->illc_control = LLC_CONTROL;
- llc->illc_oc[0] = SNAP_OC0;
- llc->illc_oc[1] = SNAP_OC1;
- llc->illc_oc[2] = SNAP_OC2;
- llc->illc_ether_type = eh->ether_type;
- mp_header->b_wptr += sizeof (struct ieee80211_llc);
-
- return (mp_header);
-}
-
-mblk_t *
-ieee80211_decap(mblk_t *mp)
-{
- struct ether_header *eh;
- struct ieee80211_frame wh;
- struct ieee80211_llc *llc;
-
- if ((mp->b_wptr - mp->b_rptr) < (sizeof (wh) + sizeof (*llc))) {
- freemsg(mp);
- return (NULL);
- }
-
- bcopy(mp->b_rptr, &wh, sizeof (struct ieee80211_frame));
- mp->b_rptr += sizeof (struct ieee80211_frame);
- llc = (struct ieee80211_llc *)mp->b_rptr;
-
- if (llc->illc_dsap == LLC_DSAP && llc->illc_ssap == LLC_SSAP &&
- llc->illc_control == LLC_CONTROL && llc->illc_oc[0] == SNAP_OC0 &&
- llc->illc_oc[1] == SNAP_OC1 && llc->illc_oc[2] == SNAP_OC2) {
- mp->b_rptr += sizeof (struct ieee80211_llc);
- llc = NULL;
- }
- /*
- * we are sure that the size of ieee80211_frame plus llc is
- * larger than the size of ether_header,
- * so there has enough space to encap ether_header in this mblk.
- */
- mp->b_rptr -= sizeof (struct ether_header);
- eh = (struct ether_header *)mp->b_rptr;
- switch (wh.ifrm_fc[1] & IEEE80211_FC1_DIR_MASK) {
- case IEEE80211_FC1_DIR_NODS:
- IEEE80211_ADDR_COPY(eh->ether_dhost.ether_addr_octet,
- wh.ifrm_addr1);
- IEEE80211_ADDR_COPY(eh->ether_shost.ether_addr_octet,
- wh.ifrm_addr2);
- break;
- case IEEE80211_FC1_DIR_TODS:
- IEEE80211_ADDR_COPY(eh->ether_dhost.ether_addr_octet,
- wh.ifrm_addr3);
- IEEE80211_ADDR_COPY(eh->ether_shost.ether_addr_octet,
- wh.ifrm_addr2);
- break;
- case IEEE80211_FC1_DIR_FROMDS:
- IEEE80211_ADDR_COPY(eh->ether_dhost.ether_addr_octet,
- wh.ifrm_addr1);
- IEEE80211_ADDR_COPY(eh->ether_shost.ether_addr_octet,
- wh.ifrm_addr3);
- break;
- case IEEE80211_FC1_DIR_DSTODS:
- /* not yet supported */
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_decap(): DS to DS\n"));
- freemsg(mp);
- return (NULL);
- }
-
- if (llc != NULL)
- eh->ether_type = htons(mp->b_wptr - mp->b_rptr - sizeof (*eh));
-
- return (mp);
-}
-
-/*
- * This function doesn't need mutex protection.
- */
-void
-ieee80211_dump_pkt(uint8_t *buf, int32_t len, int32_t rate, int32_t rssi)
-{
- struct ieee80211_frame *wh;
- int32_t i;
- int8_t buf1[100], buf2[25];
-
- bzero(buf1, sizeof (buf1));
- bzero(buf2, sizeof (buf2));
- wh = (struct ieee80211_frame *)buf;
- switch (wh->ifrm_fc[1] & IEEE80211_FC1_DIR_MASK) {
- case IEEE80211_FC1_DIR_NODS:
- (void) sprintf(buf2, "NODS %s",
- ieee80211_ether_sprintf(wh->ifrm_addr2));
- (void) strcat(buf1, buf2);
- (void) sprintf(buf2, "->%s",
- ieee80211_ether_sprintf(wh->ifrm_addr1));
- (void) strcat(buf1, buf2);
- (void) sprintf(buf2, "(%s)",
- ieee80211_ether_sprintf(wh->ifrm_addr3));
- (void) strcat(buf1, buf2);
- break;
- case IEEE80211_FC1_DIR_TODS:
- (void) sprintf(buf2, "TODS %s",
- ieee80211_ether_sprintf(wh->ifrm_addr2));
- (void) strcat(buf1, buf2);
- (void) sprintf(buf2, "->%s",
- ieee80211_ether_sprintf(wh->ifrm_addr3));
- (void) strcat(buf1, buf2);
- (void) sprintf(buf2, "(%s)",
- ieee80211_ether_sprintf(wh->ifrm_addr1));
- (void) strcat(buf1, buf2);
- break;
- case IEEE80211_FC1_DIR_FROMDS:
- (void) sprintf(buf2, "FRDS %s",
- ieee80211_ether_sprintf(wh->ifrm_addr3));
- (void) strcat(buf1, buf2);
- (void) sprintf(buf2, "->%s",
- ieee80211_ether_sprintf(wh->ifrm_addr1));
- (void) strcat(buf1, buf2);
- (void) sprintf(buf2, "(%s)",
- ieee80211_ether_sprintf(wh->ifrm_addr2));
- (void) strcat(buf1, buf2);
- break;
- case IEEE80211_FC1_DIR_DSTODS:
- (void) sprintf(buf2, "DSDS %s",
- ieee80211_ether_sprintf((uint8_t *)&wh[1]));
- (void) strcat(buf1, buf2);
- (void) sprintf(buf2, "->%s ",
- ieee80211_ether_sprintf(wh->ifrm_addr3));
- (void) strcat(buf1, buf2);
- (void) sprintf(buf2, "%s",
- ieee80211_ether_sprintf(wh->ifrm_addr2));
- (void) strcat(buf1, buf2);
- (void) sprintf(buf2, "->%s",
- ieee80211_ether_sprintf(wh->ifrm_addr1));
- (void) strcat(buf1, buf2);
- break;
- }
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_dump_pkt(): %s", buf1));
- bzero(buf1, sizeof (buf1));
-
- switch (wh->ifrm_fc[0] & IEEE80211_FC0_TYPE_MASK) {
- case IEEE80211_FC0_TYPE_DATA:
- (void) sprintf(buf2, "data");
- break;
- case IEEE80211_FC0_TYPE_MGT:
- (void) sprintf(buf2, "%s",
- ieee80211_mgt_subtype_name[
- (wh->ifrm_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
- >> IEEE80211_FC0_SUBTYPE_SHIFT]);
- break;
- default:
- (void) sprintf(buf2, "type#%d",
- wh->ifrm_fc[0] & IEEE80211_FC0_TYPE_MASK);
- break;
- }
- (void) strcat(buf1, buf2);
- if (wh->ifrm_fc[1] & IEEE80211_FC1_WEP) {
- (void) sprintf(buf2, " WEP");
- (void) strcat(buf1, buf2);
- }
- if (rate >= 0) {
- (void) sprintf(buf2, " %dM", rate / 2);
- (void) strcat(buf1, buf2);
- }
- if (rssi >= 0) {
- (void) sprintf(buf2, " +%d", rssi);
- (void) strcat(buf1, buf2);
- }
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_dump_pkt(): %s", buf1));
- bzero(buf1, sizeof (buf1));
-
- if (len > 0) {
- for (i = 0; i < (len > 40 ? 40 : len); i++) {
- if ((i & 0x03) == 0)
- (void) strcat(buf1, " ");
- (void) sprintf(buf2, "%02x", buf[i]);
- (void) strcat(buf1, buf2);
- }
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_dump_pkt(): %s",
- buf1));
- }
-}
-
-/*
- * Mark the basic rates for the 11g rate table based on the
- * operating mode. For real 11g we mark all the 11b rates
- * and 6, 12, and 24 OFDM. For 11b compatibility we mark only
- * 11b rates. There's also a pseudo 11a-mode used to mark only
- * the basic OFDM rates.
- */
-static void
-ieee80211_set11gbasicrates(struct ieee80211_rateset *rs,
- enum ieee80211_phymode mode)
-{
- static const struct ieee80211_rateset basic[] = {
- { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */
- { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11B */
- { 7, { 2, 4, 11, 22, 12, 24, 48 } }, /* IEEE80211_MODE_11G */
- { 0 }, /* IEEE80211_MODE_TURBO */
- };
- int32_t i, j;
-
- for (i = 0; i < rs->ir_nrates; i++) {
- rs->ir_rates[i] &= IEEE80211_RATE_VAL;
- for (j = 0; j < basic[mode].ir_nrates; j++)
- if (basic[mode].ir_rates[j] == rs->ir_rates[i]) {
- rs->ir_rates[i] |= IEEE80211_RATE_BASIC;
- break;
- }
- }
-}
-
-/*
- * Set the current phy mode and recalculate the active channel
- * set based on the available channels for this mode. Also
- * select a new default/current channel if the current one is
- * inappropriate for this mode.
- */
-static int
-ieee80211_setmode(ieee80211com_t *isc, enum ieee80211_phymode mode)
-{
- static const uint32_t chanflags[] = {
- 0, /* IEEE80211_MODE_AUTO */
- IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */
- IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */
- IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */
- IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO */
- };
- struct ieee80211channel *ch;
- uint32_t modeflags;
- int32_t i;
-
- /* validate new mode */
- if ((isc->isc_modecaps & (1 << mode)) == 0) {
- ath_problem("ath: ieee80211_setmode(): mode %u not supported"
- " (caps 0x%x)\n", mode, isc->isc_modecaps);
- return (EINVAL);
- }
-
- /*
- * Verify at least one channel is present in the available
- * channel list before committing to the new mode.
- */
- ASSERT(mode < ATH_N(chanflags));
-
- modeflags = chanflags[mode];
- /* isc_channels size is IEEE80211_CHAN_MAX + 1, so no problem */
- for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
- ch = &isc->isc_channels[i];
- if (mode == IEEE80211_MODE_AUTO) {
- /* ignore turbo channels for autoselect */
- if ((ch->ich_flags & ~IEEE80211_CHAN_TURBO) != 0)
- break;
- } else {
- if ((ch->ich_flags & modeflags) == modeflags)
- break;
- }
- }
- if (i > IEEE80211_CHAN_MAX) {
- ath_problem("ath: ieee80211_setmode(): "
- "no channel found for mode %u\n", mode);
- return (EINVAL);
- }
-
- /*
- * Calculate the active channel set.
- */
- bzero(isc->isc_chan_active, sizeof (isc->isc_chan_active));
- for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
- ch = &isc->isc_channels[i];
- if (mode == IEEE80211_MODE_AUTO) {
- /* take anything but pure turbo channels */
- if ((ch->ich_flags & ~IEEE80211_CHAN_TURBO) != 0)
- setbit(isc->isc_chan_active, i);
- } else {
- if ((ch->ich_flags & modeflags) == modeflags)
- setbit(isc->isc_chan_active, i);
- }
- }
- /*
- * If no current/default channel is setup or the current
- * channel is wrong for the mode then pick the first
- * available channel from the active list. This is likely
- * not the right one.
- */
- if (isc->isc_ibss_chan == NULL ||
- isclr(isc->isc_chan_active,
- ieee80211_chan2ieee(isc, isc->isc_ibss_chan))) {
- for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
- if (isset(isc->isc_chan_active, i)) {
- isc->isc_ibss_chan = &isc->isc_channels[i];
- break;
- }
- }
-
- /*
- * Set/reset state flags that influence beacon contents, etc.
- */
-
- if (isc->isc_caps & IEEE80211_C_SHPREAMBLE)
- isc->isc_flags |= IEEE80211_F_SHPREAMBLE;
- if (mode == IEEE80211_MODE_11G) {
- if (isc->isc_caps & IEEE80211_C_SHSLOT)
- isc->isc_flags |= IEEE80211_F_SHSLOT;
- ieee80211_set11gbasicrates(&isc->isc_sup_rates[mode],
- IEEE80211_MODE_11G);
- } else {
- isc->isc_flags &= ~(IEEE80211_F_SHSLOT);
- }
-
- /*
- * Setup an initial rate set according to the
- * current/default channel. This will be changed
- * when scanning but must exist now so drivers have
- * consistent state of ic_ibss_chan.
- */
- if (isc->isc_bss)
- isc->isc_bss->in_rates = isc->isc_sup_rates[mode];
- isc->isc_curmode = mode;
-
- return (0);
-}
-
-/*
- * If (its return value & IEEE80211_RATE_BASIC != 0),
- * the rate negotiation or fix rate is failed.
- */
-static int
-ieee80211_fix_rate(ieee80211com_t *isc,
- struct ieee80211_node *in, int32_t flags)
-{
- int32_t i, j, ignore, error;
- int32_t okrate, badrate;
- struct ieee80211_rateset *srs, *nrs;
- uint8_t r;
-
- error = 0;
- okrate = badrate = 0;
- srs = &isc->isc_sup_rates[ieee80211_chan2mode(isc, in->in_chan)];
- nrs = &in->in_rates;
- for (i = 0; i < in->in_rates.ir_nrates; ) {
- ignore = 0;
- if (flags & IEEE80211_F_DOSORT) {
- /*
- * Sort rates.
- */
- for (j = i + 1; j < nrs->ir_nrates; j++) {
- if (IEEE80211_RV(nrs->ir_rates[i]) >
- IEEE80211_RV(nrs->ir_rates[j])) {
- r = nrs->ir_rates[i];
- nrs->ir_rates[i] = nrs->ir_rates[j];
- nrs->ir_rates[j] = r;
- }
- }
- }
- r = nrs->ir_rates[i] & IEEE80211_RATE_VAL;
- badrate = r;
- if (flags & IEEE80211_F_DOFRATE) {
- /*
- * Apply fixed rate constraint. Note that we do
- * not apply the constraint to basic rates as
- * otherwise we may not be able to associate if
- * the rate set we submit to the AP is invalid
- * (e.g. fix rate at 36Mb/s which is not a basic
- * rate for 11a operation).
- */
- if ((nrs->ir_rates[i] & IEEE80211_RATE_BASIC) == 0 &&
- isc->isc_fixed_rate >= 0 &&
- r != IEEE80211_RV(srs->ir_rates
- [isc->isc_fixed_rate]))
- ignore++;
- }
- if (flags & IEEE80211_F_DONEGO) {
- /*
- * Check against supported rates.
- */
- for (j = 0; j < srs->ir_nrates; j++) {
- if (r == IEEE80211_RV(srs->ir_rates[j]))
- break;
- }
- if (j == srs->ir_nrates) {
- if (nrs->ir_rates[i] & IEEE80211_RATE_BASIC)
- error++;
- ignore++;
- }
- }
- if (flags & IEEE80211_F_DODEL) {
- /*
- * Delete unacceptable rates.
- */
- if (ignore) {
- nrs->ir_nrates--;
- for (j = i; j < nrs->ir_nrates; j++)
- nrs->ir_rates[j] = nrs->ir_rates[j + 1];
- nrs->ir_rates[j] = 0;
- continue;
- }
- }
- if (!ignore)
- okrate = nrs->ir_rates[i];
- i++;
- }
- if (okrate == 0 || error != 0)
- return (badrate | IEEE80211_RATE_BASIC);
- else
- return (IEEE80211_RV(okrate));
-}
-
-/*
- * Complete a scan of potential channels.
- */
-static void
-ieee80211_end_scan(ieee80211com_t *isc)
-{
- struct ieee80211_node *in, *selbs;
- uint8_t rate;
- int32_t fail;
-
- ASSERT(isc->isc_state == IEEE80211_S_SCAN);
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- isc->isc_flags &= ~IEEE80211_F_ASCAN;
- cv_broadcast(&isc->isc_scan_cv);
- in = list_head(&isc->isc_in_list);
-
- if (in == NULL) {
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_end_scan(): "
- "no scan candidate\n"));
-notfound:
- if (isc->isc_opmode == IEEE80211_M_IBSS &&
- (isc->isc_flags & IEEE80211_F_IBSSON) &&
- isc->isc_des_esslen != 0) {
- ieee80211_create_ibss(isc, isc->isc_ibss_chan);
- return;
- }
- mutex_exit(&isc->isc_genlock);
- delay(drv_usectohz(200000));
- mutex_enter(&isc->isc_genlock);
- ieee80211_begin_scan(isc, isc->isc_bss);
- return;
- }
-
- selbs = NULL;
- for (; in != NULL; in = list_next(&isc->isc_in_list, in)) {
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_end_scan(): isc_bss->in_bssid=%s",
- ieee80211_ether_sprintf(in->in_bssid)));
- if (in->in_fails) {
- /*
- * The configuration of the access points may change
- * during my scan. So delete the entry for the AP
- * and retry to associate if there is another beacon.
- */
- if (in->in_fails++ > 2)
- ieee80211_free_node(isc, in);
- continue;
- }
- fail = 0;
- if (in->in_chan == NULL || in->in_chan->ich_flags == 0)
- fail |= 0x01;
- if (isc->isc_des_chan !=
- (struct ieee80211channel *)IEEE80211_CHAN_ANY &&
- in->in_chan != isc->isc_des_chan)
- fail |= 0x01;
- if (isc->isc_opmode == IEEE80211_M_IBSS) {
- if ((in->in_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
- fail |= 0x02;
- } else {
- if ((in->in_capinfo & IEEE80211_CAPINFO_ESS) == 0)
- fail |= 0x02;
- }
-
- if (isc->isc_flags & IEEE80211_F_WEPON) {
- if ((in->in_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
- fail |= 0x04;
- } else {
- if (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY)
- fail |= 0x04;
- }
-
- rate = ieee80211_fix_rate(isc, in, IEEE80211_F_DONEGO);
- if (rate & IEEE80211_RATE_BASIC)
- fail |= 0x08;
- if (isc->isc_des_esslen != 0 &&
- (in->in_esslen != isc->isc_des_esslen ||
- bcmp(in->in_essid, isc->isc_des_essid,
- isc->isc_des_esslen) != 0))
- fail |= 0x10;
- if ((isc->isc_flags & IEEE80211_F_DESBSSID) &&
- !IEEE80211_ADDR_EQ(isc->isc_des_bssid, in->in_bssid))
- fail |= 0x20;
- if (!fail) {
- if (selbs == NULL)
- selbs = in;
- else if (ieee80211_get_rssi(in) >
- ieee80211_get_rssi(selbs))
- selbs = in;
- }
- }
- if (selbs == NULL)
- goto notfound;
- bcopy(selbs, isc->isc_bss, sizeof (struct ieee80211_node));
- if (isc->isc_opmode == IEEE80211_M_IBSS) {
- (void) ieee80211_fix_rate(isc, isc->isc_bss,
- IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO |
- IEEE80211_F_DODEL);
- if (isc->isc_bss->in_rates.ir_nrates == 0) {
- selbs->in_fails++;
- goto notfound;
- }
- (void) _ieee80211_new_state(isc, IEEE80211_S_RUN, -1);
- } else
- (void) _ieee80211_new_state(isc, IEEE80211_S_AUTH, -1);
-}
-
-
-/*
- * Switch to the next channel marked for scanning.
- * This one is only called by multi-func thread.
- */
-static void
-ieee80211_next_scan(ieee80211com_t *isc)
-{
- struct ieee80211channel *chan;
-
- ASSERT(isc->isc_state == IEEE80211_S_SCAN);
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- chan = isc->isc_bss->in_chan;
- for (;;) {
- if (++chan > &isc->isc_channels[IEEE80211_CHAN_MAX])
- chan = &isc->isc_channels[0];
- if (isset(isc->isc_chan_scan, ieee80211_chan2ieee(isc, chan))) {
- /*
- * Honor channels marked passive-only
- * during an active scan.
- */
- if ((isc->isc_flags & IEEE80211_F_ASCAN) == 0 ||
- (chan->ich_flags & IEEE80211_CHAN_PASSIVE) == 0)
- break;
- }
- if (chan == isc->isc_bss->in_chan) {
- ieee80211_end_scan(isc);
- return;
- }
- }
- clrbit(isc->isc_chan_scan, ieee80211_chan2ieee(isc, chan));
-
- isc->isc_bss->in_chan = chan;
- (void) _ieee80211_new_state(isc, IEEE80211_S_SCAN, -1);
-}
-
-
-static void
-ieee80211_setup_node(ieee80211com_t *isc,
- struct ieee80211_node *in, uint8_t *macaddr)
-{
- int32_t hash;
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- IEEE80211_ADDR_COPY(in->in_macaddr, macaddr);
- hash = IEEE80211_NODE_HASH(macaddr);
- list_insert_tail(&isc->isc_in_list, in);
- list_insert_tail(&isc->isc_inhash_list[hash], in);
- /*
- * Note we don't enable the inactive timer when acting
- * as a station. Nodes created in this mode represent
- * AP's identified while scanning. If we time them out
- * then several things happen: we can't return the data
- * to users to show the list of AP's we encountered, and
- * more importantly, we'll incorrectly deauthenticate
- * ourself because the inactivity timer will kick us off.
- */
- if (isc->isc_opmode != IEEE80211_M_STA)
- isc->isc_inact_timeout = IEEE80211_INACT_WAIT;
-}
-
-static struct ieee80211_node *
-ieee80211_alloc_node(ieee80211com_t *isc, uint8_t *macaddr)
-{
- struct ieee80211_node *in = (*isc->isc_node_alloc)(isc);
- bzero(in, sizeof (struct ieee80211_node));
- ieee80211_setup_node(isc, in, macaddr);
- return (in);
-}
-
-static struct ieee80211_node *
-ieee80211_dup_bss(ieee80211com_t *isc, uint8_t *macaddr)
-{
- struct ieee80211_node *in;
-
- in = kmem_zalloc(sizeof (struct ieee80211_node), KM_SLEEP);
- ieee80211_setup_node(isc, in, macaddr);
- return (in);
-}
-
-/*
- * Find a node state block given the mac address. Note that
- * this returns the first node found with the mac address.
- */
-struct ieee80211_node *
-ieee80211_find_node(ieee80211com_t *isc, uint8_t *macaddr)
-{
- struct ieee80211_node *in;
- int32_t hash;
-
- hash = IEEE80211_NODE_HASH(macaddr);
- in = list_head(&isc->isc_inhash_list[hash]);
- while (in != NULL) {
- if (IEEE80211_ADDR_EQ(in->in_macaddr, macaddr))
- break;
- in = list_next(&isc->isc_inhash_list[hash], in);
- }
- return (in);
-}
-
-/*
- * Like find but search based on the channel too.
- */
-struct ieee80211_node *
-ieee80211_lookup_node(ieee80211com_t *isc, uint8_t *macaddr,
- struct ieee80211channel *chan)
-{
- struct ieee80211_node *in;
- int32_t hash;
-
- hash = IEEE80211_NODE_HASH(macaddr);
- in = list_head(&isc->isc_inhash_list[hash]);
- while (in != NULL) {
- if (IEEE80211_ADDR_EQ(in->in_macaddr, macaddr) &&
- (in->in_chan == chan))
- break;
- in = list_next(&isc->isc_inhash_list[hash], in);
- }
- return (in);
-}
-
-
-
-/*
- * Install received rate set information in the node's state block.
- * If (its return value & IEEE80211_RATE_BASIC != 0),
- * the rate negotiation or fix rate is failed.
- */
-static int32_t
-ieee80211_setup_rates(ieee80211com_t *isc, struct ieee80211_node *in,
- uint8_t *rates, uint8_t *xrates, int32_t flags)
-{
- struct ieee80211_rateset *rs = &in->in_rates;
-
- bzero(rs, sizeof (*rs));
- rs->ir_nrates = rates[1];
- bcopy(rates + 2, rs->ir_rates, rs->ir_nrates);
- if (xrates != NULL) {
- uint8_t nxrates;
- /*
- * Tack on 11g extended supported rate element.
- */
- nxrates = xrates[1];
- if (rs->ir_nrates + nxrates > IEEE80211_RATE_MAXSIZE) {
- nxrates = IEEE80211_RATE_MAXSIZE - rs->ir_nrates;
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_setup_rates(): extended rate set"
- " too large; only using %u of %u rates\n",
- nxrates, xrates[1]));
- }
- bcopy(xrates + 2, rs->ir_rates + rs->ir_nrates, nxrates);
- rs->ir_nrates += nxrates;
- }
- return (ieee80211_fix_rate(isc, in, flags));
-}
-
-
-/*
- * Misc management frame encapsulation functions.
- */
-static uint8_t *
-ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs)
-{
- int32_t nrates;
-
- *frm++ = IEEE80211_ELEMID_RATES;
- nrates = rs->ir_nrates;
- if (nrates > IEEE80211_RATE_SIZE)
- nrates = IEEE80211_RATE_SIZE;
- *frm++ = nrates;
- bcopy(rs->ir_rates, frm, nrates);
- return (frm + nrates);
-}
-
-static uint8_t *
-ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs)
-{
- /*
- * Add an extended supported rates element if operating in 11g mode.
- */
- if (rs->ir_nrates > IEEE80211_RATE_SIZE) {
- int32_t nrates = rs->ir_nrates - IEEE80211_RATE_SIZE;
- *frm++ = IEEE80211_ELEMID_XRATES;
- *frm++ = nrates;
- bcopy(rs->ir_rates + IEEE80211_RATE_SIZE, frm, nrates);
- frm += nrates;
- }
- return (frm);
-}
-
-static uint8_t *
-ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, uint32_t len)
-{
- *frm++ = IEEE80211_ELEMID_SSID;
- *frm++ = len;
- bcopy(ssid, frm, len);
- return (frm + len);
-}
-
-/*
- * Following functions are responsible for management frame encapsulation.
- */
-static int32_t
-ieee80211_send_prreq(ieee80211com_t *isc, struct ieee80211_node *in,
- int32_t type, int32_t dummy)
-{
- int32_t ret, pktlen;
- mblk_t *mp;
- uint8_t *frm;
- enum ieee80211_phymode mode;
-
- _NOTE(ARGUNUSED(dummy));
-
- ASSERT(mutex_owned(&isc->isc_genlock));
- /*
- * prreq frame format
- * [tlv] ssid
- * [tlv] supported rates
- * [tlv] extended supported rates
- */
- pktlen = sizeof (struct ieee80211_frame) +
- 2 + isc->isc_des_esslen +
- 2 + IEEE80211_RATE_SIZE +
- 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE);
- mp = allocb(pktlen, BPRI_MED);
- if (mp == NULL) {
- ath_problem("ath: ieee80211_send_prreq(): no space\n");
- return (ENOMEM);
- }
- mp->b_rptr += sizeof (struct ieee80211_frame);
-
- frm = mp->b_rptr;
- frm = ieee80211_add_ssid(frm, isc->isc_des_essid, isc->isc_des_esslen);
- mode = ieee80211_chan2mode(isc, in->in_chan);
- frm = ieee80211_add_rates(frm, &isc->isc_sup_rates[mode]);
- frm = ieee80211_add_xrates(frm, &isc->isc_sup_rates[mode]);
- mp->b_wptr = frm;
-
- ret = ieee80211_mgmt_output(isc, in, mp, type);
- isc->isc_mgt_timeout = IEEE80211_TRANS_WAIT;
-
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_send_prreq() "
- "channel=%u\n", ieee80211_chan2ieee(isc, in->in_chan)));
-
- return (ret);
-}
-
-static int32_t
-ieee80211_send_prresp(ieee80211com_t *isc, struct ieee80211_node *bs0,
- int32_t type, int32_t dummy)
-{
- mblk_t *mp;
- uint8_t *frm;
- struct ieee80211_node *in = isc->isc_bss;
- uint16_t capinfo;
- int32_t pktlen;
-
- _NOTE(ARGUNUSED(dummy));
-
- ASSERT(mutex_owned(&isc->isc_genlock));
- /*
- * probe response frame format
- * [8] time stamp
- * [2] beacon interval
- * [2] cabability information
- * [tlv] ssid
- * [tlv] supported rates
- * [tlv] parameter set (IBSS)
- * [tlv] extended supported rates
- */
- pktlen = sizeof (struct ieee80211_frame) +
- 8 + 2 + 2 + 2 +
- 2 + in->in_esslen +
- 2 + IEEE80211_RATE_SIZE +
- 6 +
- 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE);
- mp = allocb(pktlen, BPRI_MED);
- if (mp == NULL) {
- ath_problem("ath: ieee80211_send_prresp(): alloc failed.\n");
- return (ENOMEM);
- }
- mp->b_rptr += sizeof (struct ieee80211_frame);
- frm = mp->b_rptr;
-
- bzero(frm, 8); /* timestamp */
- frm += 8;
-
- *(uint16_t *)frm = LE_16(in->in_intval);
- frm += 2;
-
- if (isc->isc_opmode == IEEE80211_M_IBSS)
- capinfo = IEEE80211_CAPINFO_IBSS;
- else
- capinfo = IEEE80211_CAPINFO_ESS;
- if (isc->isc_flags & IEEE80211_F_WEPON)
- capinfo |= IEEE80211_CAPINFO_PRIVACY;
- *(uint16_t *)frm = LE_16(capinfo);
- frm += 2;
-
- frm = ieee80211_add_ssid(frm, in->in_essid, in->in_esslen);
- frm = ieee80211_add_rates(frm, &in->in_rates);
-
- if (isc->isc_opmode == IEEE80211_M_IBSS) {
- *frm++ = IEEE80211_ELEMID_IBSSPARMS;
- *frm++ = 2;
- *frm++ = 0; *frm++ = 0; /* ATIM window */
- } else { /* IEEE80211_M_HOSTAP */
- /* TIM */
- *frm++ = IEEE80211_ELEMID_TIM;
- *frm++ = 4; /* length */
- *frm++ = 0; /* DTIM count */
- *frm++ = 1; /* DTIM period */
- *frm++ = 0; /* bitmap control */
- *frm++ = 0; /* Partial Virtual Bitmap (variable length) */
- }
- frm = ieee80211_add_xrates(frm, &in->in_rates);
- mp->b_wptr = frm;
-
- return (ieee80211_mgmt_output(isc, bs0, mp, type));
-}
-
-static int32_t
-ieee80211_send_auth(ieee80211com_t *isc, struct ieee80211_node *in,
- int32_t type, int32_t seq)
-{
- mblk_t *mp;
- uint16_t *frm;
- int32_t ret, pktlen;
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- pktlen = sizeof (struct ieee80211_frame) + 3 * sizeof (uint16_t);
- mp = allocb(pktlen, BPRI_MED);
- if (mp == NULL) {
- ath_problem("ath: ieee80211_send_auth(): allocb failed\n");
- return (ENOMEM);
- }
- mp->b_wptr = mp->b_rptr + pktlen;
- mp->b_rptr += sizeof (struct ieee80211_frame);
-
- frm = (uint16_t *)mp->b_rptr;
- /* shared key auth */
- frm[0] = LE_16(IEEE80211_AUTH_ALG_OPEN);
- frm[1] = LE_16(seq);
- frm[2] = 0; /* status */
- ret = ieee80211_mgmt_output(isc, in, mp, type);
- if (isc->isc_opmode == IEEE80211_M_STA)
- isc->isc_mgt_timeout = IEEE80211_TRANS_WAIT;
- return (ret);
-}
-
-static int32_t
-ieee80211_send_deauth(ieee80211com_t *isc, struct ieee80211_node *in,
- int32_t type, int32_t reason)
-{
- mblk_t *mp;
- uint16_t *frm;
- int32_t pktlen;
-
- ASSERT(mutex_owned(&isc->isc_genlock));
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_send_deauth(): station %s deauthenticate",
- " (reason %d)\n", ieee80211_ether_sprintf(in->in_macaddr), reason));
- pktlen = sizeof (struct ieee80211_frame) + sizeof (uint16_t);
- mp = allocb(pktlen, BPRI_MED);
- if (mp == NULL) {
- ath_problem("ath: ieee80211_send_deauth(): allocb failed\n");
- return (ENOMEM);
- }
- mp->b_wptr = mp->b_rptr + pktlen;
- mp->b_rptr += sizeof (struct ieee80211_frame);
-
- frm = (uint16_t *)mp->b_rptr;
- frm[0] = LE_16(reason);
-
- return (ieee80211_mgmt_output(isc, in, mp, type));
-}
-
-static int32_t
-ieee80211_send_asreq(ieee80211com_t *isc, struct ieee80211_node *in,
- int32_t type, int32_t dummy)
-{
- mblk_t *mp;
- uint8_t *frm;
- uint16_t capinfo = 0;
- int32_t ret, pktlen;
-
- _NOTE(ARGUNUSED(dummy));
-
- ASSERT(mutex_owned(&isc->isc_genlock));
- /*
- * asreq frame format
- * [2] capability information
- * [2] listen interval
- * [6*] current AP address (reassoc only)
- * [tlv] ssid
- * [tlv] supported rates
- * [tlv] extended supported rates
- */
- pktlen = sizeof (struct ieee80211_frame) +
- sizeof (capinfo) + sizeof (uint16_t) + IEEE80211_ADDR_LEN +
- 2 + in->in_esslen + 2 + IEEE80211_RATE_SIZE +
- 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE);
- mp = allocb(pktlen, BPRI_MED);
- if (mp == NULL) {
- ath_problem("ath: ieee80211_send_asreq: allocb failed\n");
- return (ENOMEM);
- }
- mp->b_rptr += sizeof (struct ieee80211_frame);
-
- frm = (uint8_t *)mp->b_rptr;
-
- capinfo = 0;
- if (isc->isc_opmode == IEEE80211_M_IBSS)
- capinfo |= IEEE80211_CAPINFO_IBSS;
- else /* IEEE80211_M_STA */
- capinfo |= IEEE80211_CAPINFO_ESS;
- if (isc->isc_flags & IEEE80211_F_WEPON)
- capinfo |= IEEE80211_CAPINFO_PRIVACY;
- if (isc->isc_flags & IEEE80211_F_SHPREAMBLE)
- capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
- if (isc->isc_flags & IEEE80211_F_SHSLOT)
- capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
- capinfo |= 0x0020;
- *(uint16_t *)frm = LE_16(capinfo);
- frm += 2;
-
- *(uint16_t *)frm = LE_16(isc->isc_lintval);
- frm += 2;
-
- if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
- IEEE80211_ADDR_COPY(frm, isc->isc_bss->in_bssid);
- frm += IEEE80211_ADDR_LEN;
- }
-
- frm = ieee80211_add_ssid(frm, in->in_essid, in->in_esslen);
- frm = ieee80211_add_rates(frm, &in->in_rates);
- frm = ieee80211_add_xrates(frm, &in->in_rates);
- mp->b_wptr = frm;
- ret = ieee80211_mgmt_output(isc, in, mp, type);
- isc->isc_mgt_timeout = IEEE80211_TRANS_WAIT;
- return (ret);
-}
-
-static int32_t
-ieee80211_send_asresp(ieee80211com_t *isc, struct ieee80211_node *in,
- int32_t type, int32_t status)
-{
- mblk_t *mp;
- uint8_t *frm;
- uint16_t capinfo;
- int32_t pktlen;
-
- ASSERT(mutex_owned(&isc->isc_genlock));
- /*
- * asreq frame format
- * [2] capability information
- * [2] status
- * [2] association ID
- * [tlv] supported rates
- * [tlv] extended supported rates
- */
- pktlen = sizeof (struct ieee80211_frame) +
- sizeof (capinfo) +
- sizeof (uint16_t) +
- sizeof (uint16_t) +
- 2 + IEEE80211_RATE_SIZE +
- 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE);
- mp = allocb(pktlen, BPRI_MED);
- if (mp == NULL) {
- ath_problem("ath: ieee80211_send_asresp: allocb failed\n");
- return (ENOMEM);
- }
- mp->b_rptr += sizeof (struct ieee80211_frame);
- frm = (uint8_t *)mp->b_rptr;
-
- capinfo = IEEE80211_CAPINFO_ESS;
- if (isc->isc_flags & IEEE80211_F_WEPON)
- capinfo |= IEEE80211_CAPINFO_PRIVACY;
- *(uint16_t *)frm = LE_16(capinfo);
- frm += 2;
-
- *(uint16_t *)frm = LE_16(status);
- frm += 2;
-
- if (status == IEEE80211_STATUS_SUCCESS && in != NULL)
- *(uint16_t *)frm = LE_16(in->in_associd);
- else
- *(uint16_t *)frm = LE_16(0);
- frm += 2;
-
- if (in != NULL) {
- frm = ieee80211_add_rates(frm, &in->in_rates);
- frm = ieee80211_add_xrates(frm, &in->in_rates);
- } else {
- frm = ieee80211_add_rates(frm, &isc->isc_bss->in_rates);
- frm = ieee80211_add_xrates(frm, &isc->isc_bss->in_rates);
- }
- mp->b_wptr = frm;
-
- return (ieee80211_mgmt_output(isc, in, mp, type));
-}
-
-static int32_t
-ieee80211_send_disassoc(ieee80211com_t *isc, struct ieee80211_node *in,
- int32_t type, int32_t reason)
-{
- mblk_t *mp;
- uint16_t *frm;
- int32_t pktlen;
-
- _NOTE(ARGUNUSED(type))
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_send_disassoc(): station %s disassociate",
- " (reason %d)\n", ieee80211_ether_sprintf(in->in_macaddr), reason));
- pktlen = sizeof (struct ieee80211_frame) + sizeof (uint16_t);
- mp = allocb(pktlen, BPRI_MED);
- if (mp == NULL) {
- ath_problem("ath: ieee80211_send_asresp: allocb failed\n");
- return (ENOMEM);
- }
- mp->b_wptr = mp->b_rptr + pktlen;
- mp->b_rptr += sizeof (struct ieee80211_frame);
- frm = (uint16_t *)mp->b_rptr;
- frm[0] = LE_16(reason);
- return (ieee80211_mgmt_output(isc, in, mp,
- IEEE80211_FC0_SUBTYPE_DISASSOC));
-}
-
-/*
- * This handles both beacon and probe response frames.
- */
-static void
-ieee80211_recv_beacon(ieee80211com_t *isc, mblk_t *mp, int32_t rssi,
- uint32_t rstamp, uint32_t rantenna)
-{
- struct ieee80211_frame *wh;
- struct ieee80211_node *in;
- uint8_t *frm, *efrm, *tstamp, *bintval, *capinfo, *ssid;
- uint8_t *rates, *xrates;
- uint8_t chan, bchan, fhindex, erp;
- uint16_t fhdwell;
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- if (isc->isc_opmode != IEEE80211_M_IBSS &&
- isc->isc_state != IEEE80211_S_SCAN) {
- return;
- }
-
- wh = (struct ieee80211_frame *)mp->b_rptr;
- frm = (uint8_t *)&wh[1];
- efrm = mp->b_wptr;
- /*
- * beacon frame format
- * [8] time stamp
- * [2] beacon interval
- * [2] cabability information
- * [tlv] ssid
- * [tlv] supported rates
- * [tlv] country information
- * [tlv] parameter set (FH/DS)
- * [tlv] erp information
- * [tlv] extended supported rates
- */
- tstamp = frm;
- frm += 8;
- bintval = frm;
- frm += 2;
- capinfo = frm;
- frm += 2;
- ssid = rates = xrates = NULL;
- bchan = ieee80211_chan2ieee(isc, isc->isc_bss->in_chan);
- chan = bchan;
- fhdwell = 0;
- fhindex = 0;
- erp = 0;
- while (frm < efrm) {
- switch (*frm) {
- case IEEE80211_ELEMID_SSID:
- ssid = frm;
- break;
- case IEEE80211_ELEMID_RATES:
- rates = frm;
- break;
- case IEEE80211_ELEMID_COUNTRY:
- /*
- * don't care 'country', otherwise,
- * just do:
- * country = frm;
- */
- break;
- case IEEE80211_ELEMID_FHPARMS:
- if (isc->isc_phytype == IEEE80211_T_FH) {
- fhdwell = (frm[3] << 8) | frm[2];
- chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
- fhindex = frm[6];
- }
- break;
- case IEEE80211_ELEMID_DSPARMS:
- /*
- * hack this since depending on phytype
- * is problematic for multi-mode devices.
- */
- if (isc->isc_phytype != IEEE80211_T_FH)
- chan = frm[2];
- break;
- case IEEE80211_ELEMID_TIM:
- break;
- case IEEE80211_ELEMID_XRATES:
- xrates = frm;
- break;
- case IEEE80211_ELEMID_ERP:
- if (frm[1] != 1) {
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_recv_beacon(): "
- "%s: invalid ERP element; "
- "length %u, expecting 1\n",
- "ieee80211_recv_beacon", frm[1]));
- break;
- }
- erp = frm[2];
- break;
- default:
- break;
- }
- frm += frm[1] + 2;
- }
- IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_SIZE, wh);
- IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, wh);
-
- if (isclr(isc->isc_chan_active, chan)) {
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_recv_beacon(): "
- "ignore %s with invalid channel %u\n",
- IEEE80211_ISPROBE(wh) ? "probe response" : "beacon", chan));
- return;
- }
- if (chan != bchan && isc->isc_phytype != IEEE80211_T_FH) {
- /*
- * Frame was received on a channel different from the
- * one indicated in the DS/FH params element id; silently
- * discard it.
- *
- * NB: this can happen due to signal leakage.
- */
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_recv_beacon(): "
- "ignore %s phytype %u on channel %u marked for %u\n",
- IEEE80211_ISPROBE(wh) ? "probe response" : "beacon",
- isc->isc_phytype,
- bchan, chan));
- return;
- }
-
- /*
- * Use mac and channel for lookup so we collect all
- * potential AP's when scanning. Otherwise we may
- * see the same AP on multiple channels and will only
- * record the last one. We could filter APs here based
- * on rssi, etc. but leave that to the end of the scan
- * so we can keep the selection criteria in one spot.
- * This may result in a bloat of the scanned AP list but
- * it shouldn't be too much.
- */
- in = ieee80211_lookup_node(isc, wh->ifrm_addr2,
- &isc->isc_channels[chan]);
- if (in == NULL || isc->isc_state == IEEE80211_S_SCAN) {
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_recv_beacon(): essid = %s\n",
- ieee80211_essid_sprintf(ssid + 2, ssid[1])));
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_recv_beacon(): "
- "from %s\n", ieee80211_ether_sprintf(wh->ifrm_addr2)));
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_recv_beacon(): to %s\n",
- ieee80211_ether_sprintf(wh->ifrm_addr1)));
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_recv_beacon(): "
- "caps 0x%x bintval %u erp 0x%x\n",
- LE_16(*(uint16_t *)capinfo),
- LE_16(*(uint16_t *)bintval), erp));
- }
-
- if (in == NULL) {
- in = ieee80211_alloc_node(isc, wh->ifrm_addr2);
- if (in == NULL)
- return;
- in->in_esslen = ssid[1];
- bzero(in->in_essid, sizeof (in->in_essid));
- bcopy(ssid + 2, in->in_essid, ssid[1]);
- } else if (ssid[1] != 0 && IEEE80211_ISPROBE(wh)) {
- /*
- * Update ESSID at probe response to adopt hidden AP by
- * Lucent/Cisco, which announces null ESSID in beacon.
- */
- in->in_esslen = ssid[1];
- bzero(in->in_essid, sizeof (in->in_essid));
- bcopy(ssid + 2, in->in_essid, ssid[1]);
- }
-
- IEEE80211_ADDR_COPY(in->in_bssid, wh->ifrm_addr3);
- ieee80211_add_recvhist(in, rssi, rstamp, rantenna);
- bcopy(tstamp, in->in_tstamp, sizeof (in->in_tstamp));
- in->in_intval = LE_16(*(uint16_t *)bintval);
- in->in_capinfo = LE_16(*(uint16_t *)capinfo);
- in->in_chan = &isc->isc_channels[chan];
- in->in_fhdwell = fhdwell;
- in->in_fhindex = fhindex;
- in->in_erp = erp;
- /* in_chan must have been setup */
- (void) ieee80211_setup_rates(isc, in, rates, xrates,
- IEEE80211_F_DOSORT);
-}
-
-static void
-ieee80211_recv_prreq(ieee80211com_t *isc, mblk_t *mp, int32_t rssi,
- uint32_t rstamp, uint32_t rantenna)
-{
- struct ieee80211_frame *wh;
- struct ieee80211_node *in;
- uint8_t *frm, *efrm, *ssid, *rates, *xrates;
- uint8_t rate;
- int32_t allocbs;
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- if (isc->isc_opmode == IEEE80211_M_STA)
- return;
- if (isc->isc_state != IEEE80211_S_RUN)
- return;
-
- wh = (struct ieee80211_frame *)mp->b_rptr;
- frm = (uint8_t *)&wh[1];
- efrm = mp->b_wptr;
- /*
- * prreq frame format
- * [tlv] ssid
- * [tlv] supported rates
- * [tlv] extended supported rates
- */
- ssid = rates = xrates = NULL;
- while (frm < efrm) {
- switch (*frm) {
- case IEEE80211_ELEMID_SSID:
- ssid = frm;
- break;
- case IEEE80211_ELEMID_RATES:
- rates = frm;
- break;
- case IEEE80211_ELEMID_XRATES:
- xrates = frm;
- break;
- }
- frm += frm[1] + 2;
- }
- IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_SIZE, wh);
- IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, wh);
- if (ssid[1] != 0 &&
- (ssid[1] != isc->isc_bss->in_esslen ||
- bcmp(ssid + 2, isc->isc_bss->in_essid,
- isc->isc_bss->in_esslen) != 0)) {
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_recv_prreq(): "
- "ssid unmatch %s from %s",
- ieee80211_essid_sprintf(ssid + 2, ssid[1]),
- ieee80211_ether_sprintf(wh->ifrm_addr2)));
- return;
- }
-
- in = ieee80211_find_node(isc, wh->ifrm_addr2);
- if (in == NULL) {
- in = ieee80211_dup_bss(isc, wh->ifrm_addr2);
- if (in == NULL) {
- ath_problem("ath: ieee80211_recv_prreq(): "
- "dup bss failed\n");
- return;
- }
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_recv_prreq: new req from %s\n",
- ieee80211_ether_sprintf(wh->ifrm_addr2)));
- allocbs = 1;
- } else
- allocbs = 0;
- ieee80211_add_recvhist(in, rssi, rstamp, rantenna);
- rate = ieee80211_setup_rates(isc, in, rates, xrates,
- IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE
- | IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
- if (rate & IEEE80211_RATE_BASIC) {
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_recv_prreq(): "
- "rate negotiation fail: %s\n",
- ieee80211_ether_sprintf(wh->ifrm_addr2)));
- } else {
- IEEE80211_SEND_MGMT(isc, in, IEEE80211_FC0_SUBTYPE_PROBE_RESP,
- 0);
- }
-
- if (allocbs && isc->isc_opmode == IEEE80211_M_HOSTAP)
- ieee80211_free_node(isc, in);
- else
- ieee80211_unref_node(&in);
-}
-
-static void
-ieee80211_recv_auth(ieee80211com_t *isc, mblk_t *mp, int32_t rssi,
- uint32_t rstamp, uint32_t rantenna)
-{
- struct ieee80211_frame *wh;
- struct ieee80211_node *in;
- uint8_t *frm, *efrm;
- uint16_t algo, seq, status;
-
- _NOTE(ARGUNUSED(rssi))
- _NOTE(ARGUNUSED(rstamp))
- _NOTE(ARGUNUSED(rantenna))
- _NOTE(ARGUNUSED(mp))
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- wh = (struct ieee80211_frame *)mp->b_rptr;
- frm = (uint8_t *)&wh[1];
- efrm = mp->b_wptr;
- /*
- * auth frame format
- * [2] algorithm
- * [2] sequence
- * [2] status
- * [tlv*] challenge
- */
- if (frm + 6 > efrm) {
- ATH_DEBUG((ATH_DBG_80211, "ath: "
- "ieee80211_recv_auth: too short from %s\n",
- ieee80211_ether_sprintf(wh->ifrm_addr2)));
- return;
- }
-
- algo = LE_16(*(uint16_t *)frm);
- seq = LE_16(*(uint16_t *)(frm + 2));
- status = LE_16(*(uint16_t *)(frm + 4));
- if (algo != IEEE80211_AUTH_ALG_OPEN) {
- /* shared key auth */
- ath_problem("ath: ieee80211_recv_auth(): "
- "unsupported auth %d from %s\n",
- algo, ieee80211_ether_sprintf(wh->ifrm_addr2));
- return;
- }
- switch (isc->isc_opmode) {
- case IEEE80211_M_IBSS:
- if (isc->isc_state != IEEE80211_S_RUN || seq != 1)
- return;
- (void) _ieee80211_new_state(isc, IEEE80211_S_AUTH,
- wh->ifrm_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
- break;
-
- case IEEE80211_M_AHDEMO:
- break;
-
- case IEEE80211_M_HOSTAP:
- break;
-
- case IEEE80211_M_STA:
- if (isc->isc_state != IEEE80211_S_AUTH || seq != 2)
- return;
- if (status != 0) {
- ath_log("ath: ieee80211_recv_auth(): "
- "authentication failed (reason %d) for %s\n",
- status, ieee80211_ether_sprintf(wh->ifrm_addr3));
- in = ieee80211_find_node(isc, wh->ifrm_addr2);
- if (in != NULL)
- in->in_fails++;
- return;
- }
- (void) _ieee80211_new_state(isc, IEEE80211_S_ASSOC,
- wh->ifrm_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
- break;
- }
-}
-
-static void
-ieee80211_recv_asreq(ieee80211com_t *isc, mblk_t *mp, int32_t rssi,
- uint32_t rstamp, uint32_t rantenna)
-{
- _NOTE(ARGUNUSED(isc))
- _NOTE(ARGUNUSED(rssi))
- _NOTE(ARGUNUSED(rstamp))
- _NOTE(ARGUNUSED(rantenna))
- _NOTE(ARGUNUSED(mp))
-
- /* doesn't support HOST-AP mode yet */
-}
-
-static void
-ieee80211_recv_asresp(ieee80211com_t *isc, mblk_t *mp, int32_t rssi,
- uint32_t rstamp, uint32_t rantenna)
-{
- struct ieee80211_frame *wh;
- struct ieee80211_node *in;
- uint8_t *frm, *efrm, *rates, *xrates;
- int32_t status;
-
- _NOTE(ARGUNUSED(rssi))
- _NOTE(ARGUNUSED(rstamp))
- _NOTE(ARGUNUSED(rantenna))
- _NOTE(ARGUNUSED(mp))
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- if (isc->isc_opmode != IEEE80211_M_STA ||
- isc->isc_state != IEEE80211_S_ASSOC)
- return;
-
- wh = (struct ieee80211_frame *)mp->b_rptr;
- frm = (uint8_t *)&wh[1];
- efrm = mp->b_wptr;
- /*
- * asresp frame format
- * [2] capability information
- * [2] status
- * [2] association ID
- * [tlv] supported rates
- * [tlv] extended supported rates
- */
- if (frm + 6 > efrm) {
- ath_log("ath: ieee80211_recv_asresp(): too short from %s\n",
- ieee80211_ether_sprintf(wh->ifrm_addr2));
- return;
- }
-
- in = isc->isc_bss;
- in->in_capinfo = LE_16(*(uint16_t *)frm);
- frm += 2;
-
- status = LE_16(*(uint16_t *)frm);
- frm += 2;
-
- if (status != 0) {
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_recv_asresp(): "
- "association failed (reason %d)\n", status));
- in = ieee80211_find_node(isc, wh->ifrm_addr2);
- if (in != NULL) {
- in->in_fails++;
- }
- return;
- }
-
- in->in_associd = LE_16(*(uint16_t *)frm);
- frm += 2;
-
- rates = xrates = NULL;
- while (frm < efrm) {
- switch (*frm) {
- case IEEE80211_ELEMID_RATES:
- rates = frm;
- break;
- case IEEE80211_ELEMID_XRATES:
- xrates = frm;
- break;
- }
- frm += frm[1] + 2;
- }
-
- IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_SIZE, wh);
- (void) ieee80211_setup_rates(isc, in, rates, xrates,
- IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
- IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
- if (in->in_rates.ir_nrates != 0)
- (void) _ieee80211_new_state(isc, IEEE80211_S_RUN,
- wh->ifrm_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
-}
-
-static void
-ieee80211_recv_disassoc(ieee80211com_t *isc, mblk_t *mp, int32_t rssi,
- uint32_t rstamp, uint32_t rantenna)
-{
- struct ieee80211_frame *wh;
- uint8_t *frm, *efrm;
- uint16_t reason;
-
- _NOTE(ARGUNUSED(rssi))
- _NOTE(ARGUNUSED(rstamp))
- _NOTE(ARGUNUSED(rantenna))
- _NOTE(ARGUNUSED(mp))
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- wh = (struct ieee80211_frame *)mp->b_rptr;
- frm = (uint8_t *)&wh[1];
- efrm = mp->b_wptr;
- /*
- * disassoc frame format
- * [2] reason
- */
- if (frm + 2 > efrm) {
- ath_log("ath: ieee80211_recv_disassoc(): too short from %s\n",
- ieee80211_ether_sprintf(wh->ifrm_addr2));
- return;
- }
- reason = LE_16(*(uint16_t *)frm);
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_recv_disassoc(): "
- "disassociation packet, reason:0x%x\n", reason));
- switch (isc->isc_opmode) {
- case IEEE80211_M_STA:
- (void) _ieee80211_new_state(isc, IEEE80211_S_ASSOC,
- wh->ifrm_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
- break;
- case IEEE80211_M_HOSTAP:
- /* don't support HOSTAP */
- break;
- default:
- break;
- }
-}
-
-static void
-ieee80211_recv_deauth(ieee80211com_t *isc, mblk_t *mp, int32_t rssi,
- uint32_t rstamp, uint32_t rantenna)
-{
- struct ieee80211_frame *wh;
- uint8_t *frm, *efrm;
- uint16_t reason;
-
- _NOTE(ARGUNUSED(rssi))
- _NOTE(ARGUNUSED(rstamp))
- _NOTE(ARGUNUSED(rantenna))
- _NOTE(ARGUNUSED(mp))
-
- ASSERT(mutex_owned(&isc->isc_genlock));
-
- wh = (struct ieee80211_frame *)mp->b_rptr;
- frm = (uint8_t *)&wh[1];
- efrm = mp->b_wptr;
- /*
- * dauth frame format
- * [2] reason
- */
- if (frm + 2 > efrm) {
- ath_log("ath: ieee80211_recv_deauth(): too short from %s\n",
- ieee80211_ether_sprintf(wh->ifrm_addr2));
- return;
- }
- reason = LE_16(*(uint16_t *)frm);
- ATH_DEBUG((ATH_DBG_80211, "ath: ieee80211_recv_deauth(): "
- "deauthentication packet, reason: 0x%x\n", reason));
- switch (isc->isc_opmode) {
- case IEEE80211_M_STA:
- (void) _ieee80211_new_state(isc, IEEE80211_S_AUTH,
- wh->ifrm_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
- break;
- case IEEE80211_M_HOSTAP:
- break;
- default:
- break;
- }
-}
-
-/*
- * Return the phy mode for with the specified channel so the
- * caller can select a rate set. This is problematic and the
- * work here assumes how things work elsewhere in this code.
- */
-enum ieee80211_phymode
-ieee80211_chan2mode(ieee80211com_t *isc, struct ieee80211channel *chan)
-{
- /*
- * NB: this assumes the channel would not be supplied to us
- * unless it was already compatible with the current mode.
- */
- if (isc->isc_curmode != IEEE80211_MODE_AUTO)
- return (isc->isc_curmode);
- /*
- * In autoselect mode; deduce a mode based on the channel
- * characteristics. We assume that turbo-only channels
- * are not considered when the channel set is constructed.
- */
- if (IEEE80211_IS_CHAN_5GHZ(chan))
- return (IEEE80211_MODE_11A);
- else if (chan->ich_flags & (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN))
- return (IEEE80211_MODE_11G);
- else
- return (IEEE80211_MODE_11B);
-}
-
-
-/*
- * Format an Ethernet MAC for printing,
- * and this function adds NULL byte at the end of string.
- */
-const char *
-ieee80211_ether_sprintf(const uint8_t *mac)
-{
- static char etherbuf[18];
- (void) snprintf(etherbuf, sizeof (etherbuf),
- "%02x:%02x:%02x:%02x:%02x:%02x",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- return (etherbuf);
-}
-
-/*
- * Format an essid for printing,
- * and this function adds NULL byte at the end of string.
- */
-const int8_t *
-ieee80211_essid_sprintf(uint8_t *essid, uint32_t len)
-{
- static int8_t essidbuf[IEEE80211_NWID_LEN * 2 + 1];
- uint32_t i;
- uint8_t *p;
- int8_t tmp[3];
-
- bzero(essidbuf, sizeof (essidbuf));
- if (len > IEEE80211_NWID_LEN)
- len = IEEE80211_NWID_LEN;
- /* determine printable or not */
- for (i = 0, p = essid; i < len; i++, p++) {
- if (*p < ' ' || *p > 0x7e)
- break;
- }
- if (i == len) {
- for (i = 0; i < len; i++)
- essidbuf[i] = essid[i];
- essidbuf[i] = '\0';
- } else {
- for (i = 0; i < len; i++) {
- (void) sprintf(tmp, "%02x", essid[i]);
- (void) strcat(essidbuf, tmp);
- }
- }
- return (essidbuf);
-}
-
-/*
- * Following fucntions are registerd to GLD and intercepting
- * the function calls from GLD to LLD to add appropriate ic_genlock protection.
- *
- * We have to protect ieee80211_gld_send() by isc_genlock,
- * because there have many references to isc struct on this transimit path,
- * and this may affect performace.
- */
-static int32_t
-ieee80211_gld_send(gld_mac_info_t *gld_p, mblk_t *mp)
-{
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
- int32_t result;
-
- mutex_enter(&isc->isc_genlock);
- result = (*isc->isc_gld_send)(gld_p, mp);
- mutex_exit(&isc->isc_genlock);
- return (result);
-}
-
-static int32_t
-ieee80211_gld_reset(gld_mac_info_t *gld_p)
-{
- int32_t result;
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
-
- mutex_enter(&isc->isc_genlock);
- result = (*isc->isc_gld_reset)(gld_p);
- mutex_exit(&isc->isc_genlock);
- return (result);
-}
-
-
-/*
- * Following function is for Multi_func thread.
- * The smallest timing unit is 100ms.
- * It is created in ieee80211_gld_start(),
- * and destroy in ieee80211_gld_stop().
- */
-void
-ieee80211_mf_thread(ieee80211com_t *isc)
-{
- struct ieee80211_node *in;
- uint32_t scan_ticks = 0;
- uint32_t ratectl_ticks = 0;
- uint32_t cali_ticks = 0;
- uint32_t mgt_ticks = 0;
- enum ieee80211_state ostate = IEEE80211_S_INIT;
-
- mutex_enter(&isc->isc_genlock);
- while (isc->isc_mfthread_switch) {
- if (isc->isc_state == IEEE80211_S_SCAN &&
- ostate != IEEE80211_S_SCAN)
- scan_ticks = 0;
-
- if (isc->isc_state == IEEE80211_S_SCAN) {
- if (scan_ticks >= (isc->isc_scan_interval/100 - 1)) {
- ieee80211_next_scan(isc);
- scan_ticks = 0;
- } else
- scan_ticks++;
- }
-
- if (ratectl_ticks >= (isc->isc_ratectl_interval/100 - 1)) {
- if (isc->isc_opmode == IEEE80211_M_STA)
- (*isc->isc_rate_ctl)(isc, isc->isc_bss);
- else {
- in = list_head(&isc->isc_in_list);
- while (in != NULL) {
- (*isc->isc_rate_ctl)(isc, in);
- in = list_next(&isc->isc_in_list, in);
- }
- }
- ratectl_ticks = 0;
- } else
- ratectl_ticks++;
-
- if (cali_ticks >= (isc->isc_cali_interval/100 - 1)) {
- (*isc->isc_calibrate)(isc);
- cali_ticks = 0;
- } else
- cali_ticks++;
-
- if (mgt_ticks >= 10) { /* one second */
- if (isc->isc_mgt_timeout &&
- --isc->isc_mgt_timeout == 0) {
- (void) _ieee80211_new_state(isc,
- IEEE80211_S_SCAN, -1);
- }
- if (isc->isc_inact_timeout &&
- --isc->isc_inact_timeout == 0)
- ieee80211_timeout_nodes(isc);
- mgt_ticks = 0;
- } else
- mgt_ticks++;
-
- ostate = isc->isc_state;
- mutex_exit(&isc->isc_genlock);
- delay(drv_usectohz(100000)); /* delay 100ms */
- mutex_enter(&isc->isc_genlock);
- }
- isc->isc_mf_thread = NULL;
- cv_broadcast(&isc->isc_mfthread_cv);
- mutex_exit(&isc->isc_genlock);
- thread_exit();
-}
-
-/*
- * This function is responsible for creating multi-func thread.
- */
-static int32_t
-ieee80211_gld_start(gld_mac_info_t *gld_p)
-{
- int32_t result;
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
-
- mutex_enter(&isc->isc_genlock);
- isc->isc_mfthread_switch = 1;
- if (isc->isc_mf_thread == NULL)
- isc->isc_mf_thread = thread_create((caddr_t)NULL, 0,
- ieee80211_mf_thread, isc, 0, &p0, TS_RUN, minclsyspri);
- result = (*isc->isc_gld_start)(gld_p);
- mutex_exit(&isc->isc_genlock);
- return (result);
-}
-
-/*
- * This function is responsible for destory multi-func thread.
- */
-static int32_t
-ieee80211_gld_stop(gld_mac_info_t *gld_p)
-{
- int32_t result;
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
-
- mutex_enter(&isc->isc_genlock);
- isc->isc_mfthread_switch = 0;
- while (isc->isc_mf_thread != NULL) {
- if (cv_wait_sig(&isc->isc_mfthread_cv, &isc->isc_genlock) == 0)
- break;
- }
- result = (*isc->isc_gld_stop)(gld_p);
- mutex_exit(&isc->isc_genlock);
- return (result);
-}
-
-static int32_t
-ieee80211_gld_saddr(gld_mac_info_t *gld_p, uint8_t *macaddr)
-{
- int32_t result;
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
-
- mutex_enter(&isc->isc_genlock);
- result = (*isc->isc_gld_saddr)(gld_p, macaddr);
- mutex_exit(&isc->isc_genlock);
- return (result);
-}
-
-static int
-ieee80211_gld_set_promiscuous(gld_mac_info_t *gld_p, int mode)
-{
- int result;
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
-
- mutex_enter(&isc->isc_genlock);
- result = (*isc->isc_gld_set_promiscuous)(gld_p, mode);
- mutex_exit(&isc->isc_genlock);
- return (result);
-}
-
-static int32_t
-ieee80211_gld_gstat(gld_mac_info_t *gld_p, struct gld_stats *glds_p)
-{
- int32_t result;
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
-
- mutex_enter(&isc->isc_genlock);
- result = (*isc->isc_gld_gstat)(gld_p, glds_p);
- mutex_exit(&isc->isc_genlock);
- return (result);
-}
-
-static int32_t
-ieee80211_gld_ioctl(gld_mac_info_t *gld_p, queue_t *wq, mblk_t *mp)
-{
- int32_t result;
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
-
- mutex_enter(&isc->isc_genlock);
- result = (*isc->isc_gld_ioctl)(gld_p, wq, mp);
- mutex_exit(&isc->isc_genlock);
- return (result);
-}
-
-static int
-ieee80211_gld_set_multicast(gld_mac_info_t *gld_p, uint8_t *eth_p, int flag)
-{
- int result;
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
-
- mutex_enter(&isc->isc_genlock);
- result = (*isc->isc_gld_set_multicast)(gld_p, eth_p, flag);
- mutex_exit(&isc->isc_genlock);
- return (result);
-}
-
-static uint32_t
-ieee80211_gld_intr(gld_mac_info_t *gld_p)
-{
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
- return ((*isc->isc_gld_intr)(gld_p));
-}
-
-
-
-int32_t
-ieee80211_ifattach(gld_mac_info_t *gld_p)
-{
- ieee80211com_t *isc =
- (ieee80211com_t *)gld_p->gldm_private;
- struct ieee80211channel *ch;
- int32_t i;
-
- mutex_init(&isc->isc_genlock, NULL, MUTEX_DRIVER, NULL);
-
- /*
- * Fill in 802.11 available channel set, mark
- * all available channels as active, and pick
- * a default channel if not already specified.
- */
- bzero(isc->isc_chan_avail, sizeof (isc->isc_chan_avail));
- isc->isc_modecaps |= 1 << IEEE80211_MODE_AUTO;
- for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
- ch = &isc->isc_channels[i];
- if (ch->ich_flags) {
- setbit(isc->isc_chan_avail, i);
- /*
- * Identify mode capabilities.
- */
- if (IEEE80211_IS_CHAN_A(ch))
- isc->isc_modecaps |= 1 << IEEE80211_MODE_11A;
- if (IEEE80211_IS_CHAN_B(ch))
- isc->isc_modecaps |= 1 << IEEE80211_MODE_11B;
- if (IEEE80211_IS_CHAN_PUREG(ch))
- isc->isc_modecaps |= 1 << IEEE80211_MODE_11G;
- if (IEEE80211_IS_CHAN_T(ch))
- isc->isc_modecaps |= 1 << IEEE80211_MODE_TURBO;
- }
- }
-
- /* Start from auto mode */
- (void) ieee80211_setmode(isc, IEEE80211_MODE_AUTO);
-
- /* Initialize WEP related variable */
- isc->isc_wep_txkey = 0;
- isc->isc_iv = (int32_t)(gethrtime() & 0x00000000ffffffff);
-
- /* Initialize some config variables */
- isc->isc_rtsthreshold = IEEE80211_RTS_MAX;
- isc->isc_fragthreshold = 2346;
- isc->isc_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */
- isc->isc_fixed_rate = -1; /* no fixed rate */
- if (isc->isc_lintval == 0)
- isc->isc_lintval = 100; /* default sleep */
- isc->isc_txpower = IEEE80211_TXPOWER_MAX; /* default tx power */
- isc->isc_bmisstimeout = 7 * isc->isc_lintval; /* default 7 beacons */
-
- list_create(&isc->isc_in_list,
- sizeof (struct ieee80211_node),
- offsetof(struct ieee80211_node, in_node));
- for (i = 0; i < IEEE80211_NODE_HASHSIZE; i++)
- list_create(&isc->isc_inhash_list[i],
- sizeof (struct ieee80211_node),
- offsetof(struct ieee80211_node, in_hash_node));
-
- /* Initialize management frame handlers */
- isc->isc_recv_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_RESP
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_beacon;
- isc->isc_recv_mgmt[IEEE80211_FC0_SUBTYPE_BEACON
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_beacon;
- isc->isc_recv_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_REQ
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_prreq;
- isc->isc_recv_mgmt[IEEE80211_FC0_SUBTYPE_AUTH
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_auth;
- isc->isc_recv_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_REQ
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asreq;
- isc->isc_recv_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_REQ
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asreq;
- isc->isc_recv_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_RESP
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asresp;
- isc->isc_recv_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_RESP
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asresp;
- isc->isc_recv_mgmt[IEEE80211_FC0_SUBTYPE_DEAUTH
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_deauth;
- isc->isc_recv_mgmt[IEEE80211_FC0_SUBTYPE_DISASSOC
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_disassoc;
-
- isc->isc_send_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_REQ
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_prreq;
- isc->isc_send_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_RESP
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_prresp;
- isc->isc_send_mgmt[IEEE80211_FC0_SUBTYPE_AUTH
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_auth;
- isc->isc_send_mgmt[IEEE80211_FC0_SUBTYPE_DEAUTH
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_deauth;
- isc->isc_send_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_REQ
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asreq;
- isc->isc_send_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_REQ
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asreq;
- isc->isc_send_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_RESP
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asresp;
- isc->isc_send_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_RESP
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asresp;
- isc->isc_send_mgmt[IEEE80211_FC0_SUBTYPE_DISASSOC
- >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_disassoc;
-
- cv_init(&isc->isc_scan_cv, NULL, CV_DRIVER, NULL);
- cv_init(&isc->isc_mfthread_cv, NULL, CV_DRIVER, NULL);
- isc->isc_mf_thread = NULL;
- isc->isc_mfthread_switch = 0;
-
- ASSERT(isc->isc_node_alloc != NULL);
- isc->isc_bss = (*isc->isc_node_alloc)(isc);
- isc->isc_bss->in_chan = IEEE80211_CHAN_ANYC;
- isc->isc_bss->in_txpower = IEEE80211_TXPOWER_MAX;
- isc->isc_scan_interval = 200;
- isc->isc_cali_interval = 30000;
- isc->isc_ratectl_interval = 500;
-
- gld_p->gldm_reset = ieee80211_gld_reset;
- gld_p->gldm_start = ieee80211_gld_start;
- gld_p->gldm_stop = ieee80211_gld_stop;
- gld_p->gldm_set_mac_addr = ieee80211_gld_saddr;
- gld_p->gldm_send = ieee80211_gld_send;
- gld_p->gldm_set_promiscuous = ieee80211_gld_set_promiscuous;
- gld_p->gldm_get_stats = ieee80211_gld_gstat;
- gld_p->gldm_ioctl = ieee80211_gld_ioctl;
- gld_p->gldm_set_multicast = ieee80211_gld_set_multicast;
- gld_p->gldm_intr = ieee80211_gld_intr;
-
- return (0);
-}
-
-void
-ieee80211_ifdetach(gld_mac_info_t *gld_p)
-{
- ieee80211com_t *isc = (ieee80211com_t *)gld_p->gldm_private;
-
- (*isc->isc_node_free)(isc, isc->isc_bss);
- ieee80211_free_allnodes(isc);
- cv_destroy(&isc->isc_mfthread_cv);
- cv_destroy(&isc->isc_scan_cv);
- mutex_destroy(&isc->isc_genlock);
-}