/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
*/
/*
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2008 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.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* IEEE 802.11 protocol support
*/
#include "net80211_impl.h"
/* tunables */
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"
};
const char *ieee80211_ctl_subtype_name[] = {
"reserved#0", "reserved#1", "reserved#2", "reserved#3",
"reserved#3", "reserved#5", "reserved#6", "reserved#7",
"reserved#8", "reserved#9", "ps_poll", "rts",
"cts", "ack", "cf_end", "cf_end_ack"
};
"INIT", /* IEEE80211_S_INIT */
"SCAN", /* IEEE80211_S_SCAN */
"AUTH", /* IEEE80211_S_AUTH */
"ASSOC", /* IEEE80211_S_ASSOC */
"RUN" /* IEEE80211_S_RUN */
};
const char *ieee80211_wme_acnames[] = {
"WME_AC_BE",
"WME_AC_BK",
"WME_AC_VI",
"WME_AC_VO",
"WME_UPSD",
};
/*
* Initialize the interface softc, ic, with protocol management
* related data structures and functions.
*/
void
{
/* protocol state change handler */
/* initialize management frame handlers */
}
/*
* Print a 802.11 frame header
*/
void
{
int i;
case IEEE80211_FC1_DIR_NODS:
break;
case IEEE80211_FC1_DIR_TODS:
break;
case IEEE80211_FC1_DIR_FROMDS:
break;
case IEEE80211_FC1_DIR_DSTODS:
break;
}
case IEEE80211_FC0_TYPE_DATA:
break;
case IEEE80211_FC0_TYPE_MGT:
break;
default:
break;
}
}
if (rate >= 0) {
}
if (rssi >= 0) {
}
if (len > 0) {
if ((i & 0x03) == 0)
}
buf1);
}
}
/*
*
* in node
* flag IEEE80211_F_DOSORT : sort the node's rate table
* IEEE80211_F_DONEGO : mark a rate as basic rate if it is
* a device's basic rate
* IEEE80211_F_DODEL : delete rates not supported by the device
* IEEE80211_F_DOFRATE: check if the fixed rate is supported by
* the device
*
* The highest bit of returned rate value is set to 1 on failure.
*/
int
{
int i;
int okrate;
int badrate;
int fixedrate;
uint8_t r;
/*
* If the fixed rate check was requested but no
* fixed has been defined then just remove it.
*/
if ((flags & IEEE80211_F_DOFRATE) &&
flags &= ~IEEE80211_F_DOFRATE;
}
return (IEEE80211_RATE_BASIC);
}
int j;
if (flags & IEEE80211_F_DOSORT) {
/*
* Sort rates.
*/
}
}
}
badrate = r;
/*
* Check against supported rates.
*/
/*
* Overwrite with the supported rate
* value so any basic rate bit is set.
* This insures that response we send
* to stations have the necessary basic
* rate bit set.
*/
if (flags & IEEE80211_F_DONEGO)
break;
}
}
/*
* A rate in the node's rate set is not
* Note that this is important for 11b stations
* when they want to associate with an 11g AP.
*/
}
if (flags & IEEE80211_F_DODEL) {
/*
* Delete unacceptable rates.
*/
if (ignore) {
continue;
}
}
if (flags & IEEE80211_F_DOFRATE) {
/*
* Check any fixed rate is included.
*/
if (r == ic->ic_fixed_rate)
fixedrate = r;
}
if (!ignore)
i++;
}
return (badrate | IEEE80211_RATE_BASIC);
else
return (IEEE80211_RV(okrate));
}
/*
* Reset 11g-related state.
*/
void
{
/*
* Short slot time is enabled only when operating in 11g
* and not in an IBSS. We must also honor whether or not
* the driver is capable of doing it.
*/
/*
* Set short preamble and ERP barker-preamble flags.
*/
} else {
}
}
/*
* Change current channel to be the next available channel
*/
void
{
do {
break;
}
}
/*
* Set the short slot time state and notify the driver.
*/
void
{
if (on)
else
/* notify driver */
}
/*
* 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.
*/
void
enum ieee80211_phymode mode)
{
{ 0 }, /* IEEE80211_MODE_AUTO */
{ 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */
{ 2, { 2, 4} }, /* IEEE80211_MODE_11B */
{ 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G mixed b/g */
{ 0 }, /* IEEE80211_MODE_FH */
{ 3, { 12, 24, 48 } }, /* IEEE80211_MODE_TURBO_A */
{ 4, { 2, 4, 11, 22 } },
/* IEEE80211_MODE_TURBO_G (mixed b/g) */
{ 0 }, /* IEEE80211_MODE_STURBO_A */
{ 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11NA */
/* IEEE80211_MODE_11NG (mixed b/g) */
{ 7, { 2, 4, 11, 22, 12, 24, 48 } }
};
int i, j;
break;
}
}
}
}
/*
* WME protocol support. The following parameters come from the spec.
*/
typedef struct phyParamType {
} paramType;
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_AUTO */
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11A */
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11B */
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11G */
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_FH */
{ 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11NA */
{ 3, 4, 6, 0, 0 } /* IEEE80211_MODE_11NG */
};
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_AUTO */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11A */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11B */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11G */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_FH */
{ 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NA */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NG */
};
{ 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_AUTO */
{ 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11A */
{ 1, 3, 4, 188, 0 }, /* IEEE80211_MODE_11B */
{ 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11G */
{ 1, 3, 4, 188, 0 }, /* IEEE80211_MODE_FH */
{ 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NA */
{ 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NG */
};
{ 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_AUTO */
{ 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11A */
{ 1, 2, 3, 102, 0 }, /* IEEE80211_MODE_11B */
{ 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11G */
{ 1, 2, 3, 102, 0 }, /* IEEE80211_MODE_FH */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NA */
{ 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NG */
};
{ 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_AUTO */
{ 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11A */
{ 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11B */
{ 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11G */
{ 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_FH */
{ 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NA */
{ 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NG */
};
{ 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_AUTO */
{ 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11A */
{ 2, 3, 4, 188, 0 }, /* IEEE80211_MODE_11B */
{ 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11G */
{ 2, 3, 4, 188, 0 }, /* IEEE80211_MODE_FH */
{ 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NA */
{ 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NG */
};
{ 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_AUTO */
{ 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11A */
{ 2, 2, 3, 102, 0 }, /* IEEE80211_MODE_11B */
{ 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11G */
{ 2, 2, 3, 102, 0 }, /* IEEE80211_MODE_FH */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NA */
{ 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NG */
};
void
{
int i;
return;
/*
* Select mode; we can be called early in which case we
* always use auto mode. We know we'll be called when
* entering the RUN state with bsschan setup properly
* so state will eventually get set correctly
*/
else
for (i = 0; i < WME_NUM_AC; i++) {
switch (i) {
case WME_AC_BK:
break;
case WME_AC_VI:
break;
case WME_AC_VO:
break;
case WME_AC_BE:
default:
break;
}
} else {
}
"%s chan [acm %u aifsn %u log2(cwmin) %u "
"log2(cwmax) %u txpoLimit %u]\n",
"%s bss [acm %u aifsn %u log2(cwmin) %u "
"log2(cwmax) %u txpoLimit %u]\n",
}
/* NB: check ic_bss to avoid NULL deref on initial attach */
/*
* Calculate agressive mode switching threshold based
* on beacon interval. This doesn't need locking since
* we're only called before entering the RUN state at
* which point we start sending beacon frames.
*/
}
}
/*
* Update WME parameters for ourself and the BSS.
*/
void
{
{ 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_AUTO */
{ 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11A */
{ 2, 5, 10, 64, 0 }, /* IEEE80211_MODE_11B */
{ 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11G */
{ 2, 5, 10, 64, 0 }, /* IEEE80211_MODE_FH */
{ 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11NA */
{ 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11NG */
};
int i;
return;
/* set up the channel access parameters for the physical device */
for (i = 0; i < WME_NUM_AC; i++) {
}
/*
* Select mode; we can be called early in which case we
* always use auto mode. We know we'll be called when
* entering the RUN state with bsschan setup properly
* so state will eventually get set correctly
*/
else
/*
* This implements agressive mode as found in certain
* vendors' AP's. When there is significant high
* traffic by using conservative parameters. Otherwise
* BE uses agressive params to optimize performance of
*/
"ieee80211_wme_updateparams_locked: "
"%s [acm %u aifsn %u log2(cwmin) %u "
"log2(cwmax) %u txpoLimit %u]\n",
}
"WME params updated, cap_info 0x%x\n",
}
/*
* Process STA mode beacon miss events. Send a direct probe request
* frame to the current ap bmiss_max times (w/o answer) before
* scanning for a new ap.
*/
void
{
return;
"%s\n", "beacon miss");
/*
* Our handling is only meaningful for stations that are
* associated; any other conditions else will be handled
* through different means (e.g. the tx timeout on mgt frames).
*/
return;
}
/*
* Send a directed probe req before falling back to a scan;
* if we receive a response ic_bmiss_count will be reset.
* Some cards mistakenly report beacon miss so this avoids
* the expensive scan if the ap is still there.
*/
return;
}
im->im_bmiss_count = 0;
}
/*
* Manage state transition between INIT | AUTH | ASSOC | RUN.
*/
static int
{
"%s -> %s\n",
switch (nstate) {
case IEEE80211_S_INIT:
switch (ostate) {
case IEEE80211_S_INIT:
return (0);
case IEEE80211_S_SCAN:
break;
case IEEE80211_S_AUTH:
break;
case IEEE80211_S_ASSOC:
}
break;
case IEEE80211_S_RUN:
case IEEE80211_M_STA:
break;
case IEEE80211_M_IBSS:
break;
default:
break;
}
break;
}
im->im_mgt_timer = 0;
break;
case IEEE80211_S_SCAN:
switch (ostate) {
case IEEE80211_S_INIT:
return (0);
case IEEE80211_S_SCAN:
/*
* Scan next. If doing an active scan and the
* channel is not marked passive-only then send
* a probe request. Otherwise just listen for
* beacons on the channel.
*/
(void) ieee80211_send_probereq(in,
return (0);
}
break;
case IEEE80211_S_RUN:
/* beacon miss */
"no recent beacons from %s, rescanning\n",
/* FALLTHRU */
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
/* timeout restart scan */
}
break;
}
break;
case IEEE80211_S_AUTH:
switch (ostate) {
case IEEE80211_S_INIT:
case IEEE80211_S_SCAN:
1);
return (0);
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
switch (arg) {
return (0);
/* ignore and retry scan on timeout */
break;
}
break;
case IEEE80211_S_RUN:
switch (arg) {
return (0);
/* try to re-auth */
return (0);
}
break;
}
break;
case IEEE80211_S_ASSOC:
switch (ostate) {
case IEEE80211_S_INIT:
case IEEE80211_S_SCAN:
case IEEE80211_S_ASSOC:
"invalid transition\n");
break;
case IEEE80211_S_AUTH:
return (0);
case IEEE80211_S_RUN:
return (0);
}
break;
case IEEE80211_S_RUN:
switch (ostate) {
case IEEE80211_S_INIT:
ieee80211_err("ieee80211_newstate: "
"invalid transition\n");
break;
case IEEE80211_S_AUTH:
ieee80211_err("ieee80211_newstate: "
"invalid transition\n");
break;
case IEEE80211_S_SCAN: /* adhoc/hostap mode */
case IEEE80211_S_ASSOC: /* infra mode */
im->im_mgt_timer = 0;
/*
* We can send data now; update the fastpath with our
* current associated BSSID and other relevant settings.
*/
sizeof (uint32_t));
}
}
break;
}
/*
* When 802.1x is not in use mark the port authorized
* at this point so traffic can flow.
*/
/*
* Enable inactivity processing.
*/
break; /* IEEE80211_S_RUN */
} /* switch nstate */
return (0);
}