Index: head/sys/net80211/_ieee80211.h =================================================================== --- head/sys/net80211/_ieee80211.h (revision 288244) +++ head/sys/net80211/_ieee80211.h (revision 288245) @@ -1,405 +1,404 @@ /*- * 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 * documentation and/or other materials provided with the distribution. * * 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. * * $FreeBSD$ */ #ifndef _NET80211__IEEE80211_H_ #define _NET80211__IEEE80211_H_ /* * 802.11 implementation definitions. * * NB: this file is used by applications. */ /* * PHY type; mostly used to identify FH phys. */ enum ieee80211_phytype { IEEE80211_T_DS, /* direct sequence spread spectrum */ IEEE80211_T_FH, /* frequency hopping */ IEEE80211_T_OFDM, /* frequency division multiplexing */ IEEE80211_T_TURBO, /* high rate OFDM, aka turbo mode */ IEEE80211_T_HT, /* high throughput */ IEEE80211_T_OFDM_HALF, /* 1/2 rate OFDM */ IEEE80211_T_OFDM_QUARTER, /* 1/4 rate OFDM */ }; #define IEEE80211_T_CCK IEEE80211_T_DS /* more common nomenclature */ /* * PHY mode; this is not really a mode as multi-mode devices * have multiple PHY's. Mode is mostly used as a shorthand * for constraining which channels to consider in setting up * operation. Modes used to be used more extensively when * channels were identified as IEEE channel numbers. */ enum ieee80211_phymode { IEEE80211_MODE_AUTO = 0, /* autoselect */ IEEE80211_MODE_11A = 1, /* 5GHz, OFDM */ IEEE80211_MODE_11B = 2, /* 2GHz, CCK */ IEEE80211_MODE_11G = 3, /* 2GHz, OFDM */ IEEE80211_MODE_FH = 4, /* 2GHz, GFSK */ IEEE80211_MODE_TURBO_A = 5, /* 5GHz, OFDM, 2x clock */ IEEE80211_MODE_TURBO_G = 6, /* 2GHz, OFDM, 2x clock */ IEEE80211_MODE_STURBO_A = 7, /* 5GHz, OFDM, 2x clock, static */ IEEE80211_MODE_11NA = 8, /* 5GHz, w/ HT */ IEEE80211_MODE_11NG = 9, /* 2GHz, w/ HT */ IEEE80211_MODE_HALF = 10, /* OFDM, 1/2x clock */ IEEE80211_MODE_QUARTER = 11, /* OFDM, 1/4x clock */ }; #define IEEE80211_MODE_MAX (IEEE80211_MODE_QUARTER+1) /* * Operating mode. Devices do not necessarily support * all modes; they indicate which are supported in their * capabilities. */ enum ieee80211_opmode { IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */ IEEE80211_M_STA = 1, /* infrastructure station */ IEEE80211_M_WDS = 2, /* WDS link */ IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */ IEEE80211_M_HOSTAP = 4, /* Software Access Point */ IEEE80211_M_MONITOR = 5, /* Monitor mode */ IEEE80211_M_MBSS = 6, /* MBSS (Mesh Point) link */ }; #define IEEE80211_OPMODE_MAX (IEEE80211_M_MBSS+1) /* * 802.11g/802.11n protection mode. */ enum ieee80211_protmode { IEEE80211_PROT_NONE = 0, /* no protection */ IEEE80211_PROT_CTSONLY = 1, /* CTS to self */ IEEE80211_PROT_RTSCTS = 2, /* RTS-CTS */ }; /* * Authentication mode. The open and shared key authentication * modes are implemented within the 802.11 layer. 802.1x and * WPA/802.11i are implemented in user mode by setting the * 802.11 layer into IEEE80211_AUTH_8021X and deferring * authentication to user space programs. */ enum ieee80211_authmode { IEEE80211_AUTH_NONE = 0, IEEE80211_AUTH_OPEN = 1, /* open */ IEEE80211_AUTH_SHARED = 2, /* shared-key */ IEEE80211_AUTH_8021X = 3, /* 802.1x */ IEEE80211_AUTH_AUTO = 4, /* auto-select/accept */ /* NB: these are used only for ioctls */ IEEE80211_AUTH_WPA = 5, /* WPA/RSN w/ 802.1x/PSK */ }; /* * Roaming mode is effectively who controls the operation * of the 802.11 state machine when operating as a station. * State transitions are controlled either by the driver * (typically when management frames are processed by the * hardware/firmware), the host (auto/normal operation of * the 802.11 layer), or explicitly through ioctl requests * when applications like wpa_supplicant want control. */ enum ieee80211_roamingmode { IEEE80211_ROAMING_DEVICE= 0, /* driver/hardware control */ IEEE80211_ROAMING_AUTO = 1, /* 802.11 layer control */ IEEE80211_ROAMING_MANUAL= 2, /* application control */ }; /* * Channels are specified by frequency and attributes. */ struct ieee80211_channel { uint32_t ic_flags; /* see below */ uint16_t ic_freq; /* setting in MHz */ uint8_t ic_ieee; /* IEEE channel number */ int8_t ic_maxregpower; /* maximum regulatory tx power in dBm */ int8_t ic_maxpower; /* maximum tx power in .5 dBm */ int8_t ic_minpower; /* minimum tx power in .5 dBm */ uint8_t ic_state; /* dynamic state */ uint8_t ic_extieee; /* HT40 extension channel number */ int8_t ic_maxantgain; /* maximum antenna gain in .5 dBm */ uint8_t ic_pad; uint16_t ic_devdata; /* opaque device/driver data */ }; #define IEEE80211_CHAN_MAX 256 #define IEEE80211_CHAN_BYTES 32 /* howmany(IEEE80211_CHAN_MAX, NBBY) */ #define IEEE80211_CHAN_ANY 0xffff /* token for ``any channel'' */ #define IEEE80211_CHAN_ANYC \ ((struct ieee80211_channel *) IEEE80211_CHAN_ANY) /* channel attributes */ #define IEEE80211_CHAN_PRIV0 0x00000001 /* driver private bit 0 */ #define IEEE80211_CHAN_PRIV1 0x00000002 /* driver private bit 1 */ #define IEEE80211_CHAN_PRIV2 0x00000004 /* driver private bit 2 */ #define IEEE80211_CHAN_PRIV3 0x00000008 /* driver private bit 3 */ #define IEEE80211_CHAN_TURBO 0x00000010 /* Turbo channel */ #define IEEE80211_CHAN_CCK 0x00000020 /* CCK channel */ #define IEEE80211_CHAN_OFDM 0x00000040 /* OFDM channel */ #define IEEE80211_CHAN_2GHZ 0x00000080 /* 2 GHz spectrum channel. */ #define IEEE80211_CHAN_5GHZ 0x00000100 /* 5 GHz spectrum channel */ #define IEEE80211_CHAN_PASSIVE 0x00000200 /* Only passive scan allowed */ #define IEEE80211_CHAN_DYN 0x00000400 /* Dynamic CCK-OFDM channel */ #define IEEE80211_CHAN_GFSK 0x00000800 /* GFSK channel (FHSS PHY) */ #define IEEE80211_CHAN_GSM 0x00001000 /* 900 MHz spectrum channel */ #define IEEE80211_CHAN_STURBO 0x00002000 /* 11a static turbo channel only */ #define IEEE80211_CHAN_HALF 0x00004000 /* Half rate channel */ #define IEEE80211_CHAN_QUARTER 0x00008000 /* Quarter rate channel */ #define IEEE80211_CHAN_HT20 0x00010000 /* HT 20 channel */ #define IEEE80211_CHAN_HT40U 0x00020000 /* HT 40 channel w/ ext above */ #define IEEE80211_CHAN_HT40D 0x00040000 /* HT 40 channel w/ ext below */ #define IEEE80211_CHAN_DFS 0x00080000 /* DFS required */ #define IEEE80211_CHAN_4MSXMIT 0x00100000 /* 4ms limit on frame length */ #define IEEE80211_CHAN_NOADHOC 0x00200000 /* adhoc mode not allowed */ #define IEEE80211_CHAN_NOHOSTAP 0x00400000 /* hostap mode not allowed */ #define IEEE80211_CHAN_11D 0x00800000 /* 802.11d required */ #define IEEE80211_CHAN_HT40 (IEEE80211_CHAN_HT40U | IEEE80211_CHAN_HT40D) #define IEEE80211_CHAN_HT (IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40) #define IEEE80211_CHAN_BITS \ "\20\1PRIV0\2PRIV2\3PRIV3\4PRIV4\5TURBO\6CCK\7OFDM\0102GHZ\0115GHZ" \ "\12PASSIVE\13DYN\14GFSK\15GSM\16STURBO\17HALF\20QUARTER\21HT20" \ "\22HT40U\23HT40D\24DFS\0254MSXMIT\26NOADHOC\27NOHOSTAP\03011D" /* * Useful combinations of channel characteristics. */ #define IEEE80211_CHAN_FHSS \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK) #define IEEE80211_CHAN_A \ (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) #define IEEE80211_CHAN_B \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) #define IEEE80211_CHAN_PUREG \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) #define IEEE80211_CHAN_G \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) #define IEEE80211_CHAN_108A \ (IEEE80211_CHAN_A | IEEE80211_CHAN_TURBO) #define IEEE80211_CHAN_108G \ (IEEE80211_CHAN_PUREG | IEEE80211_CHAN_TURBO) #define IEEE80211_CHAN_ST \ (IEEE80211_CHAN_108A | IEEE80211_CHAN_STURBO) #define IEEE80211_CHAN_ALL \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_GFSK | \ IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | \ IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER | \ IEEE80211_CHAN_HT) #define IEEE80211_CHAN_ALLTURBO \ (IEEE80211_CHAN_ALL | IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO) #define IEEE80211_IS_CHAN_FHSS(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS) #define IEEE80211_IS_CHAN_A(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) #define IEEE80211_IS_CHAN_B(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) #define IEEE80211_IS_CHAN_PUREG(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG) #define IEEE80211_IS_CHAN_G(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) #define IEEE80211_IS_CHAN_ANYG(_c) \ (IEEE80211_IS_CHAN_PUREG(_c) || IEEE80211_IS_CHAN_G(_c)) #define IEEE80211_IS_CHAN_ST(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST) #define IEEE80211_IS_CHAN_108A(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A) #define IEEE80211_IS_CHAN_108G(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G) #define IEEE80211_IS_CHAN_2GHZ(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0) #define IEEE80211_IS_CHAN_5GHZ(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_5GHZ) != 0) #define IEEE80211_IS_CHAN_PASSIVE(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE) != 0) #define IEEE80211_IS_CHAN_OFDM(_c) \ (((_c)->ic_flags & (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN)) != 0) #define IEEE80211_IS_CHAN_CCK(_c) \ (((_c)->ic_flags & (IEEE80211_CHAN_CCK | IEEE80211_CHAN_DYN)) != 0) #define IEEE80211_IS_CHAN_DYN(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_DYN) == IEEE80211_CHAN_DYN) #define IEEE80211_IS_CHAN_GFSK(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_GFSK) != 0) #define IEEE80211_IS_CHAN_TURBO(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_TURBO) != 0) #define IEEE80211_IS_CHAN_STURBO(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_STURBO) != 0) #define IEEE80211_IS_CHAN_DTURBO(_c) \ (((_c)->ic_flags & \ (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)) == IEEE80211_CHAN_TURBO) #define IEEE80211_IS_CHAN_HALF(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HALF) != 0) #define IEEE80211_IS_CHAN_QUARTER(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_QUARTER) != 0) #define IEEE80211_IS_CHAN_FULL(_c) \ (((_c)->ic_flags & (IEEE80211_CHAN_QUARTER | IEEE80211_CHAN_HALF)) == 0) #define IEEE80211_IS_CHAN_GSM(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_GSM) != 0) #define IEEE80211_IS_CHAN_HT(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT) != 0) #define IEEE80211_IS_CHAN_HT20(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT20) != 0) #define IEEE80211_IS_CHAN_HT40(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT40) != 0) #define IEEE80211_IS_CHAN_HT40U(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT40U) != 0) #define IEEE80211_IS_CHAN_HT40D(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT40D) != 0) #define IEEE80211_IS_CHAN_HTA(_c) \ (IEEE80211_IS_CHAN_5GHZ(_c) && \ ((_c)->ic_flags & IEEE80211_CHAN_HT) != 0) #define IEEE80211_IS_CHAN_HTG(_c) \ (IEEE80211_IS_CHAN_2GHZ(_c) && \ ((_c)->ic_flags & IEEE80211_CHAN_HT) != 0) #define IEEE80211_IS_CHAN_DFS(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_DFS) != 0) #define IEEE80211_IS_CHAN_NOADHOC(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_NOADHOC) != 0) #define IEEE80211_IS_CHAN_NOHOSTAP(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_NOHOSTAP) != 0) #define IEEE80211_IS_CHAN_11D(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_11D) != 0) #define IEEE80211_CHAN2IEEE(_c) (_c)->ic_ieee /* dynamic state */ #define IEEE80211_CHANSTATE_RADAR 0x01 /* radar detected */ #define IEEE80211_CHANSTATE_CACDONE 0x02 /* CAC completed */ #define IEEE80211_CHANSTATE_CWINT 0x04 /* interference detected */ #define IEEE80211_CHANSTATE_NORADAR 0x10 /* post notify on radar clear */ #define IEEE80211_IS_CHAN_RADAR(_c) \ (((_c)->ic_state & IEEE80211_CHANSTATE_RADAR) != 0) #define IEEE80211_IS_CHAN_CACDONE(_c) \ (((_c)->ic_state & IEEE80211_CHANSTATE_CACDONE) != 0) #define IEEE80211_IS_CHAN_CWINT(_c) \ (((_c)->ic_state & IEEE80211_CHANSTATE_CWINT) != 0) /* ni_chan encoding for FH phy */ #define IEEE80211_FH_CHANMOD 80 #define IEEE80211_FH_CHAN(set,pat) (((set)-1)*IEEE80211_FH_CHANMOD+(pat)) #define IEEE80211_FH_CHANSET(chan) ((chan)/IEEE80211_FH_CHANMOD+1) #define IEEE80211_FH_CHANPAT(chan) ((chan)%IEEE80211_FH_CHANMOD) #define IEEE80211_TID_SIZE (WME_NUM_TID+1) /* WME TID's +1 for non-QoS */ #define IEEE80211_NONQOS_TID WME_NUM_TID /* index for non-QoS sta */ /* * The 802.11 spec says at most 2007 stations may be * associated at once. For most AP's this is way more * than is feasible so we use a default of 128. This * number may be overridden by the driver and/or by * user configuration but may not be less than IEEE80211_AID_MIN. */ #define IEEE80211_AID_DEF 128 #define IEEE80211_AID_MIN 16 /* * 802.11 rate set. */ #define IEEE80211_RATE_SIZE 8 /* 802.11 standard */ #define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */ struct ieee80211_rateset { uint8_t rs_nrates; uint8_t rs_rates[IEEE80211_RATE_MAXSIZE]; }; /* * 802.11n variant of ieee80211_rateset. Instead of * legacy rates the entries are MCS rates. We define * the structure such that it can be used interchangeably * with an ieee80211_rateset (modulo structure size). */ #define IEEE80211_HTRATE_MAXSIZE 77 struct ieee80211_htrateset { uint8_t rs_nrates; uint8_t rs_rates[IEEE80211_HTRATE_MAXSIZE]; }; #define IEEE80211_RATE_MCS 0x80 /* * Per-mode transmit parameters/controls visible to user space. * These can be used to set fixed transmit rate for all operating * modes or on a per-client basis according to the capabilities * of the client (e.g. an 11b client associated to an 11g ap). * * MCS are distinguished from legacy rates by or'ing in 0x80. */ struct ieee80211_txparam { uint8_t ucastrate; /* ucast data rate (legacy/MCS|0x80) */ uint8_t mgmtrate; /* mgmt frame rate (legacy/MCS|0x80) */ uint8_t mcastrate; /* multicast rate (legacy/MCS|0x80) */ uint8_t maxretry; /* max unicast data retry count */ }; /* * Per-mode roaming state visible to user space. There are two * thresholds that control whether roaming is considered; when * either is exceeded the 802.11 layer will check the scan cache * for another AP. If the cache is stale then a scan may be * triggered. */ struct ieee80211_roamparam { int8_t rssi; /* rssi thresh (.5 dBm) */ uint8_t rate; /* tx rate thresh (.5 Mb/s or MCS) */ uint16_t pad; /* reserve */ }; /* * Regulatory Information. */ struct ieee80211_regdomain { uint16_t regdomain; /* SKU */ uint16_t country; /* ISO country code */ uint8_t location; /* I (indoor), O (outdoor), other */ uint8_t ecm; /* Extended Channel Mode */ char isocc[2]; /* country code string */ short pad[2]; }; /* * MIMO antenna/radio state. */ -#define IEEE80211_MAX_CHAINS 3 -#define IEEE80211_MAX_EVM_PILOTS 6 - /* * XXX This doesn't yet export both ctl/ext chain details + * XXX TODO: IEEE80211_MAX_CHAINS is defined in _freebsd.h, not here; + * figure out how to pull it in! */ struct ieee80211_mimo_info { - int8_t rssi[IEEE80211_MAX_CHAINS]; /* per-antenna rssi */ - int8_t noise[IEEE80211_MAX_CHAINS]; /* per-antenna noise floor */ + int8_t rssi[3]; /* per-antenna rssi */ + int8_t noise[3]; /* per-antenna noise floor */ uint8_t pad[2]; uint32_t evm[3]; /* EVM data */ }; #endif /* _NET80211__IEEE80211_H_ */ Index: head/sys/net80211/ieee80211_freebsd.c =================================================================== --- head/sys/net80211/ieee80211_freebsd.c (revision 288244) +++ head/sys/net80211/ieee80211_freebsd.c (revision 288245) @@ -1,873 +1,910 @@ /*- * Copyright (c) 2003-2009 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 * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); /* * IEEE 802.11 support (FreeBSD-specific code) */ #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters"); #ifdef IEEE80211_DEBUG int ieee80211_debug = 0; SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug, 0, "debugging printfs"); #endif static MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state"); static const char wlanname[] = "wlan"; static struct if_clone *wlan_cloner; static int wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params) { struct ieee80211_clone_params cp; struct ieee80211vap *vap; struct ieee80211com *ic; int error; error = copyin(params, &cp, sizeof(cp)); if (error) return error; ic = ieee80211_find_com(cp.icp_parent); if (ic == NULL) return ENXIO; if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) { ic_printf(ic, "%s: invalid opmode %d\n", __func__, cp.icp_opmode); return EINVAL; } if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) { ic_printf(ic, "%s mode not supported\n", ieee80211_opmode_name[cp.icp_opmode]); return EOPNOTSUPP; } if ((cp.icp_flags & IEEE80211_CLONE_TDMA) && #ifdef IEEE80211_SUPPORT_TDMA (ic->ic_caps & IEEE80211_C_TDMA) == 0 #else (1) #endif ) { ic_printf(ic, "TDMA not supported\n"); return EOPNOTSUPP; } vap = ic->ic_vap_create(ic, wlanname, unit, cp.icp_opmode, cp.icp_flags, cp.icp_bssid, cp.icp_flags & IEEE80211_CLONE_MACADDR ? cp.icp_macaddr : ic->ic_macaddr); return (vap == NULL ? EIO : 0); } static void wlan_clone_destroy(struct ifnet *ifp) { struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; ic->ic_vap_delete(vap); } void ieee80211_vap_destroy(struct ieee80211vap *vap) { CURVNET_SET(vap->iv_ifp->if_vnet); if_clone_destroyif(wlan_cloner, vap->iv_ifp); CURVNET_RESTORE(); } int ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS) { int msecs = ticks_to_msecs(*(int *)arg1); int error, t; error = sysctl_handle_int(oidp, &msecs, 0, req); if (error || !req->newptr) return error; t = msecs_to_ticks(msecs); *(int *)arg1 = (t < 1) ? 1 : t; return 0; } static int ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS) { int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT; int error; error = sysctl_handle_int(oidp, &inact, 0, req); if (error || !req->newptr) return error; *(int *)arg1 = inact / IEEE80211_INACT_WAIT; return 0; } static int ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS) { struct ieee80211com *ic = arg1; return SYSCTL_OUT_STR(req, ic->ic_name); } static int ieee80211_sysctl_radar(SYSCTL_HANDLER_ARGS) { struct ieee80211com *ic = arg1; int t = 0, error; error = sysctl_handle_int(oidp, &t, 0, req); if (error || !req->newptr) return error; IEEE80211_LOCK(ic); ieee80211_dfs_notify_radar(ic, ic->ic_curchan); IEEE80211_UNLOCK(ic); return 0; } void ieee80211_sysctl_attach(struct ieee80211com *ic) { } void ieee80211_sysctl_detach(struct ieee80211com *ic) { } void ieee80211_sysctl_vattach(struct ieee80211vap *vap) { struct ifnet *ifp = vap->iv_ifp; struct sysctl_ctx_list *ctx; struct sysctl_oid *oid; char num[14]; /* sufficient for 32 bits */ ctx = (struct sysctl_ctx_list *) IEEE80211_MALLOC(sizeof(struct sysctl_ctx_list), M_DEVBUF, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); if (ctx == NULL) { if_printf(ifp, "%s: cannot allocate sysctl context!\n", __func__); return; } sysctl_ctx_init(ctx); snprintf(num, sizeof(num), "%u", ifp->if_dunit); oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan), OID_AUTO, num, CTLFLAG_RD, NULL, ""); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "%parent", CTLTYPE_STRING | CTLFLAG_RD, vap->iv_ic, 0, ieee80211_sysctl_parent, "A", "parent device"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "driver_caps", CTLFLAG_RW, &vap->iv_caps, 0, "driver capabilities"); #ifdef IEEE80211_DEBUG vap->iv_debug = ieee80211_debug; SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "debug", CTLFLAG_RW, &vap->iv_debug, 0, "control debugging printfs"); #endif SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "bmiss_max", CTLFLAG_RW, &vap->iv_bmiss_max, 0, "consecutive beacon misses before scanning"); /* XXX inherit from tunables */ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "inact_run", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_run, 0, ieee80211_sysctl_inact, "I", "station inactivity timeout (sec)"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_probe, 0, ieee80211_sysctl_inact, "I", "station inactivity probe timeout (sec)"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_auth, 0, ieee80211_sysctl_inact, "I", "station authentication timeout (sec)"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "inact_init", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_init, 0, ieee80211_sysctl_inact, "I", "station initial state timeout (sec)"); if (vap->iv_htcaps & IEEE80211_HTC_HT) { SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "ampdu_mintraffic_bk", CTLFLAG_RW, &vap->iv_ampdu_mintraffic[WME_AC_BK], 0, "BK traffic tx aggr threshold (pps)"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "ampdu_mintraffic_be", CTLFLAG_RW, &vap->iv_ampdu_mintraffic[WME_AC_BE], 0, "BE traffic tx aggr threshold (pps)"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "ampdu_mintraffic_vo", CTLFLAG_RW, &vap->iv_ampdu_mintraffic[WME_AC_VO], 0, "VO traffic tx aggr threshold (pps)"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "ampdu_mintraffic_vi", CTLFLAG_RW, &vap->iv_ampdu_mintraffic[WME_AC_VI], 0, "VI traffic tx aggr threshold (pps)"); } if (vap->iv_caps & IEEE80211_C_DFS) { SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "radar", CTLTYPE_INT | CTLFLAG_RW, vap->iv_ic, 0, ieee80211_sysctl_radar, "I", "simulate radar event"); } vap->iv_sysctl = ctx; vap->iv_oid = oid; } void ieee80211_sysctl_vdetach(struct ieee80211vap *vap) { if (vap->iv_sysctl != NULL) { sysctl_ctx_free(vap->iv_sysctl); IEEE80211_FREE(vap->iv_sysctl, M_DEVBUF); vap->iv_sysctl = NULL; } } int ieee80211_node_dectestref(struct ieee80211_node *ni) { /* XXX need equivalent of atomic_dec_and_test */ atomic_subtract_int(&ni->ni_refcnt, 1); return atomic_cmpset_int(&ni->ni_refcnt, 0, 1); } void ieee80211_drain_ifq(struct ifqueue *ifq) { struct ieee80211_node *ni; struct mbuf *m; for (;;) { IF_DEQUEUE(ifq, m); if (m == NULL) break; ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; KASSERT(ni != NULL, ("frame w/o node")); ieee80211_free_node(ni); m->m_pkthdr.rcvif = NULL; m_freem(m); } } void ieee80211_flush_ifq(struct ifqueue *ifq, struct ieee80211vap *vap) { struct ieee80211_node *ni; struct mbuf *m, **mprev; IF_LOCK(ifq); mprev = &ifq->ifq_head; while ((m = *mprev) != NULL) { ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; if (ni != NULL && ni->ni_vap == vap) { *mprev = m->m_nextpkt; /* remove from list */ ifq->ifq_len--; m_freem(m); ieee80211_free_node(ni); /* reclaim ref */ } else mprev = &m->m_nextpkt; } /* recalculate tail ptr */ m = ifq->ifq_head; for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt) ; ifq->ifq_tail = m; IF_UNLOCK(ifq); } /* * As above, for mbufs allocated with m_gethdr/MGETHDR * or initialized by M_COPY_PKTHDR. */ #define MC_ALIGN(m, len) \ do { \ (m)->m_data += (MCLBYTES - (len)) &~ (sizeof(long) - 1); \ } while (/* CONSTCOND */ 0) /* * Allocate and setup a management frame of the specified * size. We return the mbuf and a pointer to the start * of the contiguous data area that's been reserved based * on the packet length. The data area is forced to 32-bit * alignment and the buffer length to a multiple of 4 bytes. * This is done mainly so beacon frames (that require this) * can use this interface too. */ struct mbuf * ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen) { struct mbuf *m; u_int len; /* * NB: we know the mbuf routines will align the data area * so we don't need to do anything special. */ len = roundup2(headroom + pktlen, 4); KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len)); if (len < MINCLSIZE) { m = m_gethdr(M_NOWAIT, MT_DATA); /* * Align the data in case additional headers are added. * This should only happen when a WEP header is added * which only happens for shared key authentication mgt * frames which all fit in MHLEN. */ if (m != NULL) M_ALIGN(m, len); } else { m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m != NULL) MC_ALIGN(m, len); } if (m != NULL) { m->m_data += headroom; *frm = m->m_data; } return m; } #ifndef __NO_STRICT_ALIGNMENT /* * Re-align the payload in the mbuf. This is mainly used (right now) * to handle IP header alignment requirements on certain architectures. */ struct mbuf * ieee80211_realign(struct ieee80211vap *vap, struct mbuf *m, size_t align) { int pktlen, space; struct mbuf *n; pktlen = m->m_pkthdr.len; space = pktlen + align; if (space < MINCLSIZE) n = m_gethdr(M_NOWAIT, MT_DATA); else { n = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, space <= MCLBYTES ? MCLBYTES : #if MJUMPAGESIZE != MCLBYTES space <= MJUMPAGESIZE ? MJUMPAGESIZE : #endif space <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES); } if (__predict_true(n != NULL)) { m_move_pkthdr(n, m); n->m_data = (caddr_t)(ALIGN(n->m_data + align) - align); m_copydata(m, 0, pktlen, mtod(n, caddr_t)); n->m_len = pktlen; } else { IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, mtod(m, const struct ieee80211_frame *), NULL, "%s", "no mbuf to realign"); vap->iv_stats.is_rx_badalign++; } m_freem(m); return n; } #endif /* !__NO_STRICT_ALIGNMENT */ int ieee80211_add_callback(struct mbuf *m, void (*func)(struct ieee80211_node *, void *, int), void *arg) { struct m_tag *mtag; struct ieee80211_cb *cb; mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, sizeof(struct ieee80211_cb), M_NOWAIT); if (mtag == NULL) return 0; cb = (struct ieee80211_cb *)(mtag+1); cb->func = func; cb->arg = arg; m_tag_prepend(m, mtag); m->m_flags |= M_TXCB; return 1; } int ieee80211_add_xmit_params(struct mbuf *m, const struct ieee80211_bpf_params *params) { struct m_tag *mtag; struct ieee80211_tx_params *tx; mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS, sizeof(struct ieee80211_tx_params), M_NOWAIT); if (mtag == NULL) return (0); tx = (struct ieee80211_tx_params *)(mtag+1); memcpy(&tx->params, params, sizeof(struct ieee80211_bpf_params)); m_tag_prepend(m, mtag); return (1); } int ieee80211_get_xmit_params(struct mbuf *m, struct ieee80211_bpf_params *params) { struct m_tag *mtag; struct ieee80211_tx_params *tx; mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS, NULL); if (mtag == NULL) return (-1); tx = (struct ieee80211_tx_params *)(mtag + 1); memcpy(params, &tx->params, sizeof(struct ieee80211_bpf_params)); return (0); } void ieee80211_process_callback(struct ieee80211_node *ni, struct mbuf *m, int status) { struct m_tag *mtag; mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL); if (mtag != NULL) { struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1); cb->func(ni, cb->arg, status); } } /* + * Add RX parameters to the given mbuf. + * + * Returns 1 if OK, 0 on error. + */ +int +ieee80211_add_rx_params(struct mbuf *m, const struct ieee80211_rx_stats *rxs) +{ + struct m_tag *mtag; + struct ieee80211_rx_params *rx; + + mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS, + sizeof(struct ieee80211_rx_stats), M_NOWAIT); + if (mtag == NULL) + return (0); + + rx = (struct ieee80211_rx_params *)(mtag + 1); + memcpy(&rx->params, rxs, sizeof(*rxs)); + m_tag_prepend(m, mtag); + return (1); +} + +int +ieee80211_get_rx_params(struct mbuf *m, struct ieee80211_rx_stats *rxs) +{ + struct m_tag *mtag; + struct ieee80211_rx_params *rx; + + mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS, + NULL); + if (mtag == NULL) + return (-1); + rx = (struct ieee80211_rx_params *)(mtag + 1); + memcpy(rxs, &rx->params, sizeof(*rxs)); + return (0); +} + +/* * Transmit a frame to the parent interface. * * TODO: if the transmission fails, make sure the parent node is freed * (the callers will first need modifying.) */ int ieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m) { int error; /* * Assert the IC TX lock is held - this enforces the * processing -> queuing order is maintained */ IEEE80211_TX_LOCK_ASSERT(ic); error = ic->ic_transmit(ic, m); if (error) m_freem(m); return (error); } /* * Transmit a frame to the VAP interface. */ int ieee80211_vap_xmitpkt(struct ieee80211vap *vap, struct mbuf *m) { struct ifnet *ifp = vap->iv_ifp; /* * When transmitting via the VAP, we shouldn't hold * any IC TX lock as the VAP TX path will acquire it. */ IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic); return (ifp->if_transmit(ifp, m)); } #include void get_random_bytes(void *p, size_t n) { uint8_t *dp = p; while (n > 0) { uint32_t v = arc4random(); size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n; bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n); dp += sizeof(uint32_t), n -= nb; } } /* * Helper function for events that pass just a single mac address. */ static void notify_macaddr(struct ifnet *ifp, int op, const uint8_t mac[IEEE80211_ADDR_LEN]) { struct ieee80211_join_event iev; CURVNET_SET(ifp->if_vnet); memset(&iev, 0, sizeof(iev)); IEEE80211_ADDR_COPY(iev.iev_addr, mac); rt_ieee80211msg(ifp, op, &iev, sizeof(iev)); CURVNET_RESTORE(); } void ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc) { struct ieee80211vap *vap = ni->ni_vap; struct ifnet *ifp = vap->iv_ifp; CURVNET_SET_QUIET(ifp->if_vnet); IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode join", (ni == vap->iv_bss) ? "bss " : ""); if (ni == vap->iv_bss) { notify_macaddr(ifp, newassoc ? RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, ni->ni_bssid); if_link_state_change(ifp, LINK_STATE_UP); } else { notify_macaddr(ifp, newassoc ? RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, ni->ni_macaddr); } CURVNET_RESTORE(); } void ieee80211_notify_node_leave(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; struct ifnet *ifp = vap->iv_ifp; CURVNET_SET_QUIET(ifp->if_vnet); IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode leave", (ni == vap->iv_bss) ? "bss " : ""); if (ni == vap->iv_bss) { rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0); if_link_state_change(ifp, LINK_STATE_DOWN); } else { /* fire off wireless event station leaving */ notify_macaddr(ifp, RTM_IEEE80211_LEAVE, ni->ni_macaddr); } CURVNET_RESTORE(); } void ieee80211_notify_scan_done(struct ieee80211vap *vap) { struct ifnet *ifp = vap->iv_ifp; IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n", "notify scan done"); /* dispatch wireless event indicating scan completed */ CURVNET_SET(ifp->if_vnet); rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); CURVNET_RESTORE(); } void ieee80211_notify_replay_failure(struct ieee80211vap *vap, const struct ieee80211_frame *wh, const struct ieee80211_key *k, u_int64_t rsc, int tid) { struct ifnet *ifp = vap->iv_ifp; IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, "%s replay detected tid %d ", k->wk_cipher->ic_name, tid, (intmax_t) rsc, (intmax_t) k->wk_keyrsc[tid], k->wk_keyix, k->wk_rxkeyix); if (ifp != NULL) { /* NB: for cipher test modules */ struct ieee80211_replay_event iev; IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); iev.iev_cipher = k->wk_cipher->ic_cipher; if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE) iev.iev_keyix = k->wk_rxkeyix; else iev.iev_keyix = k->wk_keyix; iev.iev_keyrsc = k->wk_keyrsc[tid]; iev.iev_rsc = rsc; CURVNET_SET(ifp->if_vnet); rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev)); CURVNET_RESTORE(); } } void ieee80211_notify_michael_failure(struct ieee80211vap *vap, const struct ieee80211_frame *wh, u_int keyix) { struct ifnet *ifp = vap->iv_ifp; IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, "michael MIC verification failed ", keyix); vap->iv_stats.is_rx_tkipmic++; if (ifp != NULL) { /* NB: for cipher test modules */ struct ieee80211_michael_event iev; IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); iev.iev_cipher = IEEE80211_CIPHER_TKIP; iev.iev_keyix = keyix; CURVNET_SET(ifp->if_vnet); rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev)); CURVNET_RESTORE(); } } void ieee80211_notify_wds_discover(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; struct ifnet *ifp = vap->iv_ifp; notify_macaddr(ifp, RTM_IEEE80211_WDS, ni->ni_macaddr); } void ieee80211_notify_csa(struct ieee80211com *ic, const struct ieee80211_channel *c, int mode, int count) { struct ieee80211_csa_event iev; struct ieee80211vap *vap; struct ifnet *ifp; memset(&iev, 0, sizeof(iev)); iev.iev_flags = c->ic_flags; iev.iev_freq = c->ic_freq; iev.iev_ieee = c->ic_ieee; iev.iev_mode = mode; iev.iev_count = count; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { ifp = vap->iv_ifp; CURVNET_SET(ifp->if_vnet); rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev)); CURVNET_RESTORE(); } } void ieee80211_notify_radar(struct ieee80211com *ic, const struct ieee80211_channel *c) { struct ieee80211_radar_event iev; struct ieee80211vap *vap; struct ifnet *ifp; memset(&iev, 0, sizeof(iev)); iev.iev_flags = c->ic_flags; iev.iev_freq = c->ic_freq; iev.iev_ieee = c->ic_ieee; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { ifp = vap->iv_ifp; CURVNET_SET(ifp->if_vnet); rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev)); CURVNET_RESTORE(); } } void ieee80211_notify_cac(struct ieee80211com *ic, const struct ieee80211_channel *c, enum ieee80211_notify_cac_event type) { struct ieee80211_cac_event iev; struct ieee80211vap *vap; struct ifnet *ifp; memset(&iev, 0, sizeof(iev)); iev.iev_flags = c->ic_flags; iev.iev_freq = c->ic_freq; iev.iev_ieee = c->ic_ieee; iev.iev_type = type; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { ifp = vap->iv_ifp; CURVNET_SET(ifp->if_vnet); rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev)); CURVNET_RESTORE(); } } void ieee80211_notify_node_deauth(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; struct ifnet *ifp = vap->iv_ifp; IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node deauth"); notify_macaddr(ifp, RTM_IEEE80211_DEAUTH, ni->ni_macaddr); } void ieee80211_notify_node_auth(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; struct ifnet *ifp = vap->iv_ifp; IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node auth"); notify_macaddr(ifp, RTM_IEEE80211_AUTH, ni->ni_macaddr); } void ieee80211_notify_country(struct ieee80211vap *vap, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2]) { struct ifnet *ifp = vap->iv_ifp; struct ieee80211_country_event iev; memset(&iev, 0, sizeof(iev)); IEEE80211_ADDR_COPY(iev.iev_addr, bssid); iev.iev_cc[0] = cc[0]; iev.iev_cc[1] = cc[1]; CURVNET_SET(ifp->if_vnet); rt_ieee80211msg(ifp, RTM_IEEE80211_COUNTRY, &iev, sizeof(iev)); CURVNET_RESTORE(); } void ieee80211_notify_radio(struct ieee80211com *ic, int state) { struct ieee80211_radio_event iev; struct ieee80211vap *vap; struct ifnet *ifp; memset(&iev, 0, sizeof(iev)); iev.iev_state = state; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { ifp = vap->iv_ifp; CURVNET_SET(ifp->if_vnet); rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev)); CURVNET_RESTORE(); } } void ieee80211_load_module(const char *modname) { #ifdef notyet (void)kern_kldload(curthread, modname, NULL); #else printf("%s: load the %s module by hand for now.\n", __func__, modname); #endif } static eventhandler_tag wlan_bpfevent; static void bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach) { /* NB: identify vap's by if_init */ if (dlt == DLT_IEEE802_11_RADIO && ifp->if_init == ieee80211_init) { struct ieee80211vap *vap = ifp->if_softc; /* * Track bpf radiotap listener state. We mark the vap * to indicate if any listener is present and the com * to indicate if any listener exists on any associated * vap. This flag is used by drivers to prepare radiotap * state only when needed. */ if (attach) { ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF); if (vap->iv_opmode == IEEE80211_M_MONITOR) atomic_add_int(&vap->iv_ic->ic_montaps, 1); } else if (!bpf_peers_present(vap->iv_rawbpf)) { ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF); if (vap->iv_opmode == IEEE80211_M_MONITOR) atomic_subtract_int(&vap->iv_ic->ic_montaps, 1); } } } /* * Module glue. * * NB: the module name is "wlan" for compatibility with NetBSD. */ static int wlan_modevent(module_t mod, int type, void *unused) { switch (type) { case MOD_LOAD: if (bootverbose) printf("wlan: <802.11 Link Layer>\n"); wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track, bpf_track, 0, EVENTHANDLER_PRI_ANY); wlan_cloner = if_clone_simple(wlanname, wlan_clone_create, wlan_clone_destroy, 0); return 0; case MOD_UNLOAD: if_clone_detach(wlan_cloner); EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent); return 0; } return EINVAL; } static moduledata_t wlan_mod = { wlanname, wlan_modevent, 0 }; DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); MODULE_VERSION(wlan, 1); MODULE_DEPEND(wlan, ether, 1, 1, 1); #ifdef IEEE80211_ALQ MODULE_DEPEND(wlan, alq, 1, 1, 1); #endif /* IEEE80211_ALQ */ Index: head/sys/net80211/ieee80211_freebsd.h =================================================================== --- head/sys/net80211/ieee80211_freebsd.h (revision 288244) +++ head/sys/net80211/ieee80211_freebsd.h (revision 288245) @@ -1,637 +1,676 @@ /*- * Copyright (c) 2003-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 * documentation and/or other materials provided with the distribution. * * 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. * * $FreeBSD$ */ #ifndef _NET80211_IEEE80211_FREEBSD_H_ #define _NET80211_IEEE80211_FREEBSD_H_ #ifdef _KERNEL #include #include #include #include #include #include #include #include /* * Common state locking definitions. */ typedef struct { char name[16]; /* e.g. "ath0_com_lock" */ struct mtx mtx; } ieee80211_com_lock_t; #define IEEE80211_LOCK_INIT(_ic, _name) do { \ ieee80211_com_lock_t *cl = &(_ic)->ic_comlock; \ snprintf(cl->name, sizeof(cl->name), "%s_com_lock", _name); \ mtx_init(&cl->mtx, cl->name, NULL, MTX_DEF | MTX_RECURSE); \ } while (0) #define IEEE80211_LOCK_OBJ(_ic) (&(_ic)->ic_comlock.mtx) #define IEEE80211_LOCK_DESTROY(_ic) mtx_destroy(IEEE80211_LOCK_OBJ(_ic)) #define IEEE80211_LOCK(_ic) mtx_lock(IEEE80211_LOCK_OBJ(_ic)) #define IEEE80211_UNLOCK(_ic) mtx_unlock(IEEE80211_LOCK_OBJ(_ic)) #define IEEE80211_LOCK_ASSERT(_ic) \ mtx_assert(IEEE80211_LOCK_OBJ(_ic), MA_OWNED) #define IEEE80211_UNLOCK_ASSERT(_ic) \ mtx_assert(IEEE80211_LOCK_OBJ(_ic), MA_NOTOWNED) /* * Transmit lock. * * This is a (mostly) temporary lock designed to serialise all of the * transmission operations throughout the stack. */ typedef struct { char name[16]; /* e.g. "ath0_com_lock" */ struct mtx mtx; } ieee80211_tx_lock_t; #define IEEE80211_TX_LOCK_INIT(_ic, _name) do { \ ieee80211_tx_lock_t *cl = &(_ic)->ic_txlock; \ snprintf(cl->name, sizeof(cl->name), "%s_tx_lock", _name); \ mtx_init(&cl->mtx, cl->name, NULL, MTX_DEF); \ } while (0) #define IEEE80211_TX_LOCK_OBJ(_ic) (&(_ic)->ic_txlock.mtx) #define IEEE80211_TX_LOCK_DESTROY(_ic) mtx_destroy(IEEE80211_TX_LOCK_OBJ(_ic)) #define IEEE80211_TX_LOCK(_ic) mtx_lock(IEEE80211_TX_LOCK_OBJ(_ic)) #define IEEE80211_TX_UNLOCK(_ic) mtx_unlock(IEEE80211_TX_LOCK_OBJ(_ic)) #define IEEE80211_TX_LOCK_ASSERT(_ic) \ mtx_assert(IEEE80211_TX_LOCK_OBJ(_ic), MA_OWNED) #define IEEE80211_TX_UNLOCK_ASSERT(_ic) \ mtx_assert(IEEE80211_TX_LOCK_OBJ(_ic), MA_NOTOWNED) /* * Node locking definitions. */ typedef struct { char name[16]; /* e.g. "ath0_node_lock" */ struct mtx mtx; } ieee80211_node_lock_t; #define IEEE80211_NODE_LOCK_INIT(_nt, _name) do { \ ieee80211_node_lock_t *nl = &(_nt)->nt_nodelock; \ snprintf(nl->name, sizeof(nl->name), "%s_node_lock", _name); \ mtx_init(&nl->mtx, nl->name, NULL, MTX_DEF | MTX_RECURSE); \ } while (0) #define IEEE80211_NODE_LOCK_OBJ(_nt) (&(_nt)->nt_nodelock.mtx) #define IEEE80211_NODE_LOCK_DESTROY(_nt) \ mtx_destroy(IEEE80211_NODE_LOCK_OBJ(_nt)) #define IEEE80211_NODE_LOCK(_nt) \ mtx_lock(IEEE80211_NODE_LOCK_OBJ(_nt)) #define IEEE80211_NODE_IS_LOCKED(_nt) \ mtx_owned(IEEE80211_NODE_LOCK_OBJ(_nt)) #define IEEE80211_NODE_UNLOCK(_nt) \ mtx_unlock(IEEE80211_NODE_LOCK_OBJ(_nt)) #define IEEE80211_NODE_LOCK_ASSERT(_nt) \ mtx_assert(IEEE80211_NODE_LOCK_OBJ(_nt), MA_OWNED) /* * Node table iteration locking definitions; this protects the * scan generation # used to iterate over the station table * while grabbing+releasing the node lock. */ typedef struct { char name[16]; /* e.g. "ath0_scan_lock" */ struct mtx mtx; } ieee80211_scan_lock_t; #define IEEE80211_NODE_ITERATE_LOCK_INIT(_nt, _name) do { \ ieee80211_scan_lock_t *sl = &(_nt)->nt_scanlock; \ snprintf(sl->name, sizeof(sl->name), "%s_scan_lock", _name); \ mtx_init(&sl->mtx, sl->name, NULL, MTX_DEF); \ } while (0) #define IEEE80211_NODE_ITERATE_LOCK_OBJ(_nt) (&(_nt)->nt_scanlock.mtx) #define IEEE80211_NODE_ITERATE_LOCK_DESTROY(_nt) \ mtx_destroy(IEEE80211_NODE_ITERATE_LOCK_OBJ(_nt)) #define IEEE80211_NODE_ITERATE_LOCK(_nt) \ mtx_lock(IEEE80211_NODE_ITERATE_LOCK_OBJ(_nt)) #define IEEE80211_NODE_ITERATE_UNLOCK(_nt) \ mtx_unlock(IEEE80211_NODE_ITERATE_LOCK_OBJ(_nt)) /* * Power-save queue definitions. */ typedef struct mtx ieee80211_psq_lock_t; #define IEEE80211_PSQ_INIT(_psq, _name) \ mtx_init(&(_psq)->psq_lock, _name, "802.11 ps q", MTX_DEF) #define IEEE80211_PSQ_DESTROY(_psq) mtx_destroy(&(_psq)->psq_lock) #define IEEE80211_PSQ_LOCK(_psq) mtx_lock(&(_psq)->psq_lock) #define IEEE80211_PSQ_UNLOCK(_psq) mtx_unlock(&(_psq)->psq_lock) #ifndef IF_PREPEND_LIST #define _IF_PREPEND_LIST(ifq, mhead, mtail, mcount) do { \ (mtail)->m_nextpkt = (ifq)->ifq_head; \ if ((ifq)->ifq_tail == NULL) \ (ifq)->ifq_tail = (mtail); \ (ifq)->ifq_head = (mhead); \ (ifq)->ifq_len += (mcount); \ } while (0) #define IF_PREPEND_LIST(ifq, mhead, mtail, mcount) do { \ IF_LOCK(ifq); \ _IF_PREPEND_LIST(ifq, mhead, mtail, mcount); \ IF_UNLOCK(ifq); \ } while (0) #endif /* IF_PREPEND_LIST */ /* * Age queue definitions. */ typedef struct mtx ieee80211_ageq_lock_t; #define IEEE80211_AGEQ_INIT(_aq, _name) \ mtx_init(&(_aq)->aq_lock, _name, "802.11 age q", MTX_DEF) #define IEEE80211_AGEQ_DESTROY(_aq) mtx_destroy(&(_aq)->aq_lock) #define IEEE80211_AGEQ_LOCK(_aq) mtx_lock(&(_aq)->aq_lock) #define IEEE80211_AGEQ_UNLOCK(_aq) mtx_unlock(&(_aq)->aq_lock) /* * 802.1x MAC ACL database locking definitions. */ typedef struct mtx acl_lock_t; #define ACL_LOCK_INIT(_as, _name) \ mtx_init(&(_as)->as_lock, _name, "802.11 ACL", MTX_DEF) #define ACL_LOCK_DESTROY(_as) mtx_destroy(&(_as)->as_lock) #define ACL_LOCK(_as) mtx_lock(&(_as)->as_lock) #define ACL_UNLOCK(_as) mtx_unlock(&(_as)->as_lock) #define ACL_LOCK_ASSERT(_as) \ mtx_assert((&(_as)->as_lock), MA_OWNED) /* * Scan table definitions. */ typedef struct mtx ieee80211_scan_table_lock_t; #define IEEE80211_SCAN_TABLE_LOCK_INIT(_st, _name) \ mtx_init(&(_st)->st_lock, _name, "802.11 scan table", MTX_DEF) #define IEEE80211_SCAN_TABLE_LOCK_DESTROY(_st) mtx_destroy(&(_st)->st_lock) #define IEEE80211_SCAN_TABLE_LOCK(_st) mtx_lock(&(_st)->st_lock) #define IEEE80211_SCAN_TABLE_UNLOCK(_st) mtx_unlock(&(_st)->st_lock) typedef struct mtx ieee80211_scan_iter_lock_t; #define IEEE80211_SCAN_ITER_LOCK_INIT(_st, _name) \ mtx_init(&(_st)->st_scanlock, _name, "802.11 scangen", MTX_DEF) #define IEEE80211_SCAN_ITER_LOCK_DESTROY(_st) mtx_destroy(&(_st)->st_scanlock) #define IEEE80211_SCAN_ITER_LOCK(_st) mtx_lock(&(_st)->st_scanlock) #define IEEE80211_SCAN_ITER_UNLOCK(_st) mtx_unlock(&(_st)->st_scanlock) /* * Mesh node/routing definitions. */ typedef struct mtx ieee80211_rte_lock_t; #define MESH_RT_ENTRY_LOCK_INIT(_rt, _name) \ mtx_init(&(rt)->rt_lock, _name, "802.11s route entry", MTX_DEF) #define MESH_RT_ENTRY_LOCK_DESTROY(_rt) \ mtx_destroy(&(_rt)->rt_lock) #define MESH_RT_ENTRY_LOCK(rt) mtx_lock(&(rt)->rt_lock) #define MESH_RT_ENTRY_LOCK_ASSERT(rt) mtx_assert(&(rt)->rt_lock, MA_OWNED) #define MESH_RT_ENTRY_UNLOCK(rt) mtx_unlock(&(rt)->rt_lock) typedef struct mtx ieee80211_rt_lock_t; #define MESH_RT_LOCK(ms) mtx_lock(&(ms)->ms_rt_lock) #define MESH_RT_LOCK_ASSERT(ms) mtx_assert(&(ms)->ms_rt_lock, MA_OWNED) #define MESH_RT_UNLOCK(ms) mtx_unlock(&(ms)->ms_rt_lock) #define MESH_RT_LOCK_INIT(ms, name) \ mtx_init(&(ms)->ms_rt_lock, name, "802.11s routing table", MTX_DEF) #define MESH_RT_LOCK_DESTROY(ms) \ mtx_destroy(&(ms)->ms_rt_lock) /* * Node reference counting definitions. * * ieee80211_node_initref initialize the reference count to 1 * ieee80211_node_incref add a reference * ieee80211_node_decref remove a reference * ieee80211_node_dectestref remove a reference and return 1 if this * is the last reference, otherwise 0 * ieee80211_node_refcnt reference count for printing (only) */ #include #define ieee80211_node_initref(_ni) \ do { ((_ni)->ni_refcnt = 1); } while (0) #define ieee80211_node_incref(_ni) \ atomic_add_int(&(_ni)->ni_refcnt, 1) #define ieee80211_node_decref(_ni) \ atomic_subtract_int(&(_ni)->ni_refcnt, 1) struct ieee80211_node; int ieee80211_node_dectestref(struct ieee80211_node *ni); #define ieee80211_node_refcnt(_ni) (_ni)->ni_refcnt struct ifqueue; struct ieee80211vap; void ieee80211_drain_ifq(struct ifqueue *); void ieee80211_flush_ifq(struct ifqueue *, struct ieee80211vap *); void ieee80211_vap_destroy(struct ieee80211vap *); #define IFNET_IS_UP_RUNNING(_ifp) \ (((_ifp)->if_flags & IFF_UP) && \ ((_ifp)->if_drv_flags & IFF_DRV_RUNNING)) #define msecs_to_ticks(ms) (((ms)*hz)/1000) #define ticks_to_msecs(t) (1000*(t) / hz) #define ticks_to_secs(t) ((t) / hz) #define time_after(a,b) ((long)(b) - (long)(a) < 0) #define time_before(a,b) time_after(b,a) #define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0) #define time_before_eq(a,b) time_after_eq(b,a) struct mbuf *ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen); /* tx path usage */ #define M_ENCAP M_PROTO1 /* 802.11 encap done */ #define M_EAPOL M_PROTO3 /* PAE/EAPOL frame */ #define M_PWR_SAV M_PROTO4 /* bypass PS handling */ #define M_MORE_DATA M_PROTO5 /* more data frames to follow */ #define M_FF M_PROTO6 /* fast frame */ #define M_TXCB M_PROTO7 /* do tx complete callback */ #define M_AMPDU_MPDU M_PROTO8 /* ok for A-MPDU aggregation */ #define M_FRAG M_PROTO9 /* frame fragmentation */ #define M_FIRSTFRAG M_PROTO10 /* first frame fragment */ #define M_LASTFRAG M_PROTO11 /* last frame fragment */ #define M_80211_TX \ (M_ENCAP|M_EAPOL|M_PWR_SAV|M_MORE_DATA|M_FF|M_TXCB| \ M_AMPDU_MPDU|M_FRAG|M_FIRSTFRAG|M_LASTFRAG) /* rx path usage */ #define M_AMPDU M_PROTO1 /* A-MPDU subframe */ #define M_WEP M_PROTO2 /* WEP done by hardware */ #if 0 #define M_AMPDU_MPDU M_PROTO8 /* A-MPDU re-order done */ #endif #define M_80211_RX (M_AMPDU|M_WEP|M_AMPDU_MPDU) #define IEEE80211_MBUF_TX_FLAG_BITS \ M_FLAG_BITS \ "\15M_ENCAP\17M_EAPOL\20M_PWR_SAV\21M_MORE_DATA\22M_FF\23M_TXCB" \ "\24M_AMPDU_MPDU\25M_FRAG\26M_FIRSTFRAG\27M_LASTFRAG" #define IEEE80211_MBUF_RX_FLAG_BITS \ M_FLAG_BITS \ "\15M_AMPDU\16M_WEP\24M_AMPDU_MPDU" /* * Store WME access control bits in the vlan tag. * This is safe since it's done after the packet is classified * (where we use any previous tag) and because it's passed * directly in to the driver and there's no chance someone * else will clobber them on us. */ #define M_WME_SETAC(m, ac) \ ((m)->m_pkthdr.ether_vtag = (ac)) #define M_WME_GETAC(m) ((m)->m_pkthdr.ether_vtag) /* * Mbufs on the power save queue are tagged with an age and * timed out. We reuse the hardware checksum field in the * mbuf packet header to store this data. */ #define M_AGE_SET(m,v) (m->m_pkthdr.csum_data = v) #define M_AGE_GET(m) (m->m_pkthdr.csum_data) #define M_AGE_SUB(m,adj) (m->m_pkthdr.csum_data -= adj) /* * Store the sequence number. */ #define M_SEQNO_SET(m, seqno) \ ((m)->m_pkthdr.tso_segsz = (seqno)) #define M_SEQNO_GET(m) ((m)->m_pkthdr.tso_segsz) #define MTAG_ABI_NET80211 1132948340 /* net80211 ABI */ struct ieee80211_cb { void (*func)(struct ieee80211_node *, void *, int status); void *arg; }; #define NET80211_TAG_CALLBACK 0 /* xmit complete callback */ int ieee80211_add_callback(struct mbuf *m, void (*func)(struct ieee80211_node *, void *, int), void *arg); void ieee80211_process_callback(struct ieee80211_node *, struct mbuf *, int); #define NET80211_TAG_XMIT_PARAMS 1 /* See below; this is after the bpf_params definition */ +#define NET80211_TAG_RECV_PARAMS 2 + struct ieee80211com; int ieee80211_parent_xmitpkt(struct ieee80211com *, struct mbuf *); int ieee80211_vap_xmitpkt(struct ieee80211vap *, struct mbuf *); void get_random_bytes(void *, size_t); void ieee80211_sysctl_attach(struct ieee80211com *); void ieee80211_sysctl_detach(struct ieee80211com *); void ieee80211_sysctl_vattach(struct ieee80211vap *); void ieee80211_sysctl_vdetach(struct ieee80211vap *); SYSCTL_DECL(_net_wlan); int ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS); void ieee80211_load_module(const char *); /* * A "policy module" is an adjunct module to net80211 that provides * functionality that typically includes policy decisions. This * modularity enables extensibility and vendor-supplied functionality. */ #define _IEEE80211_POLICY_MODULE(policy, name, version) \ typedef void (*policy##_setup)(int); \ SET_DECLARE(policy##_set, policy##_setup); \ static int \ wlan_##name##_modevent(module_t mod, int type, void *unused) \ { \ policy##_setup * const *iter, f; \ switch (type) { \ case MOD_LOAD: \ SET_FOREACH(iter, policy##_set) { \ f = (void*) *iter; \ f(type); \ } \ return 0; \ case MOD_UNLOAD: \ case MOD_QUIESCE: \ if (nrefs) { \ printf("wlan_" #name ": still in use " \ "(%u dynamic refs)\n", nrefs); \ return EBUSY; \ } \ if (type == MOD_UNLOAD) { \ SET_FOREACH(iter, policy##_set) { \ f = (void*) *iter; \ f(type); \ } \ } \ return 0; \ } \ return EINVAL; \ } \ static moduledata_t name##_mod = { \ "wlan_" #name, \ wlan_##name##_modevent, \ 0 \ }; \ DECLARE_MODULE(wlan_##name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);\ MODULE_VERSION(wlan_##name, version); \ MODULE_DEPEND(wlan_##name, wlan, 1, 1, 1) /* * Crypto modules implement cipher support. */ #define IEEE80211_CRYPTO_MODULE(name, version) \ _IEEE80211_POLICY_MODULE(crypto, name, version); \ static void \ name##_modevent(int type) \ { \ if (type == MOD_LOAD) \ ieee80211_crypto_register(&name); \ else \ ieee80211_crypto_unregister(&name); \ } \ TEXT_SET(crypto##_set, name##_modevent) /* * Scanner modules provide scanning policy. */ #define IEEE80211_SCANNER_MODULE(name, version) \ _IEEE80211_POLICY_MODULE(scanner, name, version) #define IEEE80211_SCANNER_ALG(name, alg, v) \ static void \ name##_modevent(int type) \ { \ if (type == MOD_LOAD) \ ieee80211_scanner_register(alg, &v); \ else \ ieee80211_scanner_unregister(alg, &v); \ } \ TEXT_SET(scanner_set, name##_modevent); \ /* * ACL modules implement acl policy. */ #define IEEE80211_ACL_MODULE(name, alg, version) \ _IEEE80211_POLICY_MODULE(acl, name, version); \ static void \ alg##_modevent(int type) \ { \ if (type == MOD_LOAD) \ ieee80211_aclator_register(&alg); \ else \ ieee80211_aclator_unregister(&alg); \ } \ TEXT_SET(acl_set, alg##_modevent); \ /* * Authenticator modules handle 802.1x/WPA authentication. */ #define IEEE80211_AUTH_MODULE(name, version) \ _IEEE80211_POLICY_MODULE(auth, name, version) #define IEEE80211_AUTH_ALG(name, alg, v) \ static void \ name##_modevent(int type) \ { \ if (type == MOD_LOAD) \ ieee80211_authenticator_register(alg, &v); \ else \ ieee80211_authenticator_unregister(alg); \ } \ TEXT_SET(auth_set, name##_modevent) /* * Rate control modules provide tx rate control support. */ #define IEEE80211_RATECTL_MODULE(alg, version) \ _IEEE80211_POLICY_MODULE(ratectl, alg, version); \ #define IEEE80211_RATECTL_ALG(name, alg, v) \ static void \ alg##_modevent(int type) \ { \ if (type == MOD_LOAD) \ ieee80211_ratectl_register(alg, &v); \ else \ ieee80211_ratectl_unregister(alg); \ } \ TEXT_SET(ratectl##_set, alg##_modevent) struct ieee80211req; typedef int ieee80211_ioctl_getfunc(struct ieee80211vap *, struct ieee80211req *); SET_DECLARE(ieee80211_ioctl_getset, ieee80211_ioctl_getfunc); #define IEEE80211_IOCTL_GET(_name, _get) TEXT_SET(ieee80211_ioctl_getset, _get) typedef int ieee80211_ioctl_setfunc(struct ieee80211vap *, struct ieee80211req *); SET_DECLARE(ieee80211_ioctl_setset, ieee80211_ioctl_setfunc); #define IEEE80211_IOCTL_SET(_name, _set) TEXT_SET(ieee80211_ioctl_setset, _set) #endif /* _KERNEL */ /* XXX this stuff belongs elsewhere */ /* * Message formats for messages from the net80211 layer to user * applications via the routing socket. These messages are appended * to an if_announcemsghdr structure. */ struct ieee80211_join_event { uint8_t iev_addr[6]; }; struct ieee80211_leave_event { uint8_t iev_addr[6]; }; struct ieee80211_replay_event { uint8_t iev_src[6]; /* src MAC */ uint8_t iev_dst[6]; /* dst MAC */ uint8_t iev_cipher; /* cipher type */ uint8_t iev_keyix; /* key id/index */ uint64_t iev_keyrsc; /* RSC from key */ uint64_t iev_rsc; /* RSC from frame */ }; struct ieee80211_michael_event { uint8_t iev_src[6]; /* src MAC */ uint8_t iev_dst[6]; /* dst MAC */ uint8_t iev_cipher; /* cipher type */ uint8_t iev_keyix; /* key id/index */ }; struct ieee80211_wds_event { uint8_t iev_addr[6]; }; struct ieee80211_csa_event { uint32_t iev_flags; /* channel flags */ uint16_t iev_freq; /* setting in Mhz */ uint8_t iev_ieee; /* IEEE channel number */ uint8_t iev_mode; /* CSA mode */ uint8_t iev_count; /* CSA count */ }; struct ieee80211_cac_event { uint32_t iev_flags; /* channel flags */ uint16_t iev_freq; /* setting in Mhz */ uint8_t iev_ieee; /* IEEE channel number */ /* XXX timestamp? */ uint8_t iev_type; /* IEEE80211_NOTIFY_CAC_* */ }; struct ieee80211_radar_event { uint32_t iev_flags; /* channel flags */ uint16_t iev_freq; /* setting in Mhz */ uint8_t iev_ieee; /* IEEE channel number */ /* XXX timestamp? */ }; struct ieee80211_auth_event { uint8_t iev_addr[6]; }; struct ieee80211_deauth_event { uint8_t iev_addr[6]; }; struct ieee80211_country_event { uint8_t iev_addr[6]; uint8_t iev_cc[2]; /* ISO country code */ }; struct ieee80211_radio_event { uint8_t iev_state; /* 1 on, 0 off */ }; #define RTM_IEEE80211_ASSOC 100 /* station associate (bss mode) */ #define RTM_IEEE80211_REASSOC 101 /* station re-associate (bss mode) */ #define RTM_IEEE80211_DISASSOC 102 /* station disassociate (bss mode) */ #define RTM_IEEE80211_JOIN 103 /* station join (ap mode) */ #define RTM_IEEE80211_LEAVE 104 /* station leave (ap mode) */ #define RTM_IEEE80211_SCAN 105 /* scan complete, results available */ #define RTM_IEEE80211_REPLAY 106 /* sequence counter replay detected */ #define RTM_IEEE80211_MICHAEL 107 /* Michael MIC failure detected */ #define RTM_IEEE80211_REJOIN 108 /* station re-associate (ap mode) */ #define RTM_IEEE80211_WDS 109 /* WDS discovery (ap mode) */ #define RTM_IEEE80211_CSA 110 /* Channel Switch Announcement event */ #define RTM_IEEE80211_RADAR 111 /* radar event */ #define RTM_IEEE80211_CAC 112 /* Channel Availability Check event */ #define RTM_IEEE80211_DEAUTH 113 /* station deauthenticate */ #define RTM_IEEE80211_AUTH 114 /* station authenticate (ap mode) */ #define RTM_IEEE80211_COUNTRY 115 /* discovered country code (sta mode) */ #define RTM_IEEE80211_RADIO 116 /* RF kill switch state change */ /* * Structure prepended to raw packets sent through the bpf * interface when set to DLT_IEEE802_11_RADIO. This allows * user applications to specify pretty much everything in * an Atheros tx descriptor. XXX need to generalize. * * XXX cannot be more than 14 bytes as it is copied to a sockaddr's * XXX sa_data area. */ struct ieee80211_bpf_params { uint8_t ibp_vers; /* version */ #define IEEE80211_BPF_VERSION 0 uint8_t ibp_len; /* header length in bytes */ uint8_t ibp_flags; #define IEEE80211_BPF_SHORTPRE 0x01 /* tx with short preamble */ #define IEEE80211_BPF_NOACK 0x02 /* tx with no ack */ #define IEEE80211_BPF_CRYPTO 0x04 /* tx with h/w encryption */ #define IEEE80211_BPF_FCS 0x10 /* frame incldues FCS */ #define IEEE80211_BPF_DATAPAD 0x20 /* frame includes data padding */ #define IEEE80211_BPF_RTS 0x40 /* tx with RTS/CTS */ #define IEEE80211_BPF_CTS 0x80 /* tx with CTS only */ uint8_t ibp_pri; /* WME/WMM AC+tx antenna */ uint8_t ibp_try0; /* series 1 try count */ uint8_t ibp_rate0; /* series 1 IEEE tx rate */ uint8_t ibp_power; /* tx power (device units) */ uint8_t ibp_ctsrate; /* IEEE tx rate for CTS */ uint8_t ibp_try1; /* series 2 try count */ uint8_t ibp_rate1; /* series 2 IEEE tx rate */ uint8_t ibp_try2; /* series 3 try count */ uint8_t ibp_rate2; /* series 3 IEEE tx rate */ uint8_t ibp_try3; /* series 4 try count */ uint8_t ibp_rate3; /* series 4 IEEE tx rate */ }; #ifdef _KERNEL struct ieee80211_tx_params { struct ieee80211_bpf_params params; }; int ieee80211_add_xmit_params(struct mbuf *m, const struct ieee80211_bpf_params *); int ieee80211_get_xmit_params(struct mbuf *m, struct ieee80211_bpf_params *); + +#define IEEE80211_MAX_CHAINS 3 +#define IEEE80211_MAX_EVM_PILOTS 6 + +#define IEEE80211_R_NF 0x0000001 /* global NF value valid */ +#define IEEE80211_R_RSSI 0x0000002 /* global RSSI value valid */ +#define IEEE80211_R_C_CHAIN 0x0000004 /* RX chain count valid */ +#define IEEE80211_R_C_NF 0x0000008 /* per-chain NF value valid */ +#define IEEE80211_R_C_RSSI 0x0000010 /* per-chain RSSI value valid */ +#define IEEE80211_R_C_EVM 0x0000020 /* per-chain EVM valid */ +#define IEEE80211_R_C_HT40 0x0000040 /* RX'ed packet is 40mhz, pilots 4,5 valid */ +#define IEEE80211_R_FREQ 0x0000080 /* Freq value populated, MHz */ +#define IEEE80211_R_IEEE 0x0000100 /* IEEE value populated */ +#define IEEE80211_R_BAND 0x0000200 /* Frequency band populated */ + +struct ieee80211_rx_stats { + uint32_t r_flags; /* IEEE80211_R_* flags */ + uint8_t c_chain; /* number of RX chains involved */ + int16_t c_nf_ctl[IEEE80211_MAX_CHAINS]; /* per-chain NF */ + int16_t c_nf_ext[IEEE80211_MAX_CHAINS]; /* per-chain NF */ + int16_t c_rssi_ctl[IEEE80211_MAX_CHAINS]; /* per-chain RSSI */ + int16_t c_rssi_ext[IEEE80211_MAX_CHAINS]; /* per-chain RSSI */ + uint8_t nf; /* global NF */ + uint8_t rssi; /* global RSSI */ + uint8_t evm[IEEE80211_MAX_CHAINS][IEEE80211_MAX_EVM_PILOTS]; + /* per-chain, per-pilot EVM values */ + uint16_t c_freq; + uint8_t c_ieee; +}; + +struct ieee80211_rx_params { + struct ieee80211_rx_stats params; +}; +int ieee80211_add_rx_params(struct mbuf *m, + const struct ieee80211_rx_stats *rxs); +int ieee80211_get_rx_params(struct mbuf *m, + struct ieee80211_rx_stats *rxs); #endif /* _KERNEL */ /* * Malloc API. Other BSD operating systems have slightly * different malloc/free namings (eg DragonflyBSD.) */ #define IEEE80211_MALLOC malloc #define IEEE80211_FREE free /* XXX TODO: get rid of WAITOK, fix all the users of it? */ #define IEEE80211_M_NOWAIT M_NOWAIT #define IEEE80211_M_WAITOK M_WAITOK #define IEEE80211_M_ZERO M_ZERO /* XXX TODO: the type fields */ #endif /* _NET80211_IEEE80211_FREEBSD_H_ */ Index: head/sys/net80211/ieee80211_input.c =================================================================== --- head/sys/net80211/ieee80211_input.c (revision 288244) +++ head/sys/net80211/ieee80211_input.c (revision 288245) @@ -1,958 +1,978 @@ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002-2009 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 * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef IEEE80211_SUPPORT_MESH #include #endif #include #ifdef INET #include #include #endif static void ieee80211_process_mimo(struct ieee80211_node *ni, struct ieee80211_rx_stats *rx) { int i; /* Verify the required MIMO bits are set */ if ((rx->r_flags & (IEEE80211_R_C_CHAIN | IEEE80211_R_C_NF | IEEE80211_R_C_RSSI)) != (IEEE80211_R_C_CHAIN | IEEE80211_R_C_NF | IEEE80211_R_C_RSSI)) return; /* XXX This assumes the MIMO radios have both ctl and ext chains */ for (i = 0; i < MIN(rx->c_chain, IEEE80211_MAX_CHAINS); i++) { IEEE80211_RSSI_LPF(ni->ni_mimo_rssi_ctl[i], rx->c_rssi_ctl[i]); IEEE80211_RSSI_LPF(ni->ni_mimo_rssi_ext[i], rx->c_rssi_ext[i]); } /* XXX This also assumes the MIMO radios have both ctl and ext chains */ for(i = 0; i < MIN(rx->c_chain, IEEE80211_MAX_CHAINS); i++) { ni->ni_mimo_noise_ctl[i] = rx->c_nf_ctl[i]; ni->ni_mimo_noise_ext[i] = rx->c_nf_ext[i]; } ni->ni_mimo_chains = rx->c_chain; } int ieee80211_input_mimo(struct ieee80211_node *ni, struct mbuf *m, struct ieee80211_rx_stats *rx) { + struct ieee80211_rx_stats rxs; + + if (rx) { + memcpy(&rxs, rx, sizeof(*rx)); + } else { + /* try to read from mbuf */ + bzero(&rxs, sizeof(rxs)); + ieee80211_get_rx_params(m, &rxs); + } + /* XXX should assert IEEE80211_R_NF and IEEE80211_R_RSSI are set */ - ieee80211_process_mimo(ni, rx); + ieee80211_process_mimo(ni, &rxs); + //return ieee80211_input(ni, m, rx->rssi, rx->nf); - return ni->ni_vap->iv_input(ni, m, rx, rx->rssi, rx->nf); + return ni->ni_vap->iv_input(ni, m, &rxs, rxs.rssi, rxs.nf); } int ieee80211_input_all(struct ieee80211com *ic, struct mbuf *m, int rssi, int nf) { struct ieee80211_rx_stats rx; rx.r_flags = IEEE80211_R_NF | IEEE80211_R_RSSI; rx.nf = nf; rx.rssi = rssi; return ieee80211_input_mimo_all(ic, m, &rx); } int ieee80211_input_mimo_all(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_rx_stats *rx) { + struct ieee80211_rx_stats rxs; struct ieee80211vap *vap; int type = -1; m->m_flags |= M_BCAST; /* NB: mark for bpf tap'ing */ + if (rx) { + memcpy(&rxs, rx, sizeof(*rx)); + } else { + /* try to read from mbuf */ + bzero(&rxs, sizeof(rxs)); + ieee80211_get_rx_params(m, &rxs); + } + /* XXX locking */ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { struct ieee80211_node *ni; struct mbuf *mcopy; /* NB: could check for IFF_UP but this is cheaper */ if (vap->iv_state == IEEE80211_S_INIT) continue; /* * WDS vap's only receive directed traffic from the * station at the ``far end''. That traffic should * be passed through the AP vap the station is associated * to--so don't spam them with mcast frames. */ if (vap->iv_opmode == IEEE80211_M_WDS) continue; if (TAILQ_NEXT(vap, iv_next) != NULL) { /* * Packet contents are changed by ieee80211_decap * so do a deep copy of the packet. */ mcopy = m_dup(m, M_NOWAIT); if (mcopy == NULL) { /* XXX stat+msg */ continue; } } else { mcopy = m; m = NULL; } ni = ieee80211_ref_node(vap->iv_bss); - type = ieee80211_input_mimo(ni, mcopy, rx); + type = ieee80211_input_mimo(ni, mcopy, &rxs); ieee80211_free_node(ni); } if (m != NULL) /* no vaps, reclaim mbuf */ m_freem(m); return type; } /* * This function reassembles fragments. * * XXX should handle 3 concurrent reassemblies per-spec. */ struct mbuf * ieee80211_defrag(struct ieee80211_node *ni, struct mbuf *m, int hdrspace) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); struct ieee80211_frame *lwh; uint16_t rxseq; uint8_t fragno; uint8_t more_frag = wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG; struct mbuf *mfrag; KASSERT(!IEEE80211_IS_MULTICAST(wh->i_addr1), ("multicast fragm?")); rxseq = le16toh(*(uint16_t *)wh->i_seq); fragno = rxseq & IEEE80211_SEQ_FRAG_MASK; /* Quick way out, if there's nothing to defragment */ if (!more_frag && fragno == 0 && ni->ni_rxfrag[0] == NULL) return m; /* * Remove frag to insure it doesn't get reaped by timer. */ if (ni->ni_table == NULL) { /* * Should never happen. If the node is orphaned (not in * the table) then input packets should not reach here. * Otherwise, a concurrent request that yanks the table * should be blocked by other interlocking and/or by first * shutting the driver down. Regardless, be defensive * here and just bail */ /* XXX need msg+stat */ m_freem(m); return NULL; } IEEE80211_NODE_LOCK(ni->ni_table); mfrag = ni->ni_rxfrag[0]; ni->ni_rxfrag[0] = NULL; IEEE80211_NODE_UNLOCK(ni->ni_table); /* * Validate new fragment is in order and * related to the previous ones. */ if (mfrag != NULL) { uint16_t last_rxseq; lwh = mtod(mfrag, struct ieee80211_frame *); last_rxseq = le16toh(*(uint16_t *)lwh->i_seq); /* NB: check seq # and frag together */ if (rxseq != last_rxseq+1 || !IEEE80211_ADDR_EQ(wh->i_addr1, lwh->i_addr1) || !IEEE80211_ADDR_EQ(wh->i_addr2, lwh->i_addr2)) { /* * Unrelated fragment or no space for it, * clear current fragments. */ m_freem(mfrag); mfrag = NULL; } } if (mfrag == NULL) { if (fragno != 0) { /* !first fragment, discard */ vap->iv_stats.is_rx_defrag++; IEEE80211_NODE_STAT(ni, rx_defrag); m_freem(m); return NULL; } mfrag = m; } else { /* concatenate */ m_adj(m, hdrspace); /* strip header */ m_cat(mfrag, m); /* NB: m_cat doesn't update the packet header */ mfrag->m_pkthdr.len += m->m_pkthdr.len; /* track last seqnum and fragno */ lwh = mtod(mfrag, struct ieee80211_frame *); *(uint16_t *) lwh->i_seq = *(uint16_t *) wh->i_seq; } if (more_frag) { /* more to come, save */ ni->ni_rxfragstamp = ticks; ni->ni_rxfrag[0] = mfrag; mfrag = NULL; } return mfrag; } void ieee80211_deliver_data(struct ieee80211vap *vap, struct ieee80211_node *ni, struct mbuf *m) { struct ether_header *eh = mtod(m, struct ether_header *); struct ifnet *ifp = vap->iv_ifp; /* clear driver/net80211 flags before passing up */ m->m_flags &= ~(M_MCAST | M_BCAST); m_clrprotoflags(m); /* NB: see hostap_deliver_data, this path doesn't handle hostap */ KASSERT(vap->iv_opmode != IEEE80211_M_HOSTAP, ("gack, hostap")); /* * Do accounting. */ if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); IEEE80211_NODE_STAT(ni, rx_data); IEEE80211_NODE_STAT_ADD(ni, rx_bytes, m->m_pkthdr.len); if (ETHER_IS_MULTICAST(eh->ether_dhost)) { m->m_flags |= M_MCAST; /* XXX M_BCAST? */ IEEE80211_NODE_STAT(ni, rx_mcast); } else IEEE80211_NODE_STAT(ni, rx_ucast); m->m_pkthdr.rcvif = ifp; if (ni->ni_vlan != 0) { /* attach vlan tag */ m->m_pkthdr.ether_vtag = ni->ni_vlan; m->m_flags |= M_VLANTAG; } ifp->if_input(ifp, m); } struct mbuf * ieee80211_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen) { struct ieee80211_qosframe_addr4 wh; struct ether_header *eh; struct llc *llc; KASSERT(hdrlen <= sizeof(wh), ("hdrlen %d > max %zd", hdrlen, sizeof(wh))); if (m->m_len < hdrlen + sizeof(*llc) && (m = m_pullup(m, hdrlen + sizeof(*llc))) == NULL) { vap->iv_stats.is_rx_tooshort++; /* XXX msg */ return NULL; } memcpy(&wh, mtod(m, caddr_t), hdrlen); llc = (struct llc *)(mtod(m, caddr_t) + hdrlen); if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP && llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 && llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0 && /* NB: preserve AppleTalk frames that have a native SNAP hdr */ !(llc->llc_snap.ether_type == htons(ETHERTYPE_AARP) || llc->llc_snap.ether_type == htons(ETHERTYPE_IPX))) { m_adj(m, hdrlen + sizeof(struct llc) - sizeof(*eh)); llc = NULL; } else { m_adj(m, hdrlen - sizeof(*eh)); } eh = mtod(m, struct ether_header *); switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1); IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2); break; case IEEE80211_FC1_DIR_TODS: IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr3); IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2); break; case IEEE80211_FC1_DIR_FROMDS: IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1); IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr3); break; case IEEE80211_FC1_DIR_DSTODS: IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr3); IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr4); break; } #ifndef __NO_STRICT_ALIGNMENT if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), uint32_t)) { m = ieee80211_realign(vap, m, sizeof(*eh)); if (m == NULL) return NULL; } #endif /* !__NO_STRICT_ALIGNMENT */ if (llc != NULL) { eh = mtod(m, struct ether_header *); eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh)); } return m; } /* * Decap a frame encapsulated in a fast-frame/A-MSDU. */ struct mbuf * ieee80211_decap1(struct mbuf *m, int *framelen) { #define FF_LLC_SIZE (sizeof(struct ether_header) + sizeof(struct llc)) struct ether_header *eh; struct llc *llc; /* * The frame has an 802.3 header followed by an 802.2 * LLC header. The encapsulated frame length is in the * first header type field; save that and overwrite it * with the true type field found in the second. Then * copy the 802.3 header up to where it belongs and * adjust the mbuf contents to remove the void. */ if (m->m_len < FF_LLC_SIZE && (m = m_pullup(m, FF_LLC_SIZE)) == NULL) return NULL; eh = mtod(m, struct ether_header *); /* 802.3 header is first */ llc = (struct llc *)&eh[1]; /* 802.2 header follows */ *framelen = ntohs(eh->ether_type) /* encap'd frame size */ + sizeof(struct ether_header) - sizeof(struct llc); eh->ether_type = llc->llc_un.type_snap.ether_type; ovbcopy(eh, mtod(m, uint8_t *) + sizeof(struct llc), sizeof(struct ether_header)); m_adj(m, sizeof(struct llc)); return m; #undef FF_LLC_SIZE } /* * Install received rate set information in the node's state block. */ int ieee80211_setup_rates(struct ieee80211_node *ni, const uint8_t *rates, const uint8_t *xrates, int flags) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_rateset *rs = &ni->ni_rates; memset(rs, 0, sizeof(*rs)); rs->rs_nrates = rates[1]; memcpy(rs->rs_rates, rates + 2, rs->rs_nrates); if (xrates != NULL) { uint8_t nxrates; /* * Tack on 11g extended supported rate element. */ nxrates = xrates[1]; if (rs->rs_nrates + nxrates > IEEE80211_RATE_MAXSIZE) { nxrates = IEEE80211_RATE_MAXSIZE - rs->rs_nrates; IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE, ni, "extended rate set too large; only using " "%u of %u rates", nxrates, xrates[1]); vap->iv_stats.is_rx_rstoobig++; } memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates); rs->rs_nrates += nxrates; } return ieee80211_fix_rate(ni, rs, flags); } /* * Send a management frame error response to the specified * station. If ni is associated with the station then use * it; otherwise allocate a temporary node suitable for * transmitting the frame and then free the reference so * it will go away as soon as the frame has been transmitted. */ void ieee80211_send_error(struct ieee80211_node *ni, const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg) { struct ieee80211vap *vap = ni->ni_vap; int istmp; if (ni == vap->iv_bss) { if (vap->iv_state != IEEE80211_S_RUN) { /* * XXX hack until we get rid of this routine. * We can be called prior to the vap reaching * run state under certain conditions in which * case iv_bss->ni_chan will not be setup. * Check for this explicitly and and just ignore * the request. */ return; } ni = ieee80211_tmp_node(vap, mac); if (ni == NULL) { /* XXX msg */ return; } istmp = 1; } else istmp = 0; IEEE80211_SEND_MGMT(ni, subtype, arg); if (istmp) ieee80211_free_node(ni); } int ieee80211_alloc_challenge(struct ieee80211_node *ni) { if (ni->ni_challenge == NULL) ni->ni_challenge = (uint32_t *) IEEE80211_MALLOC(IEEE80211_CHALLENGE_LEN, M_80211_NODE, IEEE80211_M_NOWAIT); if (ni->ni_challenge == NULL) { IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, ni, "%s", "shared key challenge alloc failed"); /* XXX statistic */ } return (ni->ni_challenge != NULL); } /* * Parse a Beacon or ProbeResponse frame and return the * useful information in an ieee80211_scanparams structure. * Status is set to 0 if no problems were found; otherwise * a bitmask of IEEE80211_BPARSE_* items is returned that * describes the problems detected. */ int ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m, struct ieee80211_channel *rxchan, struct ieee80211_scanparams *scan) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_frame *wh; uint8_t *frm, *efrm; wh = mtod(m, struct ieee80211_frame *); frm = (uint8_t *)&wh[1]; efrm = mtod(m, uint8_t *) + m->m_len; scan->status = 0; /* * beacon/probe response frame format * [8] time stamp * [2] beacon interval * [2] capability information * [tlv] ssid * [tlv] supported rates * [tlv] country information * [tlv] channel switch announcement (CSA) * [tlv] parameter set (FH/DS) * [tlv] erp information * [tlv] extended supported rates * [tlv] WME * [tlv] WPA or RSN * [tlv] HT capabilities * [tlv] HT information * [tlv] Atheros capabilities * [tlv] Mesh ID * [tlv] Mesh Configuration */ IEEE80211_VERIFY_LENGTH(efrm - frm, 12, return (scan->status = IEEE80211_BPARSE_BADIELEN)); memset(scan, 0, sizeof(*scan)); scan->tstamp = frm; frm += 8; scan->bintval = le16toh(*(uint16_t *)frm); frm += 2; scan->capinfo = le16toh(*(uint16_t *)frm); frm += 2; scan->bchan = ieee80211_chan2ieee(ic, rxchan); scan->chan = scan->bchan; scan->ies = frm; scan->ies_len = efrm - frm; while (efrm - frm > 1) { IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return (scan->status = IEEE80211_BPARSE_BADIELEN)); switch (*frm) { case IEEE80211_ELEMID_SSID: scan->ssid = frm; break; case IEEE80211_ELEMID_RATES: scan->rates = frm; break; case IEEE80211_ELEMID_COUNTRY: scan->country = frm; break; case IEEE80211_ELEMID_CSA: scan->csa = frm; break; case IEEE80211_ELEMID_QUIET: scan->quiet = frm; break; case IEEE80211_ELEMID_FHPARMS: if (ic->ic_phytype == IEEE80211_T_FH) { scan->fhdwell = LE_READ_2(&frm[2]); scan->chan = IEEE80211_FH_CHAN(frm[4], frm[5]); scan->fhindex = frm[6]; } break; case IEEE80211_ELEMID_DSPARMS: /* * XXX hack this since depending on phytype * is problematic for multi-mode devices. */ if (ic->ic_phytype != IEEE80211_T_FH) scan->chan = frm[2]; break; case IEEE80211_ELEMID_TIM: /* XXX ATIM? */ scan->tim = frm; scan->timoff = frm - mtod(m, uint8_t *); break; case IEEE80211_ELEMID_IBSSPARMS: case IEEE80211_ELEMID_CFPARMS: case IEEE80211_ELEMID_PWRCNSTR: /* NB: avoid debugging complaints */ break; case IEEE80211_ELEMID_XRATES: scan->xrates = frm; break; case IEEE80211_ELEMID_ERP: if (frm[1] != 1) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID, wh, "ERP", "bad len %u", frm[1]); vap->iv_stats.is_rx_elem_toobig++; break; } scan->erp = frm[2] | 0x100; break; case IEEE80211_ELEMID_HTCAP: scan->htcap = frm; break; case IEEE80211_ELEMID_RSN: scan->rsn = frm; break; case IEEE80211_ELEMID_HTINFO: scan->htinfo = frm; break; #ifdef IEEE80211_SUPPORT_MESH case IEEE80211_ELEMID_MESHID: scan->meshid = frm; break; case IEEE80211_ELEMID_MESHCONF: scan->meshconf = frm; break; #endif case IEEE80211_ELEMID_VENDOR: if (iswpaoui(frm)) scan->wpa = frm; else if (iswmeparam(frm) || iswmeinfo(frm)) scan->wme = frm; #ifdef IEEE80211_SUPPORT_SUPERG else if (isatherosoui(frm)) scan->ath = frm; #endif #ifdef IEEE80211_SUPPORT_TDMA else if (istdmaoui(frm)) scan->tdma = frm; #endif else if (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) { /* * Accept pre-draft HT ie's if the * standard ones have not been seen. */ if (ishtcapoui(frm)) { if (scan->htcap == NULL) scan->htcap = frm; } else if (ishtinfooui(frm)) { if (scan->htinfo == NULL) scan->htcap = frm; } } break; default: IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID, wh, "unhandled", "id %u, len %u", *frm, frm[1]); vap->iv_stats.is_rx_elem_unknown++; break; } frm += frm[1] + 2; } IEEE80211_VERIFY_ELEMENT(scan->rates, IEEE80211_RATE_MAXSIZE, scan->status |= IEEE80211_BPARSE_RATES_INVALID); if (scan->rates != NULL && scan->xrates != NULL) { /* * NB: don't process XRATES if RATES is missing. This * avoids a potential null ptr deref and should be ok * as the return code will already note RATES is missing * (so callers shouldn't otherwise process the frame). */ IEEE80211_VERIFY_ELEMENT(scan->xrates, IEEE80211_RATE_MAXSIZE - scan->rates[1], scan->status |= IEEE80211_BPARSE_XRATES_INVALID); } IEEE80211_VERIFY_ELEMENT(scan->ssid, IEEE80211_NWID_LEN, scan->status |= IEEE80211_BPARSE_SSID_INVALID); if (scan->chan != scan->bchan && ic->ic_phytype != IEEE80211_T_FH) { /* * Frame was received on a channel different from the * one indicated in the DS params element id; * silently discard it. * * NB: this can happen due to signal leakage. * But we should take it for FH phy because * the rssi value should be correct even for * different hop pattern in FH. */ IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, wh, NULL, "for off-channel %u (bchan=%u)", scan->chan, scan->bchan); vap->iv_stats.is_rx_chanmismatch++; scan->status |= IEEE80211_BPARSE_OFFCHAN; } if (!(IEEE80211_BINTVAL_MIN <= scan->bintval && scan->bintval <= IEEE80211_BINTVAL_MAX)) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, wh, NULL, "bogus beacon interval (%d TU)", (int) scan->bintval); vap->iv_stats.is_rx_badbintval++; scan->status |= IEEE80211_BPARSE_BINTVAL_INVALID; } if (scan->country != NULL) { /* * Validate we have at least enough data to extract * the country code. Not sure if we should return an * error instead of discarding the IE; consider this * being lenient as we don't depend on the data for * correct operation. */ IEEE80211_VERIFY_LENGTH(scan->country[1], 3 * sizeof(uint8_t), scan->country = NULL); } if (scan->csa != NULL) { /* * Validate Channel Switch Announcement; this must * be the correct length or we toss the frame. */ IEEE80211_VERIFY_LENGTH(scan->csa[1], 3 * sizeof(uint8_t), scan->status |= IEEE80211_BPARSE_CSA_INVALID); } /* * Process HT ie's. This is complicated by our * accepting both the standard ie's and the pre-draft * vendor OUI ie's that some vendors still use/require. */ if (scan->htcap != NULL) { IEEE80211_VERIFY_LENGTH(scan->htcap[1], scan->htcap[0] == IEEE80211_ELEMID_VENDOR ? 4 + sizeof(struct ieee80211_ie_htcap)-2 : sizeof(struct ieee80211_ie_htcap)-2, scan->htcap = NULL); } if (scan->htinfo != NULL) { IEEE80211_VERIFY_LENGTH(scan->htinfo[1], scan->htinfo[0] == IEEE80211_ELEMID_VENDOR ? 4 + sizeof(struct ieee80211_ie_htinfo)-2 : sizeof(struct ieee80211_ie_htinfo)-2, scan->htinfo = NULL); } return scan->status; } /* * Parse an Action frame. Return 0 on success, non-zero on failure. */ int ieee80211_parse_action(struct ieee80211_node *ni, struct mbuf *m) { struct ieee80211vap *vap = ni->ni_vap; const struct ieee80211_action *ia; struct ieee80211_frame *wh; uint8_t *frm, *efrm; /* * action frame format: * [1] category * [1] action * [tlv] parameters */ wh = mtod(m, struct ieee80211_frame *); frm = (u_int8_t *)&wh[1]; efrm = mtod(m, u_int8_t *) + m->m_len; IEEE80211_VERIFY_LENGTH(efrm - frm, sizeof(struct ieee80211_action), return EINVAL); ia = (const struct ieee80211_action *) frm; vap->iv_stats.is_rx_action++; IEEE80211_NODE_STAT(ni, rx_action); /* verify frame payloads but defer processing */ switch (ia->ia_category) { case IEEE80211_ACTION_CAT_BA: switch (ia->ia_action) { case IEEE80211_ACTION_BA_ADDBA_REQUEST: IEEE80211_VERIFY_LENGTH(efrm - frm, sizeof(struct ieee80211_action_ba_addbarequest), return EINVAL); break; case IEEE80211_ACTION_BA_ADDBA_RESPONSE: IEEE80211_VERIFY_LENGTH(efrm - frm, sizeof(struct ieee80211_action_ba_addbaresponse), return EINVAL); break; case IEEE80211_ACTION_BA_DELBA: IEEE80211_VERIFY_LENGTH(efrm - frm, sizeof(struct ieee80211_action_ba_delba), return EINVAL); break; } break; case IEEE80211_ACTION_CAT_HT: switch (ia->ia_action) { case IEEE80211_ACTION_HT_TXCHWIDTH: IEEE80211_VERIFY_LENGTH(efrm - frm, sizeof(struct ieee80211_action_ht_txchwidth), return EINVAL); break; case IEEE80211_ACTION_HT_MIMOPWRSAVE: IEEE80211_VERIFY_LENGTH(efrm - frm, sizeof(struct ieee80211_action_ht_mimopowersave), return EINVAL); break; } break; #ifdef IEEE80211_SUPPORT_MESH case IEEE80211_ACTION_CAT_MESH: switch (ia->ia_action) { case IEEE80211_ACTION_MESH_LMETRIC: /* * XXX: verification is true only if we are using * Airtime link metric (default) */ IEEE80211_VERIFY_LENGTH(efrm - frm, sizeof(struct ieee80211_meshlmetric_ie), return EINVAL); break; case IEEE80211_ACTION_MESH_HWMP: /* verify something */ break; case IEEE80211_ACTION_MESH_GANN: IEEE80211_VERIFY_LENGTH(efrm - frm, sizeof(struct ieee80211_meshgann_ie), return EINVAL); break; case IEEE80211_ACTION_MESH_CC: case IEEE80211_ACTION_MESH_MCCA_SREQ: case IEEE80211_ACTION_MESH_MCCA_SREP: case IEEE80211_ACTION_MESH_MCCA_AREQ: case IEEE80211_ACTION_MESH_MCCA_ADVER: case IEEE80211_ACTION_MESH_MCCA_TRDOWN: case IEEE80211_ACTION_MESH_TBTT_REQ: case IEEE80211_ACTION_MESH_TBTT_RES: /* reject these early on, not implemented */ IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, wh, NULL, "not implemented yet, act=0x%02X", ia->ia_action); return EINVAL; } break; case IEEE80211_ACTION_CAT_SELF_PROT: /* If TA or RA group address discard silently */ if (IEEE80211_IS_MULTICAST(wh->i_addr1) || IEEE80211_IS_MULTICAST(wh->i_addr2)) return EINVAL; /* * XXX: Should we verify complete length now or it is * to varying in sizes? */ switch (ia->ia_action) { case IEEE80211_ACTION_MESHPEERING_CONFIRM: case IEEE80211_ACTION_MESHPEERING_CLOSE: /* is not a peering candidate (yet) */ if (ni == vap->iv_bss) return EINVAL; break; } break; #endif } return 0; } #ifdef IEEE80211_DEBUG /* * Debugging support. */ void ieee80211_ssid_mismatch(struct ieee80211vap *vap, const char *tag, uint8_t mac[IEEE80211_ADDR_LEN], uint8_t *ssid) { printf("[%s] discard %s frame, ssid mismatch: ", ether_sprintf(mac), tag); ieee80211_print_essid(ssid + 2, ssid[1]); printf("\n"); } /* * Return the bssid of a frame. */ static const uint8_t * ieee80211_getbssid(const struct ieee80211vap *vap, const struct ieee80211_frame *wh) { if (vap->iv_opmode == IEEE80211_M_STA) return wh->i_addr2; if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != IEEE80211_FC1_DIR_NODS) return wh->i_addr1; if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL) return wh->i_addr1; return wh->i_addr3; } #include void ieee80211_note(const struct ieee80211vap *vap, const char *fmt, ...) { char buf[128]; /* XXX */ va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if_printf(vap->iv_ifp, "%s", buf); /* NB: no \n */ } void ieee80211_note_frame(const struct ieee80211vap *vap, const struct ieee80211_frame *wh, const char *fmt, ...) { char buf[128]; /* XXX */ va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if_printf(vap->iv_ifp, "[%s] %s\n", ether_sprintf(ieee80211_getbssid(vap, wh)), buf); } void ieee80211_note_mac(const struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN], const char *fmt, ...) { char buf[128]; /* XXX */ va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if_printf(vap->iv_ifp, "[%s] %s\n", ether_sprintf(mac), buf); } void ieee80211_discard_frame(const struct ieee80211vap *vap, const struct ieee80211_frame *wh, const char *type, const char *fmt, ...) { va_list ap; if_printf(vap->iv_ifp, "[%s] discard ", ether_sprintf(ieee80211_getbssid(vap, wh))); if (type == NULL) { printf("%s frame, ", ieee80211_mgt_subtype_name[ (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT]); } else printf("%s frame, ", type); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } void ieee80211_discard_ie(const struct ieee80211vap *vap, const struct ieee80211_frame *wh, const char *type, const char *fmt, ...) { va_list ap; if_printf(vap->iv_ifp, "[%s] discard ", ether_sprintf(ieee80211_getbssid(vap, wh))); if (type != NULL) printf("%s information element, ", type); else printf("information element, "); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } void ieee80211_discard_mac(const struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN], const char *type, const char *fmt, ...) { va_list ap; if_printf(vap->iv_ifp, "[%s] discard ", ether_sprintf(mac)); if (type != NULL) printf("%s frame, ", type); else printf("frame, "); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } #endif /* IEEE80211_DEBUG */ Index: head/sys/net80211/ieee80211_proto.h =================================================================== --- head/sys/net80211/ieee80211_proto.h (revision 288244) +++ head/sys/net80211/ieee80211_proto.h (revision 288245) @@ -1,439 +1,413 @@ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002-2009 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 * documentation and/or other materials provided with the distribution. * * 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. * * $FreeBSD$ */ #ifndef _NET80211_IEEE80211_PROTO_H_ #define _NET80211_IEEE80211_PROTO_H_ /* * 802.11 protocol implementation definitions. */ enum ieee80211_state { IEEE80211_S_INIT = 0, /* default state */ IEEE80211_S_SCAN = 1, /* scanning */ IEEE80211_S_AUTH = 2, /* try to authenticate */ IEEE80211_S_ASSOC = 3, /* try to assoc */ IEEE80211_S_CAC = 4, /* doing channel availability check */ IEEE80211_S_RUN = 5, /* operational (e.g. associated) */ IEEE80211_S_CSA = 6, /* channel switch announce pending */ IEEE80211_S_SLEEP = 7, /* power save */ }; #define IEEE80211_S_MAX (IEEE80211_S_SLEEP+1) #define IEEE80211_SEND_MGMT(_ni,_type,_arg) \ ((*(_ni)->ni_ic->ic_send_mgmt)(_ni, _type, _arg)) extern const char *ieee80211_mgt_subtype_name[]; extern const char *ieee80211_phymode_name[IEEE80211_MODE_MAX]; extern const int ieee80211_opcap[IEEE80211_OPMODE_MAX]; void ieee80211_proto_attach(struct ieee80211com *); void ieee80211_proto_detach(struct ieee80211com *); void ieee80211_proto_vattach(struct ieee80211vap *); void ieee80211_proto_vdetach(struct ieee80211vap *); void ieee80211_promisc(struct ieee80211vap *, bool); void ieee80211_allmulti(struct ieee80211vap *, bool); void ieee80211_syncflag(struct ieee80211vap *, int flag); void ieee80211_syncflag_ht(struct ieee80211vap *, int flag); void ieee80211_syncflag_ext(struct ieee80211vap *, int flag); -#define IEEE80211_R_NF 0x0000001 /* global NF value valid */ -#define IEEE80211_R_RSSI 0x0000002 /* global RSSI value valid */ -#define IEEE80211_R_C_CHAIN 0x0000004 /* RX chain count valid */ -#define IEEE80211_R_C_NF 0x0000008 /* per-chain NF value valid */ -#define IEEE80211_R_C_RSSI 0x0000010 /* per-chain RSSI value valid */ -#define IEEE80211_R_C_EVM 0x0000020 /* per-chain EVM valid */ -#define IEEE80211_R_C_HT40 0x0000040 /* RX'ed packet is 40mhz, pilots 4,5 valid */ -#define IEEE80211_R_FREQ 0x0000080 /* Freq value populated, MHz */ -#define IEEE80211_R_IEEE 0x0000100 /* IEEE value populated */ -#define IEEE80211_R_BAND 0x0000200 /* Frequency band populated */ - -struct ieee80211_rx_stats { - uint32_t r_flags; /* IEEE80211_R_* flags */ - uint8_t c_chain; /* number of RX chains involved */ - int16_t c_nf_ctl[IEEE80211_MAX_CHAINS]; /* per-chain NF */ - int16_t c_nf_ext[IEEE80211_MAX_CHAINS]; /* per-chain NF */ - int16_t c_rssi_ctl[IEEE80211_MAX_CHAINS]; /* per-chain RSSI */ - int16_t c_rssi_ext[IEEE80211_MAX_CHAINS]; /* per-chain RSSI */ - uint8_t nf; /* global NF */ - uint8_t rssi; /* global RSSI */ - uint8_t evm[IEEE80211_MAX_CHAINS][IEEE80211_MAX_EVM_PILOTS]; - /* per-chain, per-pilot EVM values */ - uint16_t c_freq; - uint8_t c_ieee; -}; - #define ieee80211_input(ni, m, rssi, nf) \ ((ni)->ni_vap->iv_input(ni, m, NULL, rssi, nf)) int ieee80211_input_all(struct ieee80211com *, struct mbuf *, int, int); int ieee80211_input_mimo(struct ieee80211_node *, struct mbuf *, struct ieee80211_rx_stats *); int ieee80211_input_mimo_all(struct ieee80211com *, struct mbuf *, struct ieee80211_rx_stats *); struct ieee80211_bpf_params; int ieee80211_mgmt_output(struct ieee80211_node *, struct mbuf *, int, struct ieee80211_bpf_params *); int ieee80211_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); int ieee80211_output(struct ifnet *, struct mbuf *, const struct sockaddr *, struct route *ro); int ieee80211_vap_pkt_send_dest(struct ieee80211vap *, struct mbuf *, struct ieee80211_node *); int ieee80211_raw_output(struct ieee80211vap *, struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); void ieee80211_send_setup(struct ieee80211_node *, struct mbuf *, int, int, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); int ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m); void ieee80211_vap_qflush(struct ifnet *ifp); int ieee80211_send_nulldata(struct ieee80211_node *); int ieee80211_classify(struct ieee80211_node *, struct mbuf *m); struct mbuf *ieee80211_mbuf_adjust(struct ieee80211vap *, int, struct ieee80211_key *, struct mbuf *); struct mbuf *ieee80211_encap(struct ieee80211vap *, struct ieee80211_node *, struct mbuf *); int ieee80211_send_mgmt(struct ieee80211_node *, int, int); struct ieee80211_appie; int ieee80211_send_probereq(struct ieee80211_node *ni, const uint8_t sa[IEEE80211_ADDR_LEN], const uint8_t da[IEEE80211_ADDR_LEN], const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t *ssid, size_t ssidlen); struct mbuf * ieee80211_ff_encap1(struct ieee80211vap *, struct mbuf *, const struct ether_header *); void ieee80211_tx_complete(struct ieee80211_node *, struct mbuf *, int); /* * The formation of ProbeResponse frames requires guidance to * deal with legacy clients. When the client is identified as * "legacy 11b" ieee80211_send_proberesp is passed this token. */ #define IEEE80211_SEND_LEGACY_11B 0x1 /* legacy 11b client */ #define IEEE80211_SEND_LEGACY_11 0x2 /* other legacy client */ #define IEEE80211_SEND_LEGACY 0x3 /* any legacy client */ struct mbuf *ieee80211_alloc_proberesp(struct ieee80211_node *, int); int ieee80211_send_proberesp(struct ieee80211vap *, const uint8_t da[IEEE80211_ADDR_LEN], int); struct mbuf *ieee80211_alloc_rts(struct ieee80211com *ic, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN], uint16_t); struct mbuf *ieee80211_alloc_cts(struct ieee80211com *, const uint8_t [IEEE80211_ADDR_LEN], uint16_t); uint8_t *ieee80211_add_rates(uint8_t *, const struct ieee80211_rateset *); uint8_t *ieee80211_add_xrates(uint8_t *, const struct ieee80211_rateset *); uint8_t *ieee80211_add_ssid(uint8_t *, const uint8_t *, u_int); uint8_t *ieee80211_add_wpa(uint8_t *, const struct ieee80211vap *); uint8_t *ieee80211_add_rsn(uint8_t *, const struct ieee80211vap *); uint8_t *ieee80211_add_qos(uint8_t *, const struct ieee80211_node *); uint16_t ieee80211_getcapinfo(struct ieee80211vap *, struct ieee80211_channel *); struct ieee80211_wme_state; uint8_t * ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme); void ieee80211_reset_erp(struct ieee80211com *); void ieee80211_set_shortslottime(struct ieee80211com *, int onoff); int ieee80211_iserp_rateset(const struct ieee80211_rateset *); void ieee80211_setbasicrates(struct ieee80211_rateset *, enum ieee80211_phymode); void ieee80211_addbasicrates(struct ieee80211_rateset *, enum ieee80211_phymode); /* * Return the size of the 802.11 header for a management or data frame. */ static __inline int ieee80211_hdrsize(const void *data) { const struct ieee80211_frame *wh = data; int size = sizeof(struct ieee80211_frame); /* NB: we don't handle control frames */ KASSERT((wh->i_fc[0]&IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL, ("%s: control frame", __func__)); if (IEEE80211_IS_DSTODS(wh)) size += IEEE80211_ADDR_LEN; if (IEEE80211_QOS_HAS_SEQ(wh)) size += sizeof(uint16_t); return size; } /* * Like ieee80211_hdrsize, but handles any type of frame. */ static __inline int ieee80211_anyhdrsize(const void *data) { const struct ieee80211_frame *wh = data; if ((wh->i_fc[0]&IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) { switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { case IEEE80211_FC0_SUBTYPE_CTS: case IEEE80211_FC0_SUBTYPE_ACK: return sizeof(struct ieee80211_frame_ack); case IEEE80211_FC0_SUBTYPE_BAR: return sizeof(struct ieee80211_frame_bar); } return sizeof(struct ieee80211_frame_min); } else return ieee80211_hdrsize(data); } /* * Template for an in-kernel authenticator. Authenticators * register with the protocol code and are typically loaded * as separate modules as needed. One special authenticator * is xauth; it intercepts requests so that protocols like * WPA can be handled in user space. */ struct ieee80211_authenticator { const char *ia_name; /* printable name */ int (*ia_attach)(struct ieee80211vap *); void (*ia_detach)(struct ieee80211vap *); void (*ia_node_join)(struct ieee80211_node *); void (*ia_node_leave)(struct ieee80211_node *); }; void ieee80211_authenticator_register(int type, const struct ieee80211_authenticator *); void ieee80211_authenticator_unregister(int type); const struct ieee80211_authenticator *ieee80211_authenticator_get(int auth); struct ieee80211req; /* * Template for an MAC ACL policy module. Such modules * register with the protocol code and are passed the sender's * address of each received auth frame for validation. */ struct ieee80211_aclator { const char *iac_name; /* printable name */ int (*iac_attach)(struct ieee80211vap *); void (*iac_detach)(struct ieee80211vap *); int (*iac_check)(struct ieee80211vap *, const struct ieee80211_frame *wh); int (*iac_add)(struct ieee80211vap *, const uint8_t mac[IEEE80211_ADDR_LEN]); int (*iac_remove)(struct ieee80211vap *, const uint8_t mac[IEEE80211_ADDR_LEN]); int (*iac_flush)(struct ieee80211vap *); int (*iac_setpolicy)(struct ieee80211vap *, int); int (*iac_getpolicy)(struct ieee80211vap *); int (*iac_setioctl)(struct ieee80211vap *, struct ieee80211req *); int (*iac_getioctl)(struct ieee80211vap *, struct ieee80211req *); }; void ieee80211_aclator_register(const struct ieee80211_aclator *); void ieee80211_aclator_unregister(const struct ieee80211_aclator *); const struct ieee80211_aclator *ieee80211_aclator_get(const char *name); /* flags for ieee80211_fix_rate() */ #define IEEE80211_F_DOSORT 0x00000001 /* sort rate list */ #define IEEE80211_F_DOFRATE 0x00000002 /* use fixed legacy rate */ #define IEEE80211_F_DONEGO 0x00000004 /* calc negotiated rate */ #define IEEE80211_F_DODEL 0x00000008 /* delete ignore rate */ #define IEEE80211_F_DOBRS 0x00000010 /* check basic rate set */ #define IEEE80211_F_JOIN 0x00000020 /* sta joining our bss */ #define IEEE80211_F_DOFMCS 0x00000040 /* use fixed HT rate */ int ieee80211_fix_rate(struct ieee80211_node *, struct ieee80211_rateset *, int); /* * WME/WMM support. */ struct wmeParams { uint8_t wmep_acm; uint8_t wmep_aifsn; uint8_t wmep_logcwmin; /* log2(cwmin) */ uint8_t wmep_logcwmax; /* log2(cwmax) */ uint8_t wmep_txopLimit; uint8_t wmep_noackPolicy; /* 0 (ack), 1 (no ack) */ }; #define IEEE80211_TXOP_TO_US(_txop) ((_txop)<<5) #define IEEE80211_US_TO_TXOP(_us) ((_us)>>5) struct chanAccParams { uint8_t cap_info; /* version of the current set */ struct wmeParams cap_wmeParams[WME_NUM_AC]; }; struct ieee80211_wme_state { u_int wme_flags; #define WME_F_AGGRMODE 0x00000001 /* STATUS: WME agressive mode */ u_int wme_hipri_traffic; /* VI/VO frames in beacon interval */ u_int wme_hipri_switch_thresh;/* agressive mode switch thresh */ u_int wme_hipri_switch_hysteresis;/* agressive mode switch hysteresis */ struct wmeParams wme_params[4]; /* from assoc resp for each AC*/ struct chanAccParams wme_wmeChanParams; /* WME params applied to self */ struct chanAccParams wme_wmeBssChanParams;/* WME params bcast to stations */ struct chanAccParams wme_chanParams; /* params applied to self */ struct chanAccParams wme_bssChanParams; /* params bcast to stations */ int (*wme_update)(struct ieee80211com *); }; void ieee80211_wme_initparams(struct ieee80211vap *); void ieee80211_wme_updateparams(struct ieee80211vap *); void ieee80211_wme_updateparams_locked(struct ieee80211vap *); /* * Return the WME TID from a QoS frame. If no TID * is present return the index for the "non-QoS" entry. */ static __inline uint8_t ieee80211_gettid(const struct ieee80211_frame *wh) { uint8_t tid; if (IEEE80211_QOS_HAS_SEQ(wh)) { if (IEEE80211_IS_DSTODS(wh)) tid = ((const struct ieee80211_qosframe_addr4 *)wh)-> i_qos[0]; else tid = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; tid &= IEEE80211_QOS_TID; } else tid = IEEE80211_NONQOS_TID; return tid; } void ieee80211_waitfor_parent(struct ieee80211com *); void ieee80211_start_locked(struct ieee80211vap *); void ieee80211_init(void *); void ieee80211_start_all(struct ieee80211com *); void ieee80211_stop_locked(struct ieee80211vap *); void ieee80211_stop(struct ieee80211vap *); void ieee80211_stop_all(struct ieee80211com *); void ieee80211_suspend_all(struct ieee80211com *); void ieee80211_resume_all(struct ieee80211com *); void ieee80211_dturbo_switch(struct ieee80211vap *, int newflags); void ieee80211_swbmiss(void *arg); void ieee80211_beacon_miss(struct ieee80211com *); int ieee80211_new_state(struct ieee80211vap *, enum ieee80211_state, int); int ieee80211_new_state_locked(struct ieee80211vap *, enum ieee80211_state, int); void ieee80211_print_essid(const uint8_t *, int); void ieee80211_dump_pkt(struct ieee80211com *, const uint8_t *, int, int, int); extern const char *ieee80211_opmode_name[]; extern const char *ieee80211_state_name[IEEE80211_S_MAX]; extern const char *ieee80211_wme_acnames[]; /* * Beacon frames constructed by ieee80211_beacon_alloc * have the following structure filled in so drivers * can update the frame later w/ minimal overhead. */ struct ieee80211_beacon_offsets { uint8_t bo_flags[4]; /* update/state flags */ uint16_t *bo_caps; /* capabilities */ uint8_t *bo_cfp; /* start of CFParms element */ uint8_t *bo_tim; /* start of atim/dtim */ uint8_t *bo_wme; /* start of WME parameters */ uint8_t *bo_tdma; /* start of TDMA parameters */ uint8_t *bo_tim_trailer;/* start of fixed-size trailer */ uint16_t bo_tim_len; /* atim/dtim length in bytes */ uint16_t bo_tim_trailer_len;/* tim trailer length in bytes */ uint8_t *bo_erp; /* start of ERP element */ uint8_t *bo_htinfo; /* start of HT info element */ uint8_t *bo_ath; /* start of ATH parameters */ uint8_t *bo_appie; /* start of AppIE element */ uint16_t bo_appie_len; /* AppIE length in bytes */ uint16_t bo_csa_trailer_len; uint8_t *bo_csa; /* start of CSA element */ uint8_t *bo_quiet; /* start of Quiet element */ uint8_t *bo_meshconf; /* start of MESHCONF element */ uint8_t *bo_spare[3]; }; struct mbuf *ieee80211_beacon_alloc(struct ieee80211_node *, struct ieee80211_beacon_offsets *); /* * Beacon frame updates are signaled through calls to iv_update_beacon * with one of the IEEE80211_BEACON_* tokens defined below. For devices * that construct beacon frames on the host this can trigger a rebuild * or defer the processing. For devices that offload beacon frame * handling this callback can be used to signal a rebuild. The bo_flags * array in the ieee80211_beacon_offsets structure is intended to record * deferred processing requirements; ieee80211_beacon_update uses the * state to optimize work. Since this structure is owned by the driver * and not visible to the 802.11 layer drivers must supply an iv_update_beacon * callback that marks the flag bits and schedules (as necessary) an update. */ enum { IEEE80211_BEACON_CAPS = 0, /* capabilities */ IEEE80211_BEACON_TIM = 1, /* DTIM/ATIM */ IEEE80211_BEACON_WME = 2, IEEE80211_BEACON_ERP = 3, /* Extended Rate Phy */ IEEE80211_BEACON_HTINFO = 4, /* HT Information */ IEEE80211_BEACON_APPIE = 5, /* Application IE's */ IEEE80211_BEACON_CFP = 6, /* CFParms */ IEEE80211_BEACON_CSA = 7, /* Channel Switch Announcement */ IEEE80211_BEACON_TDMA = 9, /* TDMA Info */ IEEE80211_BEACON_ATH = 10, /* ATH parameters */ IEEE80211_BEACON_MESHCONF = 11, /* Mesh Configuration */ }; int ieee80211_beacon_update(struct ieee80211_node *, struct ieee80211_beacon_offsets *, struct mbuf *, int mcast); void ieee80211_csa_startswitch(struct ieee80211com *, struct ieee80211_channel *, int mode, int count); void ieee80211_csa_completeswitch(struct ieee80211com *); void ieee80211_csa_cancelswitch(struct ieee80211com *); void ieee80211_cac_completeswitch(struct ieee80211vap *); /* * Notification methods called from the 802.11 state machine. * Note that while these are defined here, their implementation * is OS-specific. */ void ieee80211_notify_node_join(struct ieee80211_node *, int newassoc); void ieee80211_notify_node_leave(struct ieee80211_node *); void ieee80211_notify_scan_done(struct ieee80211vap *); void ieee80211_notify_wds_discover(struct ieee80211_node *); void ieee80211_notify_csa(struct ieee80211com *, const struct ieee80211_channel *, int mode, int count); void ieee80211_notify_radar(struct ieee80211com *, const struct ieee80211_channel *); enum ieee80211_notify_cac_event { IEEE80211_NOTIFY_CAC_START = 0, /* CAC timer started */ IEEE80211_NOTIFY_CAC_STOP = 1, /* CAC intentionally stopped */ IEEE80211_NOTIFY_CAC_RADAR = 2, /* CAC stopped due to radar detectio */ IEEE80211_NOTIFY_CAC_EXPIRE = 3, /* CAC expired w/o radar */ }; void ieee80211_notify_cac(struct ieee80211com *, const struct ieee80211_channel *, enum ieee80211_notify_cac_event); void ieee80211_notify_node_deauth(struct ieee80211_node *); void ieee80211_notify_node_auth(struct ieee80211_node *); void ieee80211_notify_country(struct ieee80211vap *, const uint8_t [], const uint8_t cc[2]); void ieee80211_notify_radio(struct ieee80211com *, int); #endif /* _NET80211_IEEE80211_PROTO_H_ */