Import FreeBSD's net80211(9) of 1-nov-2005

This commit is contained in:
skrll 2005-11-18 16:20:29 +00:00
parent 02d3eacb6e
commit a0f92c66a0
18 changed files with 1378 additions and 625 deletions

View File

@ -29,7 +29,7 @@
* (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: src/sys/net80211/_ieee80211.h,v 1.2 2004/12/31 22:42:38 sam Exp $
* $FreeBSD: src/sys/net80211/_ieee80211.h,v 1.3 2005/08/10 17:42:13 sam Exp $
*/
#ifndef _NET80211__IEEE80211_H_
#define _NET80211__IEEE80211_H_
@ -152,6 +152,8 @@ struct ieee80211_channel {
(((_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_T(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_T) == IEEE80211_CHAN_T)
#define IEEE80211_IS_CHAN_108G(_c) \

View File

@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.19 2005/01/27 17:39:17 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.22 2005/08/10 16:22:29 sam Exp $");
/*
* IEEE 802.11 generic handler
@ -167,6 +167,10 @@ ieee80211_ifattach(struct ieee80211com *ic)
ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO_A;
if (IEEE80211_IS_CHAN_108G(c))
ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO_G;
if (ic->ic_curchan == NULL) {
/* arbitrarily pick the first channel */
ic->ic_curchan = &ic->ic_channels[i];
}
}
}
/* validate ic->ic_curmode */
@ -182,12 +186,14 @@ ieee80211_ifattach(struct ieee80211com *ic)
#endif
(void) ieee80211_setmode(ic, ic->ic_curmode);
if (ic->ic_lintval == 0)
ic->ic_lintval = IEEE80211_BINTVAL_DEFAULT;
ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */
if (ic->ic_bintval == 0)
ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
ic->ic_bmisstimeout = 7*ic->ic_bintval; /* default 7 beacons */
ic->ic_dtim_period = IEEE80211_DTIM_DEFAULT;
IEEE80211_BEACON_LOCK_INIT(ic, "beacon");
if (ic->ic_lintval == 0)
ic->ic_lintval = ic->ic_bintval;
ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
ieee80211_node_attach(ic);
@ -665,7 +671,7 @@ ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
/*
* Calculate a current rate if possible.
*/
if (ic->ic_fixed_rate != -1) {
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
/*
* A fixed rate is set, report that.
*/

View File

@ -29,7 +29,7 @@
* (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: src/sys/net80211/ieee80211.h,v 1.9 2005/06/10 04:42:34 sam Exp $
* $FreeBSD: src/sys/net80211/ieee80211.h,v 1.10 2005/07/22 16:55:27 sam Exp $
*/
#ifndef _NET80211_IEEE80211_H_
#define _NET80211_IEEE80211_H_
@ -622,10 +622,18 @@ enum {
/*
* RTS frame length parameters. The default is specified in
* the 802.11 spec. The max may be wrong for jumbo frames.
* the 802.11 spec as 512; we treat it as implementation-dependent
* so it's defined in ieee80211_var.h. The max may be wrong
* for jumbo frames.
*/
#define IEEE80211_RTS_DEFAULT 512
#define IEEE80211_RTS_MIN 1
#define IEEE80211_RTS_MAX IEEE80211_MAX_LEN
#define IEEE80211_RTS_MAX 2346
/*
* TX fragmentation parameters. As above for RTS, we treat
* default as implementation-dependent so define it elsewhere.
*/
#define IEEE80211_FRAG_MIN 256
#define IEEE80211_FRAG_MAX 2346
#endif /* _NET80211_IEEE80211_H_ */

View File

@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_acl.c,v 1.3 2004/12/31 22:42:38 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_acl.c,v 1.4 2005/08/13 17:31:48 sam Exp $");
/*
* IEEE 802.11 MAC ACL support.
@ -75,6 +75,7 @@ struct acl {
struct aclstate {
acl_lock_t as_lock;
int as_policy;
int as_nacls;
TAILQ_HEAD(, acl) as_list; /* list of all ACL's */
LIST_HEAD(, acl) as_hash[ACL_HASHSIZE];
struct ieee80211com *as_ic;
@ -94,7 +95,7 @@ acl_attach(struct ieee80211com *ic)
struct aclstate *as;
MALLOC(as, struct aclstate *, sizeof(struct aclstate),
M_DEVBUF, M_NOWAIT | M_ZERO);
M_80211_ACL, M_NOWAIT | M_ZERO);
if (as == NULL)
return 0;
ACL_LOCK_INIT(as, "acl");
@ -138,6 +139,7 @@ _acl_free(struct aclstate *as, struct acl *acl)
TAILQ_REMOVE(&as->as_list, acl, acl_list);
LIST_REMOVE(acl, acl_hash);
FREE(acl, M_80211_ACL);
as->as_nacls--;
}
static int
@ -186,6 +188,7 @@ acl_add(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN])
IEEE80211_ADDR_COPY(new->acl_macaddr, mac);
TAILQ_INSERT_TAIL(&as->as_list, new, acl_list);
LIST_INSERT_HEAD(&as->as_hash[hash], new, acl_hash);
as->as_nacls++;
ACL_UNLOCK(as);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ACL,
@ -260,6 +263,53 @@ acl_getpolicy(struct ieee80211com *ic)
return as->as_policy;
}
static int
acl_setioctl(struct ieee80211com *ic, struct ieee80211req *ireq)
{
return EINVAL;
}
static int
acl_getioctl(struct ieee80211com *ic, struct ieee80211req *ireq)
{
struct aclstate *as = ic->ic_as;
struct acl *acl;
struct ieee80211req_maclist *ap;
int error, space, i;
switch (ireq->i_val) {
case IEEE80211_MACCMD_POLICY:
ireq->i_val = as->as_policy;
return 0;
case IEEE80211_MACCMD_LIST:
space = as->as_nacls * IEEE80211_ADDR_LEN;
if (ireq->i_len == 0) {
ireq->i_len = space; /* return required space */
return 0; /* NB: must not error */
}
MALLOC(ap, struct ieee80211req_maclist *, space,
M_TEMP, M_NOWAIT);
if (ap == NULL)
return ENOMEM;
i = 0;
ACL_LOCK(as);
TAILQ_FOREACH(acl, &as->as_list, acl_list) {
IEEE80211_ADDR_COPY(ap[i].ml_macaddr, acl->acl_macaddr);
i++;
}
ACL_UNLOCK(as);
if (ireq->i_len >= space) {
error = copyout(ap, ireq->i_data, space);
ireq->i_len = space;
} else
error = copyout(ap, ireq->i_data, ireq->i_len);
FREE(ap, M_TEMP);
return error;
}
return EINVAL;
}
static const struct ieee80211_aclator mac = {
.iac_name = "mac",
.iac_attach = acl_attach,
@ -270,6 +320,8 @@ static const struct ieee80211_aclator mac = {
.iac_flush = acl_free_all,
.iac_setpolicy = acl_setpolicy,
.iac_getpolicy = acl_getpolicy,
.iac_setioctl = acl_setioctl,
.iac_getioctl = acl_getioctl,
};
/*

View File

@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_crypto.c,v 1.10 2005/07/09 23:15:30 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_crypto.c,v 1.12 2005/08/08 18:46:35 sam Exp $");
/*
* IEEE 802.11 generic crypto support.
@ -59,7 +59,8 @@ static int _ieee80211_crypto_delkey(struct ieee80211com *,
* Default "null" key management routines.
*/
static int
null_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k)
null_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{
if (!(&ic->ic_nw_keys[0] <= k &&
k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
@ -73,12 +74,14 @@ null_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k)
* packets through untouched when marked with the WEP bit
* and key index 0.
*/
if ((k->wk_flags & IEEE80211_KEY_GROUP) == 0)
return 0; /* NB: use key index 0 for ucast key */
else
return IEEE80211_KEYIX_NONE;
if (k->wk_flags & IEEE80211_KEY_GROUP)
return 0;
*keyix = 0; /* NB: use key index 0 for ucast key */
} else {
*keyix = k - ic->ic_nw_keys;
}
return k - ic->ic_nw_keys;
*rxkeyix = IEEE80211_KEYIX_NONE; /* XXX maybe *keyix? */
return 1;
}
static int
null_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
@ -113,9 +116,10 @@ cipher_attach(struct ieee80211com *ic, struct ieee80211_key *key)
*/
static __inline int
dev_key_alloc(struct ieee80211com *ic,
const struct ieee80211_key *key)
const struct ieee80211_key *key,
ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{
return ic->ic_crypto.cs_key_alloc(ic, key);
return ic->ic_crypto.cs_key_alloc(ic, key, keyix, rxkeyix);
}
static __inline int
@ -143,6 +147,7 @@ ieee80211_crypto_attach(struct ieee80211com *ic)
/* NB: we assume everything is pre-zero'd */
cs->cs_def_txkey = IEEE80211_KEYIX_NONE;
cs->cs_max_keyix = IEEE80211_WEP_NKID;
ciphers[IEEE80211_CIPHER_NONE] = &ieee80211_cipher_none;
for (i = 0; i < IEEE80211_WEP_NKID; i++)
ieee80211_crypto_resetkey(ic, &cs->cs_nw_keys[i],
@ -241,6 +246,7 @@ ieee80211_crypto_newkey(struct ieee80211com *ic,
{
#define N(a) (sizeof(a) / sizeof(a[0]))
const struct ieee80211_cipher *cip;
ieee80211_keyix keyix, rxkeyix;
void *keyctx;
int oflags;
@ -354,8 +360,7 @@ again:
* crypto we also call the driver to give us a key index.
*/
if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
key->wk_keyix = dev_key_alloc(ic, key);
if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
if (!dev_key_alloc(ic, key, &keyix, &rxkeyix)) {
/*
* Driver has no room; fallback to doing crypto
* in the host. We change the flags and start the
@ -382,6 +387,8 @@ again:
__func__, cip->ic_name);
return 0;
}
key->wk_keyix = keyix;
key->wk_rxkeyix = rxkeyix;
}
return 1;
#undef N
@ -393,7 +400,7 @@ again:
static int
_ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key)
{
u_int16_t keyix;
ieee80211_keyix keyix;
KASSERT(key->wk_cipher != NULL, ("No cipher!"));
@ -543,7 +550,7 @@ ieee80211_crypto_decap(struct ieee80211com *ic,
{
#define IEEE80211_WEP_HDRLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
#define IEEE80211_WEP_MINLEN \
(sizeof(struct ieee80211_frame) + ETHER_HDR_LEN + \
(sizeof(struct ieee80211_frame) + \
IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN)
struct ieee80211_key *k;
struct ieee80211_frame *wh;

View File

@ -29,7 +29,7 @@
* (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: src/sys/net80211/ieee80211_crypto.h,v 1.9 2005/06/10 16:11:24 sam Exp $
* $FreeBSD: src/sys/net80211/ieee80211_crypto.h,v 1.10 2005/08/08 18:46:35 sam Exp $
*/
#ifndef _NET80211_IEEE80211_CRYPTO_H_
#define _NET80211_IEEE80211_CRYPTO_H_
@ -66,18 +66,19 @@ struct ieee80211_cipher;
* Ciphers such as TKIP may also support mixed hardware/software
* encrypt/decrypt and MIC processing.
*/
/* XXX need key index typedef */
/* XXX pack better? */
/* XXX 48-bit rsc/tsc */
typedef u_int16_t ieee80211_keyix; /* h/w key index */
struct ieee80211_key {
u_int8_t wk_keylen; /* key length in bytes */
u_int8_t wk_flags;
u_int8_t wk_pad;
u_int16_t wk_flags;
#define IEEE80211_KEY_XMIT 0x01 /* key used for xmit */
#define IEEE80211_KEY_RECV 0x02 /* key used for recv */
#define IEEE80211_KEY_GROUP 0x04 /* key used for WPA group operation */
#define IEEE80211_KEY_SWCRYPT 0x10 /* host-based encrypt/decrypt */
#define IEEE80211_KEY_SWMIC 0x20 /* host-based enmic/demic */
u_int16_t wk_keyix; /* key index */
ieee80211_keyix wk_keyix; /* h/w key index */
ieee80211_keyix wk_rxkeyix; /* optional h/w rx key index */
u_int8_t wk_key[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
#define wk_txmic wk_key+IEEE80211_KEYBUF_SIZE+0 /* XXX can't () right */
#define wk_rxmic wk_key+IEEE80211_KEYBUF_SIZE+8 /* XXX can't () right */
@ -103,7 +104,7 @@ struct ieee80211_key {
#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+1)
#define IEEE80211_KEYIX_NONE ((u_int16_t) -1)
#define IEEE80211_KEYIX_NONE ((ieee80211_keyix) -1)
#if defined(__KERNEL__) || defined(_KERNEL)
@ -120,10 +121,12 @@ struct mbuf;
*/
struct ieee80211_crypto_state {
struct ieee80211_key cs_nw_keys[IEEE80211_WEP_NKID];
u_int16_t cs_def_txkey; /* default/group tx key index */
ieee80211_keyix cs_def_txkey; /* default/group tx key index */
u_int16_t cs_max_keyix; /* max h/w key index */
int (*cs_key_alloc)(struct ieee80211com *,
const struct ieee80211_key *);
const struct ieee80211_key *,
ieee80211_keyix *, ieee80211_keyix *);
int (*cs_key_delete)(struct ieee80211com *,
const struct ieee80211_key *);
int (*cs_key_set)(struct ieee80211com *,
@ -204,11 +207,11 @@ ieee80211_crypto_enmic(struct ieee80211com *ic,
*/
static __inline void
ieee80211_crypto_resetkey(struct ieee80211com *ic,
struct ieee80211_key *k, u_int16_t ix)
struct ieee80211_key *k, ieee80211_keyix ix)
{
k->wk_cipher = &ieee80211_cipher_none;;
k->wk_private = k->wk_cipher->ic_attach(ic, k);
k->wk_keyix = ix;
k->wk_keyix = k->wk_rxkeyix = ix;
k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
}

View File

@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_crypto_tkip.c,v 1.9 2005/06/10 16:11:24 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_crypto_tkip.c,v 1.10 2005/08/08 18:46:35 sam Exp $");
/*
* IEEE 802.11i TKIP crypto support.
@ -339,7 +339,9 @@ tkip_demic(struct ieee80211_key *k, struct mbuf *m, int force)
tkip.ic_miclen, mic0);
if (memcmp(mic, mic0, tkip.ic_miclen)) {
/* NB: 802.11 layer handles statistic and debug msg */
ieee80211_notify_michael_failure(ic, wh, k->wk_keyix);
ieee80211_notify_michael_failure(ic, wh,
k->wk_rxkeyix != IEEE80211_KEYIX_NONE ?
k->wk_rxkeyix : k->wk_keyix);
return 0;
}
}

View File

@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_input.c,v 1.62 2005/07/11 03:00:20 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_input.c,v 1.81 2005/08/10 16:22:29 sam Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -112,6 +112,8 @@ static struct mbuf *ieee80211_defrag(struct ieee80211com *,
static struct mbuf *ieee80211_decap(struct ieee80211com *, struct mbuf *, int);
static void ieee80211_send_error(struct ieee80211com *, struct ieee80211_node *,
const u_int8_t *mac, int subtype, int arg);
static void ieee80211_deliver_data(struct ieee80211com *,
struct ieee80211_node *, struct mbuf *);
static void ieee80211_node_pwrsave(struct ieee80211_node *, int enable);
static void ieee80211_recv_pspoll(struct ieee80211com *,
struct ieee80211_node *, struct mbuf *);
@ -136,7 +138,7 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
struct ieee80211_frame *wh;
struct ieee80211_key *key;
struct ether_header *eh;
int len, hdrspace;
int hdrspace;
u_int8_t dir, type, subtype;
u_int8_t *bssid;
u_int16_t rxseq;
@ -295,6 +297,8 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
if (dir != IEEE80211_FC1_DIR_FROMDS) {
IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
wh, "data", "%s", "unknown dir 0x%x", dir);
ic->ic_stats.is_rx_wrongdir++;
goto out;
}
@ -316,6 +320,8 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
case IEEE80211_M_IBSS:
case IEEE80211_M_AHDEMO:
if (dir != IEEE80211_FC1_DIR_NODS) {
IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
wh, "data", "%s", "unknown dir 0x%x", dir);
ic->ic_stats.is_rx_wrongdir++;
goto out;
}
@ -323,6 +329,8 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
break;
case IEEE80211_M_HOSTAP:
if (dir != IEEE80211_FC1_DIR_TODS) {
IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
wh, "data", "%s", "unknown dir 0x%x", dir);
ic->ic_stats.is_rx_wrongdir++;
goto out;
}
@ -469,54 +477,14 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
IEEE80211_NODE_STAT(ni, rx_data);
IEEE80211_NODE_STAT_ADD(ni, rx_bytes, m->m_pkthdr.len);
/* perform as a bridge within the AP */
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
(ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0) {
struct mbuf *m1 = NULL;
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
m1 = m_copypacket(m, M_DONTWAIT);
if (m1 == NULL)
ifp->if_oerrors++;
else
m1->m_flags |= M_MCAST;
} else {
/* XXX this dups work done in ieee80211_encap */
/* check if destination is associated */
struct ieee80211_node *ni1 =
ieee80211_find_node(&ic->ic_sta,
eh->ether_dhost);
if (ni1 != NULL) {
/* XXX check if authorized */
if (ni1->ni_associd != 0) {
m1 = m;
m = NULL;
}
/* XXX statistic? */
ieee80211_free_node(ni1);
}
}
if (m1 != NULL) {
len = m1->m_pkthdr.len;
IF_ENQUEUE(&ifp->if_snd, m1);
if (m != NULL)
ifp->if_omcasts++;
ifp->if_obytes += len;
}
}
if (m != NULL) {
if (ni->ni_vlan != 0) {
/* attach vlan tag */
/* XXX goto err? */
VLAN_INPUT_TAG(ifp, m, ni->ni_vlan, goto out);
}
(*ifp->if_input)(ifp, m);
}
ieee80211_deliver_data(ic, ni, m);
return IEEE80211_FC0_TYPE_DATA;
case IEEE80211_FC0_TYPE_MGT:
IEEE80211_NODE_STAT(ni, rx_mgmt);
if (dir != IEEE80211_FC1_DIR_NODS) {
IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
wh, "data", "%s", "unknown dir 0x%x", dir);
ic->ic_stats.is_rx_wrongdir++;
goto err;
}
@ -692,6 +660,69 @@ ieee80211_defrag(struct ieee80211com *ic, struct ieee80211_node *ni,
return mfrag;
}
static void
ieee80211_deliver_data(struct ieee80211com *ic,
struct ieee80211_node *ni, struct mbuf *m)
{
struct ether_header *eh = mtod(m, struct ether_header *);
struct ifnet *ifp = ic->ic_ifp;
/* perform as a bridge within the AP */
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
(ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0) {
struct mbuf *m1 = NULL;
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
m1 = m_copypacket(m, M_DONTWAIT);
if (m1 == NULL)
ifp->if_oerrors++;
else
m1->m_flags |= M_MCAST;
} else {
/*
* Check if the destination is known; if so
* and the port is authorized dispatch directly.
*/
struct ieee80211_node *sta =
ieee80211_find_node(&ic->ic_sta, eh->ether_dhost);
if (sta != NULL) {
if (ieee80211_node_is_authorized(sta)) {
/*
* Beware of sending to ourself; this
* needs to happen via the normal
* input path.
*/
if (sta != ic->ic_bss) {
m1 = m;
m = NULL;
}
} else {
ic->ic_stats.is_rx_unauth++;
IEEE80211_NODE_STAT(sta, rx_unauth);
}
ieee80211_free_node(sta);
}
}
if (m1 != NULL)
IF_HANDOFF(&ifp->if_snd, m1, ifp);
}
if (m != NULL) {
if (ni->ni_vlan != 0) {
/* attach vlan tag */
/* XXX goto err? */
VLAN_INPUT_TAG(ifp, m, ni->ni_vlan, goto out);
}
(*ifp->if_input)(ifp, m);
}
return;
out:
if (m != NULL) {
if (ic->ic_rawbpf)
bpf_mtap(ic->ic_rawbpf, m);
m_freem(m);
}
}
static struct mbuf *
ieee80211_decap(struct ieee80211com *ic, struct mbuf *m, int hdrlen)
{
@ -794,10 +825,11 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *m, int hdrlen)
/*
* Install received rate set information in the node's state block.
*/
static int
ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni,
u_int8_t *rates, u_int8_t *xrates, int flags)
int
ieee80211_setup_rates(struct ieee80211_node *ni,
const u_int8_t *rates, const u_int8_t *xrates, int flags)
{
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_rateset *rs = &ni->ni_rates;
memset(rs, 0, sizeof(*rs));
@ -820,7 +852,7 @@ ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni,
memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates);
rs->rs_nrates += nxrates;
}
return ieee80211_fix_rate(ic, ni, flags);
return ieee80211_fix_rate(ni, flags);
}
static void
@ -882,7 +914,7 @@ ieee80211_auth_open(struct ieee80211com *ic, struct ieee80211_frame *wh,
* authorized at this point so traffic can flow.
*/
if (ni->ni_authmode != IEEE80211_AUTH_8021X)
ieee80211_node_authorize(ic, ni);
ieee80211_node_authorize(ni);
break;
case IEEE80211_M_STA:
@ -922,7 +954,7 @@ ieee80211_send_error(struct ieee80211com *ic, struct ieee80211_node *ni,
int istmp;
if (ni == ic->ic_bss) {
ni = ieee80211_dup_bss(&ic->ic_sta, mac);
ni = ieee80211_tmp_node(ic, mac);
if (ni == NULL) {
/* XXX msg */
return;
@ -1105,7 +1137,7 @@ ieee80211_auth_shared(struct ieee80211com *ic, struct ieee80211_frame *wh,
IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
"[%s] station authenticated (shared key)\n",
ether_sprintf(ni->ni_macaddr));
ieee80211_node_authorize(ic, ni);
ieee80211_node_authorize(ni);
break;
default:
IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_AUTH,
@ -1361,8 +1393,12 @@ ieee80211_parse_wpa(struct ieee80211com *ic, u_int8_t *frm,
* version, mcast cipher, and 2 selector counts.
* Other, variable-length data, must be checked separately.
*/
KASSERT(ic->ic_flags & IEEE80211_F_WPA1,
("not WPA, flags 0x%x", ic->ic_flags));
if ((ic->ic_flags & IEEE80211_F_WPA1) == 0) {
IEEE80211_DISCARD_IE(ic,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
wh, "WPA", "not WPA, flags 0x%x", ic->ic_flags);
return IEEE80211_REASON_IE_INVALID;
}
if (len < 14) {
IEEE80211_DISCARD_IE(ic,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
@ -1524,8 +1560,12 @@ ieee80211_parse_rsn(struct ieee80211com *ic, u_int8_t *frm,
* version, mcast cipher, and 2 selector counts.
* Other, variable-length data, must be checked separately.
*/
KASSERT(ic->ic_flags & IEEE80211_F_WPA2,
("not RSN, flags 0x%x", ic->ic_flags));
if ((ic->ic_flags & IEEE80211_F_WPA2) == 0) {
IEEE80211_DISCARD_IE(ic,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
wh, "WPA", "not RSN, flags 0x%x", ic->ic_flags);
return IEEE80211_REASON_IE_INVALID;
}
if (len < 10) {
IEEE80211_DISCARD_IE(ic,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
@ -1652,7 +1692,7 @@ ieee80211_parse_wmeparams(struct ieee80211com *ic, u_int8_t *frm,
#undef MS
}
static void
void
ieee80211_saveie(u_int8_t **iep, const u_int8_t *ie)
{
u_int ielen = ie[1]+2;
@ -1669,38 +1709,6 @@ ieee80211_saveie(u_int8_t **iep, const u_int8_t *ie)
/* XXX note failure */
}
#ifdef IEEE80211_DEBUG
static void
dump_probe_beacon(u_int8_t subtype, int isnew,
const u_int8_t mac[IEEE80211_ADDR_LEN],
u_int8_t chan, u_int8_t bchan, u_int16_t capinfo, u_int16_t bintval,
u_int8_t erp, u_int8_t *ssid, u_int8_t *country)
{
printf("[%s] %s%s on chan %u (bss chan %u) ",
ether_sprintf(mac), isnew ? "new " : "",
ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT],
chan, bchan);
ieee80211_print_essid(ssid + 2, ssid[1]);
printf("\n");
if (isnew) {
printf("[%s] caps 0x%x bintval %u erp 0x%x",
ether_sprintf(mac), capinfo, bintval, erp);
if (country) {
#ifdef __FreeBSD__
printf(" country info %*D", country[1], country+2, " ");
#else
int i;
printf(" country info");
for (i = 0; i < country[1]; i++)
printf(" %02x", country[i+2]);
#endif
}
printf("\n");
}
}
#endif /* IEEE80211_DEBUG */
void
ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_node *ni,
@ -1720,10 +1728,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
switch (subtype) {
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
case IEEE80211_FC0_SUBTYPE_BEACON: {
u_int8_t *tstamp, *country, *tim;
u_int8_t chan, bchan, fhindex, erp;
u_int16_t capinfo, bintval, timoff;
u_int16_t fhdwell;
struct ieee80211_scanparams scan;
/*
* We process beacon/probe response frames:
@ -1754,32 +1759,29 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
* [tlv] WPA or RSN
*/
IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
tstamp = frm; frm += 8;
bintval = le16toh(*(u_int16_t *)frm); frm += 2;
capinfo = le16toh(*(u_int16_t *)frm); frm += 2;
ssid = rates = xrates = country = wpa = wme = tim = NULL;
bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
chan = bchan;
fhdwell = 0;
fhindex = 0;
erp = 0;
timoff = 0;
memset(&scan, 0, sizeof(scan));
scan.tstamp = frm; frm += 8;
scan.bintval = le16toh(*(u_int16_t *)frm); frm += 2;
scan.capinfo = le16toh(*(u_int16_t *)frm); frm += 2;
scan.bchan = ieee80211_chan2ieee(ic, ic->ic_curchan);
scan.chan = scan.bchan;
while (frm < efrm) {
switch (*frm) {
case IEEE80211_ELEMID_SSID:
ssid = frm;
scan.ssid = frm;
break;
case IEEE80211_ELEMID_RATES:
rates = frm;
scan.rates = frm;
break;
case IEEE80211_ELEMID_COUNTRY:
country = frm;
scan.country = frm;
break;
case IEEE80211_ELEMID_FHPARMS:
if (ic->ic_phytype == IEEE80211_T_FH) {
fhdwell = LE_READ_2(&frm[2]);
chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
fhindex = frm[6];
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:
@ -1788,17 +1790,17 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
* is problematic for multi-mode devices.
*/
if (ic->ic_phytype != IEEE80211_T_FH)
chan = frm[2];
scan.chan = frm[2];
break;
case IEEE80211_ELEMID_TIM:
/* XXX ATIM? */
tim = frm;
timoff = frm - mtod(m0, u_int8_t *);
scan.tim = frm;
scan.timoff = frm - mtod(m0, u_int8_t *);
break;
case IEEE80211_ELEMID_IBSSPARMS:
break;
case IEEE80211_ELEMID_XRATES:
xrates = frm;
scan.xrates = frm;
break;
case IEEE80211_ELEMID_ERP:
if (frm[1] != 1) {
@ -1808,16 +1810,16 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
ic->ic_stats.is_rx_elem_toobig++;
break;
}
erp = frm[2];
scan.erp = frm[2];
break;
case IEEE80211_ELEMID_RSN:
wpa = frm;
scan.wpa = frm;
break;
case IEEE80211_ELEMID_VENDOR:
if (iswpaoui(frm))
wpa = frm;
scan.wpa = frm;
else if (iswmeparam(frm) || iswmeinfo(frm))
wme = frm;
scan.wme = frm;
/* XXX Atheros OUI support */
break;
default:
@ -1829,21 +1831,23 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
}
frm += frm[1] + 2;
}
IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
IEEE80211_VERIFY_ELEMENT(scan.rates, IEEE80211_RATE_MAXSIZE);
IEEE80211_VERIFY_ELEMENT(scan.ssid, IEEE80211_NWID_LEN);
if (
#if IEEE80211_CHAN_MAX < 255
chan > IEEE80211_CHAN_MAX ||
scan.chan > IEEE80211_CHAN_MAX ||
#endif
isclr(ic->ic_chan_active, chan)) {
IEEE80211_DISCARD(ic, IEEE80211_MSG_ELEMID,
isclr(ic->ic_chan_active, scan.chan)) {
IEEE80211_DISCARD(ic,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
wh, ieee80211_mgt_subtype_name[subtype >>
IEEE80211_FC0_SUBTYPE_SHIFT],
"invalid channel %u", chan);
"invalid channel %u", scan.chan);
ic->ic_stats.is_rx_badchan++;
return;
}
if (chan != bchan && ic->ic_phytype != IEEE80211_T_FH) {
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;
@ -1854,13 +1858,24 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
* the rssi value should be correct even for
* different hop pattern in FH.
*/
IEEE80211_DISCARD(ic, IEEE80211_MSG_ELEMID,
IEEE80211_DISCARD(ic,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
wh, ieee80211_mgt_subtype_name[subtype >>
IEEE80211_FC0_SUBTYPE_SHIFT],
"for off-channel %u", chan);
"for off-channel %u", scan.chan);
ic->ic_stats.is_rx_chanmismatch++;
return;
}
if (!(IEEE80211_BINTVAL_MIN <= scan.bintval &&
scan.bintval <= IEEE80211_BINTVAL_MAX)) {
IEEE80211_DISCARD(ic,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
wh, ieee80211_mgt_subtype_name[subtype >>
IEEE80211_FC0_SUBTYPE_SHIFT],
"bogus beacon interval", scan.bintval);
ic->ic_stats.is_rx_badbintval++;
return;
}
/*
* Count frame now that we know it's to be processed.
@ -1881,27 +1896,27 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
((ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))) {
/* record tsf of last beacon */
memcpy(ni->ni_tstamp.data, tstamp,
memcpy(ni->ni_tstamp.data, scan.tstamp,
sizeof(ni->ni_tstamp));
if (ni->ni_erp != erp) {
if (ni->ni_erp != scan.erp) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
"[%s] erp change: was 0x%x, now 0x%x\n",
ether_sprintf(wh->i_addr2),
ni->ni_erp, erp);
ni->ni_erp, scan.erp);
if (ic->ic_curmode == IEEE80211_MODE_11G &&
(ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
ic->ic_flags |= IEEE80211_F_USEPROT;
else
ic->ic_flags &= ~IEEE80211_F_USEPROT;
ni->ni_erp = erp;
ni->ni_erp = scan.erp;
/* XXX statistic */
}
if ((ni->ni_capinfo ^ capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) {
if ((ni->ni_capinfo ^ scan.capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
"[%s] capabilities change: before 0x%x,"
" now 0x%x\n",
ether_sprintf(wh->i_addr2),
ni->ni_capinfo, capinfo);
ni->ni_capinfo, scan.capinfo);
/*
* NB: we assume short preamble doesn't
* change dynamically
@ -1909,105 +1924,51 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
ieee80211_set_shortslottime(ic,
ic->ic_curmode == IEEE80211_MODE_11A ||
(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
ni->ni_capinfo = capinfo;
ni->ni_capinfo = scan.capinfo;
/* XXX statistic */
}
if (wme != NULL &&
if (scan.wme != NULL &&
(ni->ni_flags & IEEE80211_NODE_QOS) &&
ieee80211_parse_wmeparams(ic, wme, wh) > 0)
ieee80211_parse_wmeparams(ic, scan.wme, wh) > 0)
ieee80211_wme_updateparams(ic);
if (tim != NULL) {
if (scan.tim != NULL) {
struct ieee80211_tim_ie *ie =
(struct ieee80211_tim_ie *) tim;
(struct ieee80211_tim_ie *) scan.tim;
ni->ni_dtim_count = ie->tim_count;
ni->ni_dtim_period = ie->tim_period;
}
/* NB: don't need the rest of this */
if ((ic->ic_flags & IEEE80211_F_SCAN) == 0)
return;
}
if (ni == ic->ic_bss &&
!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) {
#ifdef IEEE80211_DEBUG
if (ieee80211_msg_scan(ic))
dump_probe_beacon(subtype, 1,
wh->i_addr2, chan, bchan, capinfo,
bintval, erp, ssid, country);
#endif
/*
* Create a new entry. If scanning the entry goes
* in the scan cache. Otherwise, be particular when
* operating in adhoc mode--only take nodes marked
* as ibss participants so we don't populate our
* neighbor table with unintersting sta's.
*/
if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
if ((capinfo & IEEE80211_CAPINFO_IBSS) == 0)
return;
ni = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
wh->i_addr2);
} else
ni = ieee80211_dup_bss(&ic->ic_scan, wh->i_addr2);
if (ni == NULL)
return;
ni->ni_esslen = ssid[1];
memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
memcpy(ni->ni_essid, ssid + 2, ssid[1]);
} else if (ssid[1] != 0 &&
(ISPROBE(subtype) || ni->ni_esslen == 0)) {
/*
* Update ESSID at probe response to adopt
* hidden AP by Lucent/Cisco, which announces
* null ESSID in beacon.
*/
#ifdef IEEE80211_DEBUG
if (ieee80211_msg_scan(ic) ||
ieee80211_msg_debug(ic))
dump_probe_beacon(subtype, 0,
wh->i_addr2, chan, bchan, capinfo,
bintval, erp, ssid, country);
#endif
ni->ni_esslen = ssid[1];
memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
memcpy(ni->ni_essid, ssid + 2, ssid[1]);
}
ni->ni_scangen = ic->ic_scan.nt_scangen;
IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
memcpy(ni->ni_tstamp.data, tstamp, sizeof(ni->ni_tstamp));
ni->ni_intval = bintval;
ni->ni_capinfo = capinfo;
ni->ni_chan = &ic->ic_channels[chan];
ni->ni_fhdwell = fhdwell;
ni->ni_fhindex = fhindex;
ni->ni_erp = erp;
if (tim != NULL) {
struct ieee80211_tim_ie *ie =
(struct ieee80211_tim_ie *) tim;
ni->ni_dtim_count = ie->tim_count;
ni->ni_dtim_period = ie->tim_period;
if (ic->ic_flags & IEEE80211_F_SCAN)
ieee80211_add_scan(ic, &scan, wh,
subtype, rssi, rstamp);
return;
}
/*
* Record the byte offset from the mac header to
* the start of the TIM information element for
* use by hardware and/or to speedup software
* processing of beacon frames.
* If scanning, just pass information to the scan module.
*/
ni->ni_timoff = timoff;
/*
* Record optional information elements that might be
* used by applications or drivers.
*/
if (wme != NULL)
ieee80211_saveie(&ni->ni_wme_ie, wme);
if (wpa != NULL)
ieee80211_saveie(&ni->ni_wpa_ie, wpa);
/* NB: must be after ni_chan is setup */
ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT);
if (ic->ic_flags & IEEE80211_F_SCAN) {
ieee80211_add_scan(ic, &scan, wh,
subtype, rssi, rstamp);
return;
}
if (scan.capinfo & IEEE80211_CAPINFO_IBSS) {
if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
/*
* Create a new entry in the neighbor table.
*/
ni = ieee80211_add_neighbor(ic, wh, &scan);
} else {
/*
* Record tsf for potential resync.
*/
memcpy(ni->ni_tstamp.data, scan.tstamp,
sizeof(ni->ni_tstamp));
}
if (ni != NULL) {
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
}
}
break;
}
@ -2067,7 +2028,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
ni = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
wh->i_addr2);
} else
ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);
ni = ieee80211_tmp_node(ic, wh->i_addr2);
if (ni == NULL)
return;
allocbs = 1;
@ -2077,7 +2038,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
"[%s] recv probe req\n", ether_sprintf(wh->i_addr2));
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
rate = ieee80211_setup_rates(ic, ni, rates, xrates,
rate = ieee80211_setup_rates(ni, rates, xrates,
IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE
| IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
if (rate & IEEE80211_RATE_BASIC) {
@ -2119,6 +2080,11 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
IEEE80211_DISCARD(ic, IEEE80211_MSG_ACL,
wh, "auth", "%s", "disallowed by ACL");
ic->ic_stats.is_rx_acl++;
if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_AUTH,
(seq+1) | (IEEE80211_STATUS_UNSPECIFIED<<16));
}
return;
}
if (ic->ic_flags & IEEE80211_F_COUNTERM) {
@ -2156,7 +2122,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: {
u_int16_t capinfo, bintval;
u_int16_t capinfo, lintval;
struct ieee80211_rsnparms rsn;
u_int8_t reason;
@ -2193,7 +2159,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
return;
}
capinfo = le16toh(*(u_int16_t *)frm); frm += 2;
bintval = le16toh(*(u_int16_t *)frm); frm += 2;
lintval = le16toh(*(u_int16_t *)frm); frm += 2;
if (reassoc)
frm += 6; /* ignore current AP info */
ssid = rates = xrates = wpa = wme = NULL;
@ -2213,10 +2179,9 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
wpa = frm;
break;
case IEEE80211_ELEMID_VENDOR:
if (iswpaoui(frm)) {
if (ic->ic_flags & IEEE80211_F_WPA1)
wpa = frm;
} else if (iswmeinfo(frm))
if (iswpaoui(frm))
wpa = frm;
else if (iswmeinfo(frm))
wme = frm;
/* XXX Atheros OUI support */
break;
@ -2299,7 +2264,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
ic->ic_stats.is_rx_assoc_capmismatch++;
return;
}
rate = ieee80211_setup_rates(ic, ni, rates, xrates,
rate = ieee80211_setup_rates(ni, rates, xrates,
IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
/*
@ -2322,7 +2287,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
}
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
ni->ni_intval = bintval;
ni->ni_intval = lintval;
ni->ni_capinfo = capinfo;
ni->ni_chan = ic->ic_bss->ni_chan;
ni->ni_fhdwell = ic->ic_bss->ni_fhdwell;
@ -2420,7 +2385,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
}
IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
rate = ieee80211_setup_rates(ic, ni, rates, xrates,
rate = ieee80211_setup_rates(ni, rates, xrates,
IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
if (rate & IEEE80211_RATE_BASIC) {
@ -2537,7 +2502,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
IEEE80211_NODE_STAT(ni, rx_disassoc);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
"[%s] recv disassociated (reason %d)\n",
"[%s] recv disassociate (reason %d)\n",
ether_sprintf(ni->ni_macaddr), reason);
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
@ -2598,7 +2563,7 @@ ieee80211_node_pwrsave(struct ieee80211_node *ni, int enable)
*/
if (IEEE80211_NODE_SAVEQ_QLEN(ni) == 0) {
if (ic->ic_set_tim != NULL)
ic->ic_set_tim(ic, ni, 0); /* just in case */
ic->ic_set_tim(ni, 0); /* just in case */
return;
}
IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
@ -2623,7 +2588,7 @@ ieee80211_node_pwrsave(struct ieee80211_node *ni, int enable)
IF_ENQUEUE(&ic->ic_ifp->if_snd, m);
}
if (ic->ic_set_tim != NULL)
ic->ic_set_tim(ic, ni, 0);
ic->ic_set_tim(ni, 0);
}
/*
@ -2667,10 +2632,10 @@ ieee80211_recv_pspoll(struct ieee80211com *ic,
IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
"[%s] recv ps-poll, but queue empty\n",
ether_sprintf(wh->i_addr2));
ieee80211_send_nulldata(ic, ni);
ieee80211_send_nulldata(ieee80211_ref_node(ni));
ic->ic_stats.is_ps_qempty++; /* XXX node stat */
if (ic->ic_set_tim != NULL)
ic->ic_set_tim(ic, ni, 0); /* just in case */
ic->ic_set_tim(ni, 0); /* just in case */
return;
}
/*
@ -2688,7 +2653,7 @@ ieee80211_recv_pspoll(struct ieee80211com *ic,
"[%s] recv ps-poll, send packet, queue empty\n",
ether_sprintf(ni->ni_macaddr));
if (ic->ic_set_tim != NULL)
ic->ic_set_tim(ic, ni, 0);
ic->ic_set_tim(ni, 0);
}
m->m_flags |= M_PWR_SAV; /* bypass PS handling */
IF_ENQUEUE(&ic->ic_ifp->if_snd, m);
@ -2714,6 +2679,48 @@ ieee80211_getbssid(struct ieee80211com *ic, const struct ieee80211_frame *wh)
return wh->i_addr3;
}
void
ieee80211_note(struct ieee80211com *ic, 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(ic->ic_ifp, "%s", buf); /* NB: no \n */
}
void
ieee80211_note_frame(struct ieee80211com *ic,
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(ic->ic_ifp, "[%s] %s\n",
ether_sprintf(ieee80211_getbssid(ic, wh)), buf);
}
void
ieee80211_note_mac(struct ieee80211com *ic,
const u_int8_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(ic->ic_ifp, "[%s] %s\n", ether_sprintf(mac), buf);
}
static void
ieee80211_discard_frame(struct ieee80211com *ic,
const struct ieee80211_frame *wh,
@ -2721,11 +2728,12 @@ ieee80211_discard_frame(struct ieee80211com *ic,
{
va_list ap;
printf("[%s] discard ", ether_sprintf(ieee80211_getbssid(ic, wh)));
printf("[%s:%s] discard ", ic->ic_ifp->if_xname,
ether_sprintf(ieee80211_getbssid(ic, wh)));
if (type != NULL)
printf(" %s frame, ", type);
printf("%s frame, ", type);
else
printf(" frame, ");
printf("frame, ");
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
@ -2739,11 +2747,12 @@ ieee80211_discard_ie(struct ieee80211com *ic,
{
va_list ap;
printf("[%s] discard ", ether_sprintf(ieee80211_getbssid(ic, wh)));
printf("[%s:%s] discard ", ic->ic_ifp->if_xname,
ether_sprintf(ieee80211_getbssid(ic, wh)));
if (type != NULL)
printf(" %s information element, ", type);
printf("%s information element, ", type);
else
printf(" information element, ");
printf("information element, ");
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
@ -2757,11 +2766,11 @@ ieee80211_discard_mac(struct ieee80211com *ic,
{
va_list ap;
printf("[%s] discard ", ether_sprintf(mac));
printf("[%s:%s] discard ", ic->ic_ifp->if_xname, ether_sprintf(mac));
if (type != NULL)
printf(" %s frame, ", type);
printf("%s frame, ", type);
else
printf(" frame, ");
printf("frame, ");
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);

View File

@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.25 2005/07/06 15:38:27 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.35 2005/08/30 14:27:47 avatar Exp $");
/*
* IEEE 802.11 ioctl support (FreeBSD-specific)
@ -68,7 +68,8 @@ __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.25 2005/07/06 15:38:2
#include <dev/wi/if_wavelan_ieee.h>
#define IS_UP(_ic) \
(((_ic)->ic_ifp->if_flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP))
(((_ic)->ic_ifp->if_flags & IFF_UP) && \
((_ic)->ic_ifp->if_drv_flags & IFF_DRV_RUNNING))
#define IS_UP_AUTO(_ic) \
(IS_UP(_ic) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
@ -251,7 +252,7 @@ ieee80211_cfgget(struct ieee80211com *ic, u_long cmd, caddr_t data)
break;
case WI_RID_CURRENT_CHAN:
wreq.wi_val[0] = htole16(
ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
ieee80211_chan2ieee(ic, ic->ic_curchan));
wreq.wi_len = 1;
break;
case WI_RID_COMMS_QUALITY:
@ -273,7 +274,7 @@ ieee80211_cfgget(struct ieee80211com *ic, u_long cmd, caddr_t data)
wreq.wi_len = IEEE80211_ADDR_LEN / 2;
break;
case WI_RID_TX_RATE:
if (ic->ic_fixed_rate == -1)
if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
wreq.wi_val[0] = 0; /* auto */
else
wreq.wi_val[0] = htole16(
@ -447,7 +448,6 @@ findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
static int
ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[])
{
int i;
/*
* XXX don't permit a scan to be started unless we
@ -459,20 +459,6 @@ ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[])
*/
if (!IS_UP(ic))
return EINVAL;
if (ic->ic_ibss_chan == NULL ||
isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
if (isset(chanlist, i)) {
ic->ic_ibss_chan = &ic->ic_channels[i];
goto found;
}
return EINVAL; /* no active channels */
found:
;
}
if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
/*
* We force the state to INIT before calling ieee80211_new_state
@ -592,7 +578,7 @@ ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, caddr_t data)
return EINVAL;
if (wreq.wi_val[0] == 0) {
/* auto */
ic->ic_fixed_rate = -1;
ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
break;
}
rate = 2 * le16toh(wreq.wi_val[0]);
@ -826,18 +812,6 @@ ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, caddr_t data)
return error;
}
static struct ieee80211_channel *
getcurchan(struct ieee80211com *ic)
{
switch (ic->ic_state) {
case IEEE80211_S_INIT:
case IEEE80211_S_SCAN:
return ic->ic_des_chan;
default:
return ic->ic_ibss_chan;
}
}
static int
cap2cipher(int flag)
{
@ -1074,18 +1048,57 @@ ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ire
return error;
}
static void
get_sta_info(struct ieee80211req_sta_info *si, const struct ieee80211_node *ni)
{
struct ieee80211com *ic = ni->ni_ic;
struct stainforeq {
struct ieee80211com *ic;
struct ieee80211req_sta_info *si;
size_t space;
};
si->isi_ie_len = 0;
static size_t
sta_space(const struct ieee80211_node *ni, size_t *ielen)
{
*ielen = 0;
if (ni->ni_wpa_ie != NULL)
si->isi_ie_len += 2+ni->ni_wpa_ie[1];
*ielen += 2+ni->ni_wpa_ie[1];
if (ni->ni_wme_ie != NULL)
si->isi_ie_len += 2+ni->ni_wme_ie[1];
si->isi_len = sizeof(*si) + si->isi_ie_len, sizeof(u_int32_t);
si->isi_len = roundup(si->isi_len, sizeof(u_int32_t));
*ielen += 2+ni->ni_wme_ie[1];
return roundup(sizeof(struct ieee80211req_sta_info) + *ielen,
sizeof(u_int32_t));
}
static void
get_sta_space(void *arg, struct ieee80211_node *ni)
{
struct stainforeq *req = arg;
struct ieee80211com *ic = ni->ni_ic;
size_t ielen;
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
ni->ni_associd == 0) /* only associated stations */
return;
req->space += sta_space(ni, &ielen);
}
static void
get_sta_info(void *arg, struct ieee80211_node *ni)
{
struct stainforeq *req = arg;
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211req_sta_info *si;
size_t ielen, len;
u_int8_t *cp;
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
ni->ni_associd == 0) /* only associated stations */
return;
if (ni->ni_chan == IEEE80211_CHAN_ANYC) /* XXX bogus entry */
return;
len = sta_space(ni, &ielen);
if (len > req->space)
return;
si = req->si;
si->isi_len = len;
si->isi_ie_len = ielen;
si->isi_freq = ni->ni_chan->ic_freq;
si->isi_flags = ni->ni_chan->ic_flags;
si->isi_state = ni->ni_flags;
@ -1109,55 +1122,60 @@ get_sta_info(struct ieee80211req_sta_info *si, const struct ieee80211_node *ni)
si->isi_txseqs[0] = ni->ni_txseqs[0];
si->isi_rxseqs[0] = ni->ni_rxseqs[0];
}
if (ic->ic_opmode == IEEE80211_M_IBSS || ni->ni_associd != 0)
/* NB: leave all cases in case we relax ni_associd == 0 check */
if (ieee80211_node_is_authorized(ni))
si->isi_inact = ic->ic_inact_run;
else if (ieee80211_node_is_authorized(ni))
else if (ni->ni_associd != 0)
si->isi_inact = ic->ic_inact_auth;
else
si->isi_inact = ic->ic_inact_init;
si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
cp = (u_int8_t *)(si+1);
if (ni->ni_wpa_ie != NULL) {
memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
cp += 2+ni->ni_wpa_ie[1];
}
if (ni->ni_wme_ie != NULL) {
memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
cp += 2+ni->ni_wme_ie[1];
}
req->si = (struct ieee80211req_sta_info *)(((u_int8_t *)si) + len);
req->space -= len;
}
static int
ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
{
union {
struct ieee80211req_sta_info info;
char data[512]; /* XXX shrink? */
} u;
struct ieee80211req_sta_info *si = &u.info;
struct ieee80211_node_table *nt;
struct ieee80211_node *ni;
int error, space;
u_int8_t *p, *cp;
struct stainforeq req;
int error;
if (ireq->i_len < sizeof(struct stainforeq))
return EFAULT;
nt = &ic->ic_sta;
p = ireq->i_data;
space = ireq->i_len;
error = 0;
/* XXX locking */
TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
get_sta_info(si, ni);
if (si->isi_len > sizeof(u))
continue; /* XXX */
if (space < si->isi_len)
break;
cp = (u_int8_t *)(si+1);
if (ni->ni_wpa_ie != NULL) {
memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
cp += 2+ni->ni_wpa_ie[1];
}
if (ni->ni_wme_ie != NULL) {
memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
cp += 2+ni->ni_wme_ie[1];
}
error = copyout(si, p, si->isi_len);
if (error)
break;
p += si->isi_len;
space -= si->isi_len;
}
ireq->i_len -= space;
req.space = 0;
ieee80211_iterate_nodes(&ic->ic_sta, get_sta_space, &req);
if (req.space > ireq->i_len)
req.space = ireq->i_len;
if (req.space > 0) {
size_t space;
void *p;
space = req.space;
/* XXX M_WAITOK after driver lock released */
MALLOC(p, void *, space, M_TEMP, M_NOWAIT);
if (p == NULL)
return ENOMEM;
req.si = p;
ieee80211_iterate_nodes(&ic->ic_sta, get_sta_info, &req);
ireq->i_len = space - req.space;
error = copyout(p, ireq->i_data, ireq->i_len);
FREE(p, M_TEMP);
} else
ireq->i_len = 0;
return error;
}
@ -1224,6 +1242,14 @@ ieee80211_ioctl_getwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
return 0;
}
static int
ieee80211_ioctl_getmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
{
const struct ieee80211_aclator *acl = ic->ic_acl;
return (acl == NULL ? EINVAL : acl->iac_getioctl(ic, ireq));
}
/*
* When building the kernel with -O2 on the i386 architecture, gcc
* seems to want to inline this function into ieee80211_ioctl()
@ -1306,7 +1332,7 @@ ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
ireq->i_val = ic->ic_bss->ni_authmode;
break;
case IEEE80211_IOC_CHANNEL:
ireq->i_val = ieee80211_chan2ieee(ic, getcurchan(ic));
ireq->i_val = ieee80211_chan2ieee(ic, ic->ic_curchan);
break;
case IEEE80211_IOC_POWERSAVE:
if (ic->ic_flags & IEEE80211_F_PMGTON)
@ -1454,6 +1480,12 @@ ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
case IEEE80211_IOC_PUREG:
ireq->i_val = (ic->ic_flags & IEEE80211_F_PUREG) != 0;
break;
case IEEE80211_IOC_FRAGTHRESHOLD:
ireq->i_val = ic->ic_fragthreshold;
break;
case IEEE80211_IOC_MACCMD:
error = ieee80211_ioctl_getmaccmd(ic, ireq);
break;
default:
error = EINVAL;
break;
@ -1583,7 +1615,7 @@ ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq)
return ENOENT;
}
/* XXX error return */
ieee80211_crypto_delkey(ic, &ni->ni_ucastkey);
ieee80211_node_delucastkey(ni);
ieee80211_free_node(ni);
} else {
if (kid >= IEEE80211_WEP_NKID)
@ -1682,9 +1714,9 @@ ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
if (ni == NULL)
return EINVAL;
if (mlme.im_op == IEEE80211_MLME_AUTHORIZE)
ieee80211_node_authorize(ic, ni);
ieee80211_node_authorize(ni);
else
ieee80211_node_unauthorize(ic, ni);
ieee80211_node_unauthorize(ni);
ieee80211_free_node(ni);
break;
default:
@ -1719,7 +1751,7 @@ ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq)
}
static int
ieee80211_ioctl_maccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
ieee80211_ioctl_setmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
{
const struct ieee80211_aclator *acl = ic->ic_acl;
@ -1747,7 +1779,10 @@ ieee80211_ioctl_maccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
}
break;
default:
return EINVAL;
if (acl == NULL)
return EINVAL;
else
return acl->iac_setioctl(ic, ireq);
}
return 0;
}
@ -1793,9 +1828,6 @@ found:
;
}
memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
return IS_UP_AUTO(ic) ? ENETRESET : 0;
}
@ -2058,8 +2090,18 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
error = ENETRESET;
break;
}
if (error == ENETRESET && ic->ic_opmode == IEEE80211_M_MONITOR)
error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
if (error == ENETRESET &&
ic->ic_opmode == IEEE80211_M_MONITOR) {
if (IS_UP(ic)) {
/*
* Monitor mode can switch directly.
*/
if (ic->ic_des_chan != IEEE80211_CHAN_ANYC)
ic->ic_curchan = ic->ic_des_chan;
error = ic->ic_reset(ic->ic_ifp);
} else
error = 0;
}
break;
case IEEE80211_IOC_POWERSAVE:
switch (ireq->i_val) {
@ -2089,8 +2131,8 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
break;
case IEEE80211_IOC_RTSTHRESHOLD:
if (!(IEEE80211_RTS_MIN < ireq->i_val &&
ireq->i_val < IEEE80211_RTS_MAX))
if (!(IEEE80211_RTS_MIN <= ireq->i_val &&
ireq->i_val <= IEEE80211_RTS_MAX))
return EINVAL;
ic->ic_rtsthreshold = ireq->i_val;
error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
@ -2284,7 +2326,7 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
error = ieee80211_ioctl_macmac(ic, ireq);
break;
case IEEE80211_IOC_MACCMD:
error = ieee80211_ioctl_maccmd(ic, ireq);
error = ieee80211_ioctl_setmaccmd(ic, ireq);
break;
case IEEE80211_IOC_STA_TXPOW:
error = ieee80211_ioctl_setstatxpow(ic, ireq);
@ -2314,7 +2356,7 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
return EINVAL;
if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
ireq->i_val <= IEEE80211_BINTVAL_MAX) {
ic->ic_lintval = ireq->i_val;
ic->ic_bintval = ireq->i_val;
error = ENETRESET; /* requires restart */
} else
error = EINVAL;
@ -2328,6 +2370,16 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
if (ic->ic_curmode == IEEE80211_MODE_11G)
error = ENETRESET;
break;
case IEEE80211_IOC_FRAGTHRESHOLD:
if ((ic->ic_caps & IEEE80211_C_TXFRAG) == 0 &&
ireq->i_val != IEEE80211_FRAG_MAX)
return EINVAL;
if (!(IEEE80211_FRAG_MIN <= ireq->i_val &&
ireq->i_val <= IEEE80211_FRAG_MAX))
return EINVAL;
ic->ic_fragthreshold = ireq->i_val;
error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
break;
default:
error = EINVAL;
break;

View File

@ -29,7 +29,7 @@
* (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: src/sys/net80211/ieee80211_ioctl.h,v 1.10 2005/07/06 15:38:27 sam Exp $
* $FreeBSD: src/sys/net80211/ieee80211_ioctl.h,v 1.14 2005/08/13 17:31:48 sam Exp $
*/
#ifndef _NET80211_IEEE80211_IOCTL_H_
#define _NET80211_IEEE80211_IOCTL_H_
@ -149,6 +149,8 @@ struct ieee80211_stats {
u_int32_t is_tx_badcipher; /* tx failed 'cuz key type */
u_int32_t is_tx_nodefkey; /* tx failed 'cuz no defkey */
u_int32_t is_tx_noheadroom; /* tx failed 'cuz no space */
u_int32_t is_tx_fragframes; /* tx frames fragmented */
u_int32_t is_tx_frags; /* tx fragments created */
u_int32_t is_scan_active; /* active scans started */
u_int32_t is_scan_passive; /* passive scans started */
u_int32_t is_node_timeout; /* nodes timed out inactivity */
@ -173,6 +175,13 @@ struct ieee80211_stats {
u_int32_t is_ps_unassoc; /* ps-poll for unassoc. sta */
u_int32_t is_ps_badaid; /* ps-poll w/ incorrect aid */
u_int32_t is_ps_qempty; /* ps-poll w/ nothing to send */
u_int32_t is_ff_badhdr; /* fast frame rx'd w/ bad hdr */
u_int32_t is_ff_tooshort; /* fast frame rx decap error */
u_int32_t is_ff_split; /* fast frame rx split error */
u_int32_t is_ff_decap; /* fast frames decap'd */
u_int32_t is_ff_encap; /* fast frames encap'd for tx */
u_int32_t is_rx_badbintval; /* rx frame w/ bogus bintval */
u_int32_t is_spare[9];
};
/*
@ -243,6 +252,12 @@ enum {
IEEE80211_MACCMD_POLICY_DENY = 2, /* set policy: deny traffic */
IEEE80211_MACCMD_FLUSH = 3, /* flush ACL database */
IEEE80211_MACCMD_DETACH = 4, /* detach ACL policy */
IEEE80211_MACCMD_POLICY = 5, /* get ACL policy */
IEEE80211_MACCMD_LIST = 6, /* get ACL database */
};
struct ieee80211req_maclist {
u_int8_t ml_macaddr[IEEE80211_ADDR_LEN];
};
/*
@ -427,6 +442,7 @@ struct ieee80211req {
#define IEEE80211_IOC_ADDMAC 54 /* add sta to MAC ACL table */
#define IEEE80211_IOC_DELMAC 55 /* del sta from MAC ACL table */
#define IEEE80211_IOC_PUREG 56 /* pure 11g (no 11b stations) */
#define IEEE80211_IOC_FRAGTHRESHOLD 73 /* tx fragmentation threshold */
/*
* Scan result data returned for IEEE80211_IOC_SCAN_RESULTS.

View File

@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_freebsd.c,v 1.7 2005/03/29 19:36:42 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_freebsd.c,v 1.8 2005/08/08 18:46:35 sam Exp $");
/*
* IEEE 802.11 support (FreeBSD-specific code)
@ -261,9 +261,10 @@ ieee80211_notify_replay_failure(struct ieee80211com *ic,
struct ifnet *ifp = ic->ic_ifp;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
"[%s] %s replay detected <rsc %ju, csc %ju, keyix %u>\n",
ether_sprintf(wh->i_addr2), k->wk_cipher->ic_name,
(intmax_t) rsc, (intmax_t) k->wk_keyrsc, k->wk_keyix);
"[%s] %s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>\n",
ether_sprintf(wh->i_addr2), k->wk_cipher->ic_name,
(intmax_t) rsc, (intmax_t) k->wk_keyrsc,
k->wk_keyix, k->wk_rxkeyix);
if (ifp != NULL) { /* NB: for cipher test modules */
struct ieee80211_replay_event iev;
@ -271,7 +272,10 @@ ieee80211_notify_replay_failure(struct ieee80211com *ic,
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;
iev.iev_keyix = k->wk_keyix;
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;
iev.iev_rsc = rsc;
rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev));

View File

@ -24,7 +24,7 @@
* (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: src/sys/net80211/ieee80211_freebsd.h,v 1.5 2005/07/06 01:55:17 sam Exp $
* $FreeBSD: src/sys/net80211/ieee80211_freebsd.h,v 1.6 2005/08/08 18:46:36 sam Exp $
*/
#ifndef _NET80211_IEEE80211_FREEBSD_H_
#define _NET80211_IEEE80211_FREEBSD_H_
@ -43,12 +43,15 @@ typedef struct mtx ieee80211_beacon_lock_t;
/*
* Node locking definitions.
* NB: MTX_DUPOK is because we don't generate per-interface strings.
*/
typedef struct mtx ieee80211_node_lock_t;
#define IEEE80211_NODE_LOCK_INIT(_nt, _name) \
mtx_init(&(_nt)->nt_nodelock, _name, "802.11 node table", MTX_DEF)
mtx_init(&(_nt)->nt_nodelock, _name, "802.11 node table", \
MTX_DEF | MTX_DUPOK)
#define IEEE80211_NODE_LOCK_DESTROY(_nt) mtx_destroy(&(_nt)->nt_nodelock)
#define IEEE80211_NODE_LOCK(_nt) mtx_lock(&(_nt)->nt_nodelock)
#define IEEE80211_NODE_IS_LOCKED(_nt) mtx_owned(&(_nt)->nt_nodelock)
#define IEEE80211_NODE_UNLOCK(_nt) mtx_unlock(&(_nt)->nt_nodelock)
#define IEEE80211_NODE_LOCK_ASSERT(_nt) \
mtx_assert(&(_nt)->nt_nodelock, MA_OWNED)

View File

@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.48 2005/07/06 01:51:44 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.65 2005/08/13 17:50:21 sam Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -72,11 +72,11 @@ static void ieee80211_free_allnodes(struct ieee80211_node_table *);
static void ieee80211_timeout_scan_candidates(struct ieee80211_node_table *);
static void ieee80211_timeout_stations(struct ieee80211_node_table *);
static void ieee80211_set_tim(struct ieee80211com *,
struct ieee80211_node *, int set);
static void ieee80211_set_tim(struct ieee80211_node *, int set);
static void ieee80211_node_table_init(struct ieee80211com *ic,
struct ieee80211_node_table *nt, const char *name, int inact,
struct ieee80211_node_table *nt, const char *name,
int inact, int keyixmax,
void (*timeout)(struct ieee80211_node_table *));
static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt);
@ -86,11 +86,6 @@ void
ieee80211_node_attach(struct ieee80211com *ic)
{
ieee80211_node_table_init(ic, &ic->ic_sta, "station",
IEEE80211_INACT_INIT, ieee80211_timeout_stations);
ieee80211_node_table_init(ic, &ic->ic_scan, "scan",
IEEE80211_INACT_SCAN, ieee80211_timeout_scan_candidates);
ic->ic_node_alloc = node_alloc;
ic->ic_node_free = node_free;
ic->ic_node_cleanup = node_cleanup;
@ -102,10 +97,17 @@ ieee80211_node_attach(struct ieee80211com *ic)
ic->ic_inact_run = IEEE80211_INACT_RUN;
ic->ic_inact_probe = IEEE80211_INACT_PROBE;
/* XXX defer */
if (ic->ic_max_aid == 0)
ic->ic_max_aid = IEEE80211_AID_DEF;
else if (ic->ic_max_aid > IEEE80211_AID_MAX)
/* NB: driver should override */
ic->ic_max_aid = IEEE80211_AID_DEF;
ic->ic_set_tim = ieee80211_set_tim;
}
void
ieee80211_node_lateattach(struct ieee80211com *ic)
{
struct ieee80211_rsnparms *rsn;
if (ic->ic_max_aid > IEEE80211_AID_MAX)
ic->ic_max_aid = IEEE80211_AID_MAX;
MALLOC(ic->ic_aid_bitmap, u_int32_t *,
howmany(ic->ic_max_aid, 32) * sizeof(u_int32_t),
@ -124,22 +126,20 @@ ieee80211_node_attach(struct ieee80211com *ic)
/* XXX no way to recover */
printf("%s: no memory for TIM bitmap!\n", __func__);
}
ic->ic_set_tim = ieee80211_set_tim; /* NB: driver should override */
}
void
ieee80211_node_lateattach(struct ieee80211com *ic)
{
struct ieee80211_node *ni;
struct ieee80211_rsnparms *rsn;
ieee80211_node_table_init(ic, &ic->ic_sta, "station",
IEEE80211_INACT_INIT, ic->ic_crypto.cs_max_keyix,
ieee80211_timeout_stations);
ieee80211_node_table_init(ic, &ic->ic_scan, "scan",
IEEE80211_INACT_SCAN, 0,
ieee80211_timeout_scan_candidates);
ni = ieee80211_alloc_node(&ic->ic_scan, ic->ic_myaddr);
KASSERT(ni != NULL, ("unable to setup inital BSS node"));
ieee80211_reset_bss(ic);
/*
* Setup "global settings" in the bss node so that
* each new station automatically inherits them.
*/
rsn = &ni->ni_rsn;
rsn = &ic->ic_bss->ni_rsn;
/* WEP, TKIP, and AES-CCM are always supported */
rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_WEP;
rsn->rsn_ucastcipherset |= 1<<IEEE80211_CIPHER_TKIP;
@ -171,8 +171,7 @@ ieee80211_node_lateattach(struct ieee80211com *ic)
rsn->rsn_keymgmtset = WPA_ASE_8021X_UNSPEC | WPA_ASE_8021X_PSK;
rsn->rsn_keymgmt = WPA_ASE_8021X_PSK;
ic->ic_bss = ieee80211_ref_node(ni); /* hold reference */
ic->ic_auth = ieee80211_authenticator_get(ni->ni_authmode);
ic->ic_auth = ieee80211_authenticator_get(ic->ic_bss->ni_authmode);
}
void
@ -200,14 +199,16 @@ ieee80211_node_detach(struct ieee80211com *ic)
*/
void
ieee80211_node_authorize(struct ieee80211com *ic, struct ieee80211_node *ni)
ieee80211_node_authorize(struct ieee80211_node *ni)
{
struct ieee80211com *ic = ni->ni_ic;
ni->ni_flags |= IEEE80211_NODE_AUTH;
ni->ni_inact_reload = ic->ic_inact_run;
}
void
ieee80211_node_unauthorize(struct ieee80211com *ic, struct ieee80211_node *ni)
ieee80211_node_unauthorize(struct ieee80211_node *ni)
{
ni->ni_flags &= ~IEEE80211_NODE_AUTH;
}
@ -260,16 +261,12 @@ ieee80211_reset_scan(struct ieee80211com *ic)
} else
memcpy(ic->ic_chan_scan, ic->ic_chan_active,
sizeof(ic->ic_chan_active));
/* NB: hack, setup so next_scan starts with the first channel */
if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC)
ieee80211_set_chan(ic, ic->ic_bss,
&ic->ic_channels[IEEE80211_CHAN_MAX]);
#ifdef IEEE80211_DEBUG
if (ieee80211_msg_scan(ic)) {
printf("%s: scan set:", __func__);
dump_chanlist(ic->ic_chan_scan);
printf(" start chan %u\n",
ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
ieee80211_chan2ieee(ic, ic->ic_curchan));
}
#endif /* IEEE80211_DEBUG */
}
@ -323,7 +320,7 @@ ieee80211_next_scan(struct ieee80211com *ic)
*/
ic->ic_mgt_timer = 0;
chan = ic->ic_bss->ni_chan;
chan = ic->ic_curchan;
do {
if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX])
chan = &ic->ic_channels[0];
@ -331,28 +328,19 @@ ieee80211_next_scan(struct ieee80211com *ic)
clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan));
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: chan %d->%d\n", __func__,
ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan),
ieee80211_chan2ieee(ic, ic->ic_curchan),
ieee80211_chan2ieee(ic, chan));
ieee80211_set_chan(ic, ic->ic_bss, chan);
#ifdef notyet
/* XXX driver state change */
ic->ic_curchan = chan;
/*
* Scan next channel. If doing an active scan
* and the channel is not marked passive-only
* then send a probe request. Otherwise just
* listen for beacons on the channel.
* XXX drivers should do this as needed,
* XXX for now maintain compatibility
*/
if ((ic->ic_flags & IEEE80211_F_ASCAN) &&
(ni->ni_chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) {
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0);
}
#else
ic->ic_bss->ni_rates =
ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)];
ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
#endif
return 1;
}
} while (chan != ic->ic_bss->ni_chan);
} while (chan != ic->ic_curchan);
ieee80211_end_scan(ic);
return 0;
}
@ -394,7 +382,7 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
}
IEEE80211_NODE_UNLOCK(nt);
ni = ieee80211_alloc_node(nt, ic->ic_myaddr);
ni = ieee80211_alloc_node(&ic->ic_sta, ic->ic_myaddr);
if (ni == NULL) {
/* XXX recovery? */
return;
@ -403,7 +391,7 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
ni->ni_esslen = ic->ic_des_esslen;
memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
copy_bss(ni, ic->ic_bss);
ni->ni_intval = ic->ic_lintval;
ni->ni_intval = ic->ic_bintval;
if (ic->ic_flags & IEEE80211_F_PRIVACY)
ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
if (ic->ic_phytype == IEEE80211_T_FH) {
@ -422,6 +410,7 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
* Fix the channel and related attributes.
*/
ieee80211_set_chan(ic, ni, chan);
ic->ic_curchan = chan;
ic->ic_curmode = ieee80211_chan2mode(ic, chan);
/*
* Do mode-specific rate setup.
@ -455,11 +444,14 @@ ieee80211_reset_bss(struct ieee80211com *ic)
ic->ic_bss = ieee80211_ref_node(ni);
if (obss != NULL) {
copy_bss(ni, obss);
ni->ni_intval = ic->ic_lintval;
ni->ni_intval = ic->ic_bintval;
ieee80211_free_node(obss);
}
}
/* XXX tunable */
#define STA_FAILS_MAX 2 /* assoc failures before ignored */
static int
ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
{
@ -487,8 +479,7 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
fail |= 0x04;
}
rate = ieee80211_fix_rate(ic, ni,
IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
rate = ieee80211_fix_rate(ni, IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE);
if (rate & IEEE80211_RATE_BASIC)
fail |= 0x08;
if (ic->ic_des_esslen != 0 &&
@ -498,9 +489,12 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
!IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
fail |= 0x20;
if (ni->ni_fails >= STA_FAILS_MAX)
fail |= 0x40;
#ifdef IEEE80211_DEBUG
if (ieee80211_msg_scan(ic)) {
printf(" %c %s", fail ? '-' : '+',
printf(" %c %s",
fail & 0x40 ? '=' : fail & 0x80 ? '^' : fail ? '-' : '+',
ether_sprintf(ni->ni_macaddr));
printf(" %s%c", ether_sprintf(ni->ni_bssid),
fail & 0x20 ? '!' : ' ');
@ -547,6 +541,7 @@ ieee80211_node_compare(struct ieee80211com *ic,
{
u_int8_t maxa, maxb;
u_int8_t rssia, rssib;
int weight;
/* privacy support preferred */
if ((a->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) &&
@ -556,6 +551,11 @@ ieee80211_node_compare(struct ieee80211com *ic,
(b->ni_capinfo & IEEE80211_CAPINFO_PRIVACY))
return -1;
/* compare count of previous failures */
weight = b->ni_fails - a->ni_fails;
if (abs(weight) > 1)
return weight;
rssia = ic->ic_node_getrssi(a);
rssib = ic->ic_node_getrssi(b);
if (abs(rssib - rssia) < 5) {
@ -672,6 +672,17 @@ ieee80211_end_scan(struct ieee80211com *ic)
ieee80211_create_ibss(ic, ic->ic_ibss_chan);
return;
}
/*
* Decrement the failure counts so entries will be
* reconsidered the next time around. We really want
* to do this only for sta's where we've previously
had some success.
*/
IEEE80211_NODE_LOCK(nt);
TAILQ_FOREACH(ni, &nt->nt_node, ni_list)
if (ni->ni_fails)
ni->ni_fails--;
IEEE80211_NODE_UNLOCK(nt);
/*
* Reset the list of channels to scan and start again.
*/
@ -685,23 +696,6 @@ ieee80211_end_scan(struct ieee80211com *ic)
"macaddr bssid chan rssi rate flag wep essid");
IEEE80211_NODE_LOCK(nt);
TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
if (ni->ni_fails) {
/*
* The configuration of the access points may change
* during my scan. So delete the entry for the AP
* and retry to associate if there is another beacon.
*/
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: skip scan candidate %s, fails %u\n",
__func__, ether_sprintf(ni->ni_macaddr),
ni->ni_fails);
ni->ni_fails++;
#if 0
if (ni->ni_fails++ > 2)
ieee80211_free_node(ni);
#endif
continue;
}
if (ieee80211_match_bss(ic, ni) == 0) {
if (selbs == NULL)
selbs = ni;
@ -733,8 +727,9 @@ ieee80211_end_scan(struct ieee80211com *ic)
* Return !0 if the BSSID changed, 0 otherwise.
*/
int
ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni)
ieee80211_ibss_merge(struct ieee80211_node *ni)
{
struct ieee80211com *ic = ni->ni_ic;
if (ni == ic->ic_bss ||
IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) {
@ -772,7 +767,7 @@ ieee80211_sta_join(struct ieee80211com *ic, struct ieee80211_node *selbs)
* Delete unusable rates; we've already checked
* that the negotiated rate set is acceptable.
*/
ieee80211_fix_rate(ic, selbs, IEEE80211_F_DODEL);
ieee80211_fix_rate(selbs, IEEE80211_F_DODEL);
/*
* Fillin the neighbor table; it will already
* exist if we are simply switching mastership.
@ -798,6 +793,7 @@ ieee80211_sta_join(struct ieee80211com *ic, struct ieee80211_node *selbs)
* mode is locked.
*/
ic->ic_curmode = ieee80211_chan2mode(ic, selbs->ni_chan);
ic->ic_curchan = selbs->ni_chan;
ieee80211_reset_erp(ic);
ieee80211_wme_initparams(ic);
@ -863,7 +859,7 @@ node_cleanup(struct ieee80211_node *ni)
*/
IEEE80211_NODE_SAVEQ_DRAIN(ni, qlen);
if (qlen != 0 && ic->ic_set_tim != NULL)
ic->ic_set_tim(ic, ni, 0);
ic->ic_set_tim(ni, 0);
ni->ni_associd = 0;
if (ni->ni_challenge != NULL) {
@ -887,7 +883,10 @@ node_cleanup(struct ieee80211_node *ni)
m_freem(ni->ni_rxfrag[i]);
ni->ni_rxfrag[i] = NULL;
}
ieee80211_crypto_delkey(ic, &ni->ni_ucastkey);
/*
* Must be careful here to remove any key map entry w/o a LOR.
*/
ieee80211_node_delucastkey(ni);
#undef N
}
@ -955,6 +954,42 @@ ieee80211_alloc_node(struct ieee80211_node_table *nt, const u_int8_t *macaddr)
return ni;
}
/*
* Craft a temporary node suitable for sending a management frame
* to the specified station. We craft only as much state as we
* need to do the work since the node will be immediately reclaimed
* once the send completes.
*/
struct ieee80211_node *
ieee80211_tmp_node(struct ieee80211com *ic, const u_int8_t *macaddr)
{
struct ieee80211_node *ni;
ni = ic->ic_node_alloc(&ic->ic_sta);
if (ni != NULL) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
"%s %p<%s>\n", __func__, ni, ether_sprintf(macaddr));
IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
ieee80211_node_initref(ni); /* mark referenced */
ni->ni_txpower = ic->ic_bss->ni_txpower;
/* NB: required by ieee80211_fix_rate */
ieee80211_set_chan(ic, ni, ic->ic_bss->ni_chan);
ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey,
IEEE80211_KEYIX_NONE);
/* XXX optimize away */
IEEE80211_NODE_SAVEQ_INIT(ni, "unknown");
ni->ni_table = NULL; /* NB: pedantic */
ni->ni_ic = ic;
} else {
/* XXX msg */
ic->ic_stats.is_rx_nodealloc++;
}
return ni;
}
struct ieee80211_node *
ieee80211_dup_bss(struct ieee80211_node_table *nt, const u_int8_t *macaddr)
{
@ -1047,13 +1082,188 @@ ieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt,
/* XXX no rate negotiation; just dup */
ni->ni_rates = ic->ic_bss->ni_rates;
if (ic->ic_newassoc != NULL)
ic->ic_newassoc(ic, ni, 1);
ic->ic_newassoc(ni, 1);
/* XXX not right for 802.1x/WPA */
ieee80211_node_authorize(ic, ni);
ieee80211_node_authorize(ni);
}
return ni;
}
#ifdef IEEE80211_DEBUG
static void
dump_probe_beacon(u_int8_t subtype, int isnew,
const u_int8_t mac[IEEE80211_ADDR_LEN],
const struct ieee80211_scanparams *sp)
{
printf("[%s] %s%s on chan %u (bss chan %u) ",
ether_sprintf(mac), isnew ? "new " : "",
ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT],
sp->chan, sp->bchan);
ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]);
printf("\n");
if (isnew) {
printf("[%s] caps 0x%x bintval %u erp 0x%x",
ether_sprintf(mac), sp->capinfo, sp->bintval, sp->erp);
if (sp->country != NULL) {
#ifdef __FreeBSD__
printf(" country info %*D",
sp->country[1], sp->country+2, " ");
#else
int i;
printf(" country info");
for (i = 0; i < sp->country[1]; i++)
printf(" %02x", sp->country[i+2]);
#endif
}
printf("\n");
}
}
#endif /* IEEE80211_DEBUG */
static void
saveie(u_int8_t **iep, const u_int8_t *ie)
{
if (ie == NULL)
*iep = NULL;
else
ieee80211_saveie(iep, ie);
}
/*
* Process a beacon or probe response frame.
*/
void
ieee80211_add_scan(struct ieee80211com *ic,
const struct ieee80211_scanparams *sp,
const struct ieee80211_frame *wh,
int subtype, int rssi, int rstamp)
{
#define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
struct ieee80211_node_table *nt = &ic->ic_scan;
struct ieee80211_node *ni;
int newnode = 0;
ni = ieee80211_find_node(nt, wh->i_addr2);
if (ni == NULL) {
/*
* Create a new entry.
*/
ni = ic->ic_node_alloc(nt);
if (ni == NULL) {
ic->ic_stats.is_rx_nodealloc++;
return;
}
ieee80211_setup_node(nt, ni, wh->i_addr2);
/*
* XXX inherit from ic_bss.
*/
ni->ni_authmode = ic->ic_bss->ni_authmode;
ni->ni_txpower = ic->ic_bss->ni_txpower;
ni->ni_vlan = ic->ic_bss->ni_vlan; /* XXX?? */
ieee80211_set_chan(ic, ni, ic->ic_curchan);
ni->ni_rsn = ic->ic_bss->ni_rsn;
newnode = 1;
}
#ifdef IEEE80211_DEBUG
if (ieee80211_msg_scan(ic) && (ic->ic_flags & IEEE80211_F_SCAN))
dump_probe_beacon(subtype, newnode, wh->i_addr2, sp);
#endif
/* XXX ap beaconing multiple ssid w/ same bssid */
if (sp->ssid[1] != 0 &&
(ISPROBE(subtype) || ni->ni_esslen == 0)) {
ni->ni_esslen = sp->ssid[1];
memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]);
}
ni->ni_scangen = ic->ic_scan.nt_scangen;
IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp));
ni->ni_intval = sp->bintval;
ni->ni_capinfo = sp->capinfo;
ni->ni_chan = &ic->ic_channels[sp->chan];
ni->ni_fhdwell = sp->fhdwell;
ni->ni_fhindex = sp->fhindex;
ni->ni_erp = sp->erp;
if (sp->tim != NULL) {
struct ieee80211_tim_ie *ie =
(struct ieee80211_tim_ie *) sp->tim;
ni->ni_dtim_count = ie->tim_count;
ni->ni_dtim_period = ie->tim_period;
}
/*
* Record the byte offset from the mac header to
* the start of the TIM information element for
* use by hardware and/or to speedup software
* processing of beacon frames.
*/
ni->ni_timoff = sp->timoff;
/*
* Record optional information elements that might be
* used by applications or drivers.
*/
saveie(&ni->ni_wme_ie, sp->wme);
saveie(&ni->ni_wpa_ie, sp->wpa);
/* NB: must be after ni_chan is setup */
ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT);
if (!newnode)
ieee80211_free_node(ni);
#undef ISPROBE
}
/*
* Do node discovery in adhoc mode on receipt of a beacon
* or probe response frame. Note that for the driver's
* benefit we we treat this like an association so the
* driver has an opportunity to setup it's private state.
*/
struct ieee80211_node *
ieee80211_add_neighbor(struct ieee80211com *ic,
const struct ieee80211_frame *wh,
const struct ieee80211_scanparams *sp)
{
struct ieee80211_node *ni;
ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);/* XXX alloc_node? */
if (ni != NULL) {
ni->ni_esslen = sp->ssid[1];
memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]);
IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp));
ni->ni_intval = sp->bintval;
ni->ni_capinfo = sp->capinfo;
ni->ni_chan = ic->ic_bss->ni_chan;
ni->ni_fhdwell = sp->fhdwell;
ni->ni_fhindex = sp->fhindex;
ni->ni_erp = sp->erp;
ni->ni_timoff = sp->timoff;
if (sp->wme != NULL)
ieee80211_saveie(&ni->ni_wme_ie, sp->wme);
if (sp->wpa != NULL)
ieee80211_saveie(&ni->ni_wpa_ie, sp->wpa);
/* NB: must be after ni_chan is setup */
ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT);
if (ic->ic_newassoc != NULL)
ic->ic_newassoc(ni, 1);
/* XXX not right for 802.1x/WPA */
ieee80211_node_authorize(ni);
}
return ni;
}
#define IS_CTL(wh) \
((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
#define IS_PSPOLL(wh) \
((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
/*
* Locate the node for sender, track state, and then pass the
* (referenced) node up to the 802.11 layer for its use. We
@ -1071,10 +1281,6 @@ ieee80211_find_rxnode(struct ieee80211com *ic,
const struct ieee80211_frame_min *wh)
#endif
{
#define IS_CTL(wh) \
((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
#define IS_PSPOLL(wh) \
((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
struct ieee80211_node_table *nt;
struct ieee80211_node *ni;
@ -1092,12 +1298,77 @@ ieee80211_find_rxnode(struct ieee80211com *ic,
ni = _ieee80211_find_node(nt, wh->i_addr1);
else
ni = _ieee80211_find_node(nt, wh->i_addr2);
if (ni == NULL)
ni = ieee80211_ref_node(ic->ic_bss);
IEEE80211_NODE_UNLOCK(nt);
return (ni != NULL ? ni : ieee80211_ref_node(ic->ic_bss));
return ni;
}
/*
* Like ieee80211_find_rxnode but use the supplied h/w
* key index as a hint to locate the node in the key
* mapping table. If an entry is present at the key
* index we return it; otherwise do a normal lookup and
* update the mapping table if the station has a unicast
* key assigned to it.
*/
struct ieee80211_node *
#ifdef IEEE80211_DEBUG_REFCNT
ieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic,
const struct ieee80211_frame_min *wh, ieee80211_keyix keyix,
const char *func, int line)
#else
ieee80211_find_rxnode_withkey(struct ieee80211com *ic,
const struct ieee80211_frame_min *wh, ieee80211_keyix keyix)
#endif
{
struct ieee80211_node_table *nt;
struct ieee80211_node *ni;
if (ic->ic_opmode == IEEE80211_M_STA ||
ic->ic_opmode == IEEE80211_M_MONITOR ||
(ic->ic_flags & IEEE80211_F_SCAN))
nt = &ic->ic_scan;
else
nt = &ic->ic_sta;
IEEE80211_NODE_LOCK(nt);
if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax)
ni = nt->nt_keyixmap[keyix];
else
ni = NULL;
if (ni == NULL) {
if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/)
ni = _ieee80211_find_node(nt, wh->i_addr1);
else
ni = _ieee80211_find_node(nt, wh->i_addr2);
if (ni == NULL)
ni = ieee80211_ref_node(ic->ic_bss);
if (nt->nt_keyixmap != NULL) {
/*
* If the station has a unicast key cache slot
* assigned update the key->node mapping table.
*/
keyix = ni->ni_ucastkey.wk_rxkeyix;
/* XXX can keyixmap[keyix] != NULL? */
if (keyix < nt->nt_keyixmax &&
nt->nt_keyixmap[keyix] == NULL) {
IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
"%s: add key map entry %p<%s> refcnt %d\n",
__func__, ni, ether_sprintf(ni->ni_macaddr),
ieee80211_node_refcnt(ni)+1);
nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni);
}
}
} else {
ieee80211_ref_node(ni);
}
IEEE80211_NODE_UNLOCK(nt);
return ni;
}
#undef IS_PSPOLL
#undef IS_CTL
}
/*
* Return a reference to the appropriate node for sending
@ -1116,15 +1387,16 @@ ieee80211_find_txnode(struct ieee80211com *ic, const u_int8_t *macaddr)
/*
* The destination address should be in the node table
* unless we are operating in station mode or this is a
* multicast/broadcast frame.
* unless this is a multicast/broadcast frame. We can
* also optimize station mode operation, all frames go
* to the bss node.
*/
if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr))
return ieee80211_ref_node(ic->ic_bss);
/* XXX can't hold lock across dup_bss 'cuz of recursive locking */
IEEE80211_NODE_LOCK(nt);
ni = _ieee80211_find_node(nt, macaddr);
if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr))
ni = ieee80211_ref_node(ic->ic_bss);
else
ni = _ieee80211_find_node(nt, macaddr);
IEEE80211_NODE_UNLOCK(nt);
if (ni == NULL) {
@ -1274,22 +1546,86 @@ ieee80211_free_node(struct ieee80211_node *ni)
"%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni,
ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)-1);
#endif
if (ieee80211_node_dectestref(ni)) {
/*
* Beware; if the node is marked gone then it's already
* been removed from the table and we cannot assume the
* table still exists. Regardless, there's no need to lock
* the table.
*/
if (ni->ni_table != NULL) {
IEEE80211_NODE_LOCK(nt);
if (nt != NULL) {
IEEE80211_NODE_LOCK(nt);
if (ieee80211_node_dectestref(ni)) {
/*
* Last reference, reclaim state.
*/
_ieee80211_free_node(ni);
IEEE80211_NODE_UNLOCK(nt);
} else
} else if (ieee80211_node_refcnt(ni) == 1 &&
nt->nt_keyixmap != NULL) {
ieee80211_keyix keyix;
/*
* Check for a last reference in the key mapping table.
*/
keyix = ni->ni_ucastkey.wk_rxkeyix;
if (keyix < nt->nt_keyixmax &&
nt->nt_keyixmap[keyix] == ni) {
IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
"%s: %p<%s> clear key map entry", __func__,
ni, ether_sprintf(ni->ni_macaddr));
nt->nt_keyixmap[keyix] = NULL;
ieee80211_node_decref(ni); /* XXX needed? */
_ieee80211_free_node(ni);
}
}
IEEE80211_NODE_UNLOCK(nt);
} else {
if (ieee80211_node_dectestref(ni))
_ieee80211_free_node(ni);
}
}
/*
* Reclaim a unicast key and clear any key cache state.
*/
int
ieee80211_node_delucastkey(struct ieee80211_node *ni)
{
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_node_table *nt = &ic->ic_sta;
struct ieee80211_node *nikey;
ieee80211_keyix keyix;
int isowned, status;
/*
* NB: We must beware of LOR here; deleting the key
* can cause the crypto layer to block traffic updates
* which can generate a LOR against the node table lock;
* grab it here and stash the key index for our use below.
*
* Must also beware of recursion on the node table lock.
* When called from node_cleanup we may already have
* the node table lock held. Unfortunately there's no
* way to separate out this path so we must do this
* conditionally.
*/
isowned = IEEE80211_NODE_IS_LOCKED(nt);
if (!isowned)
IEEE80211_NODE_LOCK(nt);
keyix = ni->ni_ucastkey.wk_rxkeyix;
status = ieee80211_crypto_delkey(ic, &ni->ni_ucastkey);
if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) {
nikey = nt->nt_keyixmap[keyix];
nt->nt_keyixmap[keyix] = NULL;;
} else
nikey = NULL;
if (!isowned)
IEEE80211_NODE_UNLOCK(&ic->ic_sta);
if (nikey != NULL) {
KASSERT(nikey == ni,
("key map out of sync, ni %p nikey %p", ni, nikey));
IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
"%s: delete key map entry %p<%s> refcnt %d\n",
__func__, ni, ether_sprintf(ni->ni_macaddr),
ieee80211_node_refcnt(ni)-1);
ieee80211_free_node(ni);
}
return status;
}
/*
* Reclaim a node. If this is the last reference count then
* do the normal free work. Otherwise remove it from the node
@ -1298,11 +1634,30 @@ ieee80211_free_node(struct ieee80211_node *ni)
static void
node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
{
ieee80211_keyix keyix;
IEEE80211_NODE_LOCK_ASSERT(nt);
IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
"%s: remove %p<%s> from %s table, refcnt %d\n",
__func__, ni, ether_sprintf(ni->ni_macaddr),
nt->nt_name, ieee80211_node_refcnt(ni)-1);
/*
* Clear any entry in the unicast key mapping table.
* We need to do it here so rx lookups don't find it
* in the mapping table even if it's not in the hash
* table. We cannot depend on the mapping table entry
* being cleared because the node may not be free'd.
*/
keyix = ni->ni_ucastkey.wk_rxkeyix;
if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax &&
nt->nt_keyixmap[keyix] == ni) {
IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
"%s: %p<%s> clear key map entry\n",
__func__, ni, ether_sprintf(ni->ni_macaddr));
nt->nt_keyixmap[keyix] = NULL;
ieee80211_node_decref(ni); /* NB: don't need free */
}
if (!ieee80211_node_dectestref(ni)) {
/*
* Other references are present, just remove the
@ -1392,7 +1747,10 @@ ieee80211_timeout_stations(struct ieee80211_node_table *nt)
struct ieee80211com *ic = nt->nt_ic;
struct ieee80211_node *ni;
u_int gen;
int isadhoc;
isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS ||
ic->ic_opmode == IEEE80211_M_AHDEMO);
IEEE80211_SCAN_LOCK(nt);
gen = nt->nt_scangen++;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
@ -1409,7 +1767,8 @@ restart:
* will be reclaimed when the last reference to them
* goes away (when frame xmits complete).
*/
if ((ni->ni_flags & IEEE80211_NODE_AREF) == 0)
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
(ni->ni_flags & IEEE80211_NODE_AREF) == 0)
continue;
/*
* Free fragment if not needed anymore
@ -1428,7 +1787,7 @@ restart:
if (ni == ic->ic_bss)
continue;
ni->ni_inact--;
if (ni->ni_associd != 0) {
if (ni->ni_associd != 0 || isadhoc) {
/*
* Age frames on the power save queue. The
* aging interval is 4 times the listen
@ -1463,7 +1822,7 @@ IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, "[%s] discard frame, age %u\n", ether
IEEE80211_NODE_STAT_ADD(ni,
ps_discard, discard);
if (IEEE80211_NODE_SAVEQ_QLEN(ni) == 0)
ic->ic_set_tim(ic, ni, 0);
ic->ic_set_tim(ni, 0);
}
}
/*
@ -1474,20 +1833,29 @@ IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, "[%s] discard frame, age %u\n", ether
*/
if (0 < ni->ni_inact &&
ni->ni_inact <= ic->ic_inact_probe) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
"[%s] probe station due to inactivity\n",
ether_sprintf(ni->ni_macaddr));
IEEE80211_NOTE(ic,
IEEE80211_MSG_INACT | IEEE80211_MSG_NODE,
ni, "%s",
"probe station due to inactivity");
/*
* Grab a reference before unlocking the table
* so the node cannot be reclaimed before we
* send the frame. ieee80211_send_nulldata
* understands we've done this and reclaims the
* ref for us as needed.
*/
ieee80211_ref_node(ni);
IEEE80211_NODE_UNLOCK(nt);
ieee80211_send_nulldata(ic, ni);
ieee80211_send_nulldata(ni);
/* XXX stat? */
goto restart;
}
}
if (ni->ni_inact <= 0) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
"[%s] station timed out due to inactivity "
"(refcnt %u)\n", ether_sprintf(ni->ni_macaddr),
ieee80211_node_refcnt(ni));
IEEE80211_NOTE(ic,
IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni,
"station timed out due to inactivity "
"(refcnt %u)", ieee80211_node_refcnt(ni));
/*
* Send a deauthenticate frame and drop the station.
* This is somewhat complicated due to reference counts
@ -1659,8 +2027,7 @@ ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp
IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap);
ic->ic_sta_assoc++;
newassoc = 1;
if (ic->ic_curmode == IEEE80211_MODE_11G ||
ic->ic_curmode == IEEE80211_MODE_TURBO_G)
if (ic->ic_curmode == IEEE80211_MODE_11G)
ieee80211_node_join_11g(ic, ni);
} else
newassoc = 0;
@ -1677,7 +2044,7 @@ ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp
/* give driver a chance to setup state like ni_txrate */
if (ic->ic_newassoc != NULL)
ic->ic_newassoc(ic, ni, newassoc);
ic->ic_newassoc(ni, newassoc);
ni->ni_inact_reload = ic->ic_inact_auth;
ni->ni_inact = ni->ni_inact_reload;
IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
@ -1694,9 +2061,9 @@ static void
ieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni)
{
KASSERT(ic->ic_curmode == IEEE80211_MODE_11G ||
ic->ic_curmode == IEEE80211_MODE_TURBO_G,
("not in 11g, curmode %x", ic->ic_curmode));
KASSERT(ic->ic_curmode == IEEE80211_MODE_11G,
("not in 11g, bss %u:0x%x, curmode %u", ni->ni_chan->ic_freq,
ni->ni_chan->ic_flags, ic->ic_curmode));
/*
* If a long slot station do the slot time bookkeeping.
@ -1784,8 +2151,7 @@ ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
ni->ni_associd = 0;
ic->ic_sta_assoc--;
if (ic->ic_curmode == IEEE80211_MODE_11G ||
ic->ic_curmode == IEEE80211_MODE_TURBO_G)
if (ic->ic_curmode == IEEE80211_MODE_11G)
ieee80211_node_leave_11g(ic, ni);
/*
* Cleanup station state. In particular clear various
@ -1859,8 +2225,9 @@ ieee80211_getrssi(struct ieee80211com *ic)
* Indicate whether there are frames queued for a station in power-save mode.
*/
static void
ieee80211_set_tim(struct ieee80211com *ic, struct ieee80211_node *ni, int set)
ieee80211_set_tim(struct ieee80211_node *ni, int set)
{
struct ieee80211com *ic = ni->ni_ic;
u_int16_t aid;
KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP ||
@ -1892,7 +2259,7 @@ ieee80211_set_tim(struct ieee80211com *ic, struct ieee80211_node *ni, int set)
static void
ieee80211_node_table_init(struct ieee80211com *ic,
struct ieee80211_node_table *nt,
const char *name, int inact,
const char *name, int inact, int keyixmax,
void (*timeout)(struct ieee80211_node_table *))
{
@ -1908,6 +2275,17 @@ ieee80211_node_table_init(struct ieee80211com *ic,
nt->nt_scangen = 1;
nt->nt_inact_init = inact;
nt->nt_timeout = timeout;
nt->nt_keyixmax = keyixmax;
if (nt->nt_keyixmax > 0) {
MALLOC(nt->nt_keyixmap, struct ieee80211_node **,
keyixmax * sizeof(struct ieee80211_node *),
M_80211_NODE, M_NOWAIT | M_ZERO);
if (nt->nt_keyixmap == NULL)
if_printf(ic->ic_ifp,
"Cannot allocate key index map with %u entries\n",
keyixmax);
} else
nt->nt_keyixmap = NULL;
}
void
@ -1930,7 +2308,18 @@ ieee80211_node_table_cleanup(struct ieee80211_node_table *nt)
IEEE80211_DPRINTF(nt->nt_ic, IEEE80211_MSG_NODE,
"%s %s table\n", __func__, nt->nt_name);
IEEE80211_NODE_LOCK(nt);
ieee80211_free_allnodes_locked(nt);
if (nt->nt_keyixmap != NULL) {
/* XXX verify all entries are NULL */
int i;
for (i = 0; i < nt->nt_keyixmax; i++)
if (nt->nt_keyixmap[i] != NULL)
printf("%s: %s[%u] still active\n", __func__,
nt->nt_name, i);
FREE(nt->nt_keyixmap, M_80211_NODE);
nt->nt_keyixmap = NULL;
}
IEEE80211_SCAN_LOCK_DESTROY(nt);
IEEE80211_NODE_LOCK_DESTROY(nt);
}

View File

@ -29,7 +29,7 @@
* (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: src/sys/net80211/ieee80211_node.h,v 1.17 2005/07/06 01:51:44 sam Exp $
* $FreeBSD: src/sys/net80211/ieee80211_node.h,v 1.22 2005/08/10 16:22:29 sam Exp $
*/
#ifndef _NET80211_IEEE80211_NODE_H_
#define _NET80211_IEEE80211_NODE_H_
@ -132,7 +132,7 @@ struct ieee80211_node {
u_int8_t ni_esslen;
u_int8_t ni_essid[IEEE80211_NWID_LEN];
struct ieee80211_rateset ni_rates; /* negotiated rate set */
struct ieee80211_channel *ni_chan;
struct ieee80211_channel *ni_chan; /* XXX multiple uses */
u_int16_t ni_fhdwell; /* FH only */
u_int8_t ni_fhindex; /* FH only */
u_int8_t ni_erp; /* ERP from beacon/probe resp */
@ -182,10 +182,8 @@ ieee80211_node_is_authorized(const struct ieee80211_node *ni)
return (ni->ni_flags & IEEE80211_NODE_AUTH);
}
void ieee80211_node_authorize(struct ieee80211com *,
struct ieee80211_node *);
void ieee80211_node_unauthorize(struct ieee80211com *,
struct ieee80211_node *);
void ieee80211_node_authorize(struct ieee80211_node *);
void ieee80211_node_unauthorize(struct ieee80211_node *);
void ieee80211_begin_scan(struct ieee80211com *, int);
int ieee80211_next_scan(struct ieee80211com *);
@ -193,7 +191,7 @@ void ieee80211_create_ibss(struct ieee80211com*, struct ieee80211_channel *);
void ieee80211_reset_bss(struct ieee80211com *);
void ieee80211_cancel_scan(struct ieee80211com *);
void ieee80211_end_scan(struct ieee80211com *);
int ieee80211_ibss_merge(struct ieee80211com *, struct ieee80211_node *);
int ieee80211_ibss_merge(struct ieee80211_node *);
int ieee80211_sta_join(struct ieee80211com *, struct ieee80211_node *);
void ieee80211_sta_leave(struct ieee80211com *, struct ieee80211_node *);
@ -213,6 +211,8 @@ struct ieee80211_node_table {
u_int nt_scangen; /* gen# for timeout scan */
int nt_inact_timer; /* inactivity timer */
int nt_inact_init; /* initial node inact setting */
struct ieee80211_node **nt_keyixmap; /* key ix -> node map */
int nt_keyixmax; /* keyixmap size */
void (*nt_timeout)(struct ieee80211_node_table *);
};
@ -220,6 +220,8 @@ void ieee80211_node_table_reset(struct ieee80211_node_table *);
struct ieee80211_node *ieee80211_alloc_node(
struct ieee80211_node_table *, const u_int8_t *);
struct ieee80211_node *ieee80211_tmp_node(struct ieee80211com *,
const u_int8_t *macaddr);
struct ieee80211_node *ieee80211_dup_bss(struct ieee80211_node_table *,
const u_int8_t *);
#ifdef IEEE80211_DEBUG_REFCNT
@ -231,6 +233,10 @@ struct ieee80211_node *ieee80211_find_node_debug(
struct ieee80211_node * ieee80211_find_rxnode_debug(
struct ieee80211com *, const struct ieee80211_frame_min *,
const char *func, int line);
struct ieee80211_node * ieee80211_find_rxnode_withkey_debug(
struct ieee80211com *,
const struct ieee80211_frame_min *, u_int16_t keyix,
const char *func, int line);
struct ieee80211_node *ieee80211_find_txnode_debug(
struct ieee80211com *, const u_int8_t *,
const char *func, int line);
@ -247,6 +253,8 @@ struct ieee80211_node *ieee80211_find_node_with_ssid_debug(
ieee80211_find_node_debug(nt, mac, __func__, __LINE__)
#define ieee80211_find_rxnode(nt, wh) \
ieee80211_find_rxnode_debug(nt, wh, __func__, __LINE__)
#define ieee80211_find_rxnode_withkey(nt, wh, keyix) \
ieee80211_find_rxnode_withkey_debug(nt, wh, keyix, __func__, __LINE__)
#define ieee80211_find_txnode(nt, mac) \
ieee80211_find_txnode_debug(nt, mac, __func__, __LINE__)
#define ieee80211_find_node_with_channel(nt, mac, c) \
@ -259,6 +267,8 @@ struct ieee80211_node *ieee80211_find_node(
struct ieee80211_node_table *, const u_int8_t *);
struct ieee80211_node * ieee80211_find_rxnode(
struct ieee80211com *, const struct ieee80211_frame_min *);
struct ieee80211_node * ieee80211_find_rxnode_withkey(struct ieee80211com *,
const struct ieee80211_frame_min *, u_int16_t keyix);
struct ieee80211_node *ieee80211_find_txnode(
struct ieee80211com *, const u_int8_t *);
struct ieee80211_node *ieee80211_find_node_with_channel(
@ -268,6 +278,7 @@ struct ieee80211_node *ieee80211_find_node_with_ssid(
struct ieee80211_node_table *, const u_int8_t *macaddr,
u_int ssidlen, const u_int8_t *ssid);
#endif
int ieee80211_node_delucastkey(struct ieee80211_node *);
typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
void ieee80211_iterate_nodes(struct ieee80211_node_table *,
@ -282,4 +293,38 @@ struct ieee80211_node *ieee80211_fakeup_adhoc_node(
void ieee80211_node_join(struct ieee80211com *, struct ieee80211_node *,int);
void ieee80211_node_leave(struct ieee80211com *, struct ieee80211_node *);
u_int8_t ieee80211_getrssi(struct ieee80211com *ic);
/*
* Parameters supplied when adding/updating an entry in a
* scan cache. Pointer variables should be set to NULL
* if no data is available. Pointer references can be to
* local data; any information that is saved will be copied.
* All multi-byte values must be in host byte order.
*/
struct ieee80211_scanparams {
u_int16_t capinfo; /* 802.11 capabilities */
u_int16_t fhdwell; /* FHSS dwell interval */
u_int8_t chan; /* */
u_int8_t bchan;
u_int8_t fhindex;
u_int8_t erp;
u_int16_t bintval;
u_int8_t timoff;
u_int8_t *tim;
u_int8_t *tstamp;
u_int8_t *country;
u_int8_t *ssid;
u_int8_t *rates;
u_int8_t *xrates;
u_int8_t *wpa;
u_int8_t *wme;
};
void ieee80211_add_scan(struct ieee80211com *,
const struct ieee80211_scanparams *,
const struct ieee80211_frame *,
int subtype, int rssi, int rstamp);
struct ieee80211_node *ieee80211_add_neighbor(struct ieee80211com *,
const struct ieee80211_frame *,
const struct ieee80211_scanparams *);
#endif /* _NET80211_IEEE80211_NODE_H_ */

View File

@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.26 2005/07/06 01:55:17 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.34 2005/08/10 16:22:29 sam Exp $");
#include "opt_inet.h"
@ -77,6 +77,62 @@ doprint(struct ieee80211com *ic, int subtype)
}
#endif
/*
* Set the direction field and address fields of an outgoing
* non-QoS frame. Note this should be called early on in
* constructing a frame as it sets i_fc[1]; other bits can
* then be or'd in.
*/
static void
ieee80211_send_setup(struct ieee80211com *ic,
struct ieee80211_node *ni,
struct ieee80211_frame *wh,
int type,
const u_int8_t sa[IEEE80211_ADDR_LEN],
const u_int8_t da[IEEE80211_ADDR_LEN],
const u_int8_t bssid[IEEE80211_ADDR_LEN])
{
#define WH4(wh) ((struct ieee80211_frame_addr4 *)wh)
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
IEEE80211_ADDR_COPY(wh->i_addr1, bssid);
IEEE80211_ADDR_COPY(wh->i_addr2, sa);
IEEE80211_ADDR_COPY(wh->i_addr3, da);
break;
case IEEE80211_M_IBSS:
case IEEE80211_M_AHDEMO:
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
IEEE80211_ADDR_COPY(wh->i_addr1, da);
IEEE80211_ADDR_COPY(wh->i_addr2, sa);
IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
break;
case IEEE80211_M_HOSTAP:
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
IEEE80211_ADDR_COPY(wh->i_addr1, da);
IEEE80211_ADDR_COPY(wh->i_addr2, bssid);
IEEE80211_ADDR_COPY(wh->i_addr3, sa);
break;
case IEEE80211_M_MONITOR: /* NB: to quiet compiler */
break;
}
} else {
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
IEEE80211_ADDR_COPY(wh->i_addr1, da);
IEEE80211_ADDR_COPY(wh->i_addr2, sa);
IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
}
*(u_int16_t *)&wh->i_dur[0] = 0;
/* NB: use non-QoS tid */
*(u_int16_t *)&wh->i_seq[0] =
htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
ni->ni_txseqs[0]++;
#undef WH4
}
/*
* Send a management frame to the specified node. The node pointer
* must have a reference as the pointer will be passed to the driver
@ -112,30 +168,9 @@ ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni,
m->m_pkthdr.rcvif = (void *)ni;
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type;
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
*(u_int16_t *)wh->i_dur = 0;
*(u_int16_t *)wh->i_seq =
htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
ni->ni_txseqs[0]++;
/*
* Hack. When sending PROBE_REQ frames while scanning we
* explicitly force a broadcast rather than (as before) clobber
* ni_macaddr and ni_bssid. This is stopgap, we need a way
* to communicate this directly rather than do something
* implicit based on surrounding state.
*/
if (type == IEEE80211_FC0_SUBTYPE_PROBE_REQ &&
(ic->ic_flags & IEEE80211_F_SCAN)) {
IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr);
} else {
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
}
ieee80211_send_setup(ic, ni, wh,
IEEE80211_FC0_TYPE_MGT | type,
ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid);
if ((m->m_flags & M_LINK0) != 0 && ni->ni_challenge != NULL) {
m->m_flags &= ~M_LINK0;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
@ -152,7 +187,7 @@ ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni,
ieee80211_mgt_subtype_name[
(type & IEEE80211_FC0_SUBTYPE_MASK) >>
IEEE80211_FC0_SUBTYPE_SHIFT],
ieee80211_chan2ieee(ic, ni->ni_chan));
ieee80211_chan2ieee(ic, ic->ic_curchan));
}
#endif
IEEE80211_NODE_STAT(ni, tx_mgmt);
@ -164,10 +199,15 @@ ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni,
/*
* Send a null data frame to the specified node.
*
* NB: the caller is assumed to have setup a node reference
* for use; this is necessary to deal with a race condition
* when probing for inactive stations.
*/
int
ieee80211_send_nulldata(struct ieee80211com *ic, struct ieee80211_node *ni)
ieee80211_send_nulldata(struct ieee80211_node *ni)
{
struct ieee80211com *ic = ni->ni_ic;
struct ifnet *ifp = ic->ic_ifp;
struct mbuf *m;
struct ieee80211_frame *wh;
@ -176,27 +216,29 @@ ieee80211_send_nulldata(struct ieee80211com *ic, struct ieee80211_node *ni)
if (m == NULL) {
/* XXX debug msg */
ic->ic_stats.is_tx_nobuf++;
ieee80211_unref_node(&ni);
return ENOMEM;
}
m->m_pkthdr.rcvif = (void *) ieee80211_ref_node(ni);
m->m_pkthdr.rcvif = (void *) ni;
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA |
IEEE80211_FC0_SUBTYPE_NODATA;
*(u_int16_t *)wh->i_dur = 0;
*(u_int16_t *)wh->i_seq =
htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
ni->ni_txseqs[0]++;
/* XXX WDS */
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_myaddr);
ieee80211_send_setup(ic, ni, wh,
IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid);
/* NB: power management bit is never sent by an AP */
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
ic->ic_opmode != IEEE80211_M_HOSTAP)
wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
m->m_len = m->m_pkthdr.len = sizeof(struct ieee80211_frame);
IEEE80211_NODE_STAT(ni, tx_data);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
"[%s] send null data frame on channel %u, pwr mgt %s\n",
ether_sprintf(ni->ni_macaddr),
ieee80211_chan2ieee(ic, ic->ic_curchan),
wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis");
IF_ENQUEUE(&ic->ic_mgtq, m); /* cheat */
if_start(ifp);
@ -907,6 +949,91 @@ ieee80211_add_wme_param(u_int8_t *frm, struct ieee80211_wme_state *wme)
}
#undef WME_OUI_BYTES
/*
* Send a probe request frame with the specified ssid
* and any optional information element data.
*/
int
ieee80211_send_probereq(struct ieee80211_node *ni,
const u_int8_t sa[IEEE80211_ADDR_LEN],
const u_int8_t da[IEEE80211_ADDR_LEN],
const u_int8_t bssid[IEEE80211_ADDR_LEN],
const u_int8_t *ssid, size_t ssidlen,
const void *optie, size_t optielen)
{
struct ieee80211com *ic = ni->ni_ic;
enum ieee80211_phymode mode;
struct ieee80211_frame *wh;
struct mbuf *m;
u_int8_t *frm;
/*
* Hold a reference on the node so it doesn't go away until after
* the xmit is complete all the way in the driver. On error we
* will remove our reference.
*/
IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
__func__, __LINE__,
ni, ether_sprintf(ni->ni_macaddr),
ieee80211_node_refcnt(ni)+1);
ieee80211_ref_node(ni);
/*
* prreq frame format
* [tlv] ssid
* [tlv] supported rates
* [tlv] extended supported rates
* [tlv] user-specified ie's
*/
m = ieee80211_getmgtframe(&frm,
2 + IEEE80211_NWID_LEN
+ 2 + IEEE80211_RATE_SIZE
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ (optie != NULL ? optielen : 0)
);
if (m == NULL) {
ic->ic_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
return ENOMEM;
}
frm = ieee80211_add_ssid(frm, ssid, ssidlen);
mode = ieee80211_chan2mode(ic, ic->ic_curchan);
frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]);
frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]);
if (optie != NULL) {
memcpy(frm, optie, optielen);
frm += optielen;
}
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
if (m == NULL)
return ENOMEM;
KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
m->m_pkthdr.rcvif = (void *)ni;
wh = mtod(m, struct ieee80211_frame *);
ieee80211_send_setup(ic, ni, wh,
IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
sa, da, bssid);
/* XXX power management? */
IEEE80211_NODE_STAT(ni, tx_probereq);
IEEE80211_NODE_STAT(ni, tx_mgmt);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
"[%s] send probe req on channel %u\n",
ether_sprintf(wh->i_addr1),
ieee80211_chan2ieee(ic, ic->ic_curchan));
IF_ENQUEUE(&ic->ic_mgtq, m);
if_start(ic->ic_ifp);
return 0;
}
/*
* Send a management frame. The node is for the destination (or ic_bss
* when in station mode). Nodes other than ic_bss have their reference
@ -919,7 +1046,6 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
#define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0)
struct mbuf *m;
u_int8_t *frm;
enum ieee80211_phymode mode;
u_int16_t capinfo;
int has_challenge, is_shared_key, ret, timer, status;
@ -939,38 +1065,6 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
timer = 0;
switch (type) {
case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
/*
* prreq frame format
* [tlv] ssid
* [tlv] supported rates
* [tlv] extended supported rates
* [tlv] user-specified ie's
*/
m = ieee80211_getmgtframe(&frm,
2 + IEEE80211_NWID_LEN
+ 2 + IEEE80211_RATE_SIZE
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ (ic->ic_opt_ie != NULL ? ic->ic_opt_ie_len : 0)
);
if (m == NULL)
senderr(ENOMEM, is_tx_nobuf);
frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
mode = ieee80211_chan2mode(ic, ni->ni_chan);
frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]);
frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]);
if (ic->ic_opt_ie != NULL) {
memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len);
frm += ic->ic_opt_ie_len;
}
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
IEEE80211_NODE_STAT(ni, tx_probereq);
if (ic->ic_opmode == IEEE80211_M_STA)
timer = IEEE80211_TRANS_WAIT;
break;
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
/*
* probe response frame format
@ -1015,7 +1109,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
if (ic->ic_flags & IEEE80211_F_PRIVACY)
capinfo |= IEEE80211_CAPINFO_PRIVACY;
if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
if (ic->ic_flags & IEEE80211_F_SHSLOT)
capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
@ -1032,14 +1126,14 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
*frm++ = ni->ni_fhdwell & 0x00ff;
*frm++ = (ni->ni_fhdwell >> 8) & 0x00ff;
*frm++ = IEEE80211_FH_CHANSET(
ieee80211_chan2ieee(ic, ni->ni_chan));
ieee80211_chan2ieee(ic, ic->ic_curchan));
*frm++ = IEEE80211_FH_CHANPAT(
ieee80211_chan2ieee(ic, ni->ni_chan));
ieee80211_chan2ieee(ic, ic->ic_curchan));
*frm++ = ni->ni_fhindex;
} else {
*frm++ = IEEE80211_ELEMID_DSPARMS;
*frm++ = 1;
*frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
*frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan);
}
if (ic->ic_opmode == IEEE80211_M_IBSS) {
@ -1130,7 +1224,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
IEEE80211_NODE_STAT(ni, tx_deauth);
IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg);
ieee80211_node_unauthorize(ic, ni); /* port closed */
ieee80211_node_unauthorize(ni); /* port closed */
break;
case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
@ -1171,7 +1265,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
* short premable is set.
*/
if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) &&
(ic->ic_caps & IEEE80211_C_SHSLOT))
@ -1227,7 +1321,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
if (ic->ic_flags & IEEE80211_F_PRIVACY)
capinfo |= IEEE80211_CAPINFO_PRIVACY;
if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
if (ic->ic_flags & IEEE80211_F_SHSLOT)
capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
@ -1592,14 +1686,14 @@ ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni,
* using this information.
*/
/* XXX handle overflow? */
age = ((ni->ni_intval * ic->ic_lintval) << 2) / 1024; /* TU -> secs */
age = ((ni->ni_intval * ic->ic_bintval) << 2) / 1024; /* TU -> secs */
_IEEE80211_NODE_SAVEQ_ENQUEUE(ni, m, qlen, age);
IEEE80211_NODE_SAVEQ_UNLOCK(ni);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
"[%s] save frame, %u now queued\n",
ether_sprintf(ni->ni_macaddr), qlen);
"[%s] save frame with age %d, %u now queued\n",
ether_sprintf(ni->ni_macaddr), age, qlen);
if (qlen == 1)
ic->ic_set_tim(ic, ni, 1);
ic->ic_set_tim(ni, 1);
}

View File

@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_proto.c,v 1.17 2005/07/04 01:29:41 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_proto.c,v 1.23 2005/08/10 16:22:29 sam Exp $");
/*
* IEEE 802.11 protocol support.
@ -94,13 +94,9 @@ ieee80211_proto_attach(struct ieee80211com *ic)
/* XXX room for crypto */
ifp->if_hdrlen = sizeof(struct ieee80211_qosframe_addr4);
#ifdef notdef
ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT;
#else
ic->ic_rtsthreshold = IEEE80211_RTS_MAX;
#endif
ic->ic_fragthreshold = 2346; /* XXX not used yet */
ic->ic_fixed_rate = -1; /* no fixed rate */
ic->ic_fragthreshold = IEEE80211_FRAG_DEFAULT;
ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
ic->ic_protmode = IEEE80211_PROT_CTSONLY;
ic->ic_roaming = IEEE80211_ROAMING_AUTO;
@ -323,9 +319,10 @@ ieee80211_dump_pkt(const u_int8_t *buf, int len, int rate, int rssi)
}
int
ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags)
ieee80211_fix_rate(struct ieee80211_node *ni, int flags)
{
#define RV(v) ((v) & IEEE80211_RATE_VAL)
struct ieee80211com *ic = ni->ni_ic;
int i, j, ignore, error;
int okrate, badrate, fixedrate;
struct ieee80211_rateset *srs, *nrs;
@ -335,7 +332,8 @@ ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags
* If the fixed rate check was requested but no
* fixed has been defined then just remove it.
*/
if ((flags & IEEE80211_F_DOFRATE) && ic->ic_fixed_rate < 0)
if ((flags & IEEE80211_F_DOFRATE) &&
ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
flags &= ~IEEE80211_F_DOFRATE;
error = 0;
okrate = badrate = fixedrate = 0;
@ -924,9 +922,12 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
* beacons on the channel.
*/
if ((ic->ic_flags & IEEE80211_F_ASCAN) &&
(ni->ni_chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) {
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0);
(ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) {
ieee80211_send_probereq(ni,
ic->ic_myaddr, ifp->if_broadcastaddr,
ifp->if_broadcastaddr,
ic->ic_des_essid, ic->ic_des_esslen,
ic->ic_opt_ie, ic->ic_opt_ie_len);
}
break;
case IEEE80211_S_RUN:
@ -1042,7 +1043,7 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
ieee80211_print_essid(ic->ic_bss->ni_essid,
ni->ni_esslen);
printf(" channel %d start %uMb\n",
ieee80211_chan2ieee(ic, ni->ni_chan),
ieee80211_chan2ieee(ic, ic->ic_curchan),
IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate]));
}
#endif
@ -1070,7 +1071,7 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
* at this point so traffic can flow.
*/
if (ni->ni_authmode != IEEE80211_AUTH_8021X)
ieee80211_node_authorize(ic, ni);
ieee80211_node_authorize(ni);
/*
* Enable inactivity processing.
* XXX

View File

@ -29,7 +29,7 @@
* (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: src/sys/net80211/ieee80211_proto.h,v 1.11 2005/04/04 04:27:20 sam Exp $
* $FreeBSD: src/sys/net80211/ieee80211_proto.h,v 1.16 2005/08/13 17:31:48 sam Exp $
*/
#ifndef _NET80211_IEEE80211_PROTO_H_
#define _NET80211_IEEE80211_PROTO_H_
@ -59,9 +59,18 @@ void ieee80211_proto_detach(struct ieee80211com *);
struct ieee80211_node;
int ieee80211_input(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, int, u_int32_t);
int ieee80211_setup_rates(struct ieee80211_node *ni,
const u_int8_t *rates, const u_int8_t *xrates, int flags);
void ieee80211_saveie(u_int8_t **, const u_int8_t *);
void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, int, int, u_int32_t);
int ieee80211_send_nulldata(struct ieee80211com *, struct ieee80211_node *);
int ieee80211_send_nulldata(struct ieee80211_node *);
int ieee80211_send_probereq(struct ieee80211_node *ni,
const u_int8_t sa[IEEE80211_ADDR_LEN],
const u_int8_t da[IEEE80211_ADDR_LEN],
const u_int8_t bssid[IEEE80211_ADDR_LEN],
const u_int8_t *ssid, size_t ssidlen,
const void *optie, size_t optielen);
int ieee80211_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
int, int);
int ieee80211_classify(struct ieee80211com *, struct mbuf *,
@ -135,6 +144,7 @@ void ieee80211_authenticator_register(int type,
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
@ -153,6 +163,8 @@ struct ieee80211_aclator {
int (*iac_flush)(struct ieee80211com *);
int (*iac_setpolicy)(struct ieee80211com *, int);
int (*iac_getpolicy)(struct ieee80211com *);
int (*iac_setioctl)(struct ieee80211com *, struct ieee80211req *);
int (*iac_getioctl)(struct ieee80211com *, struct ieee80211req *);
};
void ieee80211_aclator_register(const struct ieee80211_aclator *);
void ieee80211_aclator_unregister(const struct ieee80211_aclator *);
@ -163,7 +175,7 @@ const struct ieee80211_aclator *ieee80211_aclator_get(const char *name);
#define IEEE80211_F_DOFRATE 0x00000002 /* use fixed rate */
#define IEEE80211_F_DONEGO 0x00000004 /* calc negotiated rate */
#define IEEE80211_F_DODEL 0x00000008 /* delete ignore rate */
int ieee80211_fix_rate(struct ieee80211com *, struct ieee80211_node *, int);
int ieee80211_fix_rate(struct ieee80211_node *, int);
/*
* WME/WMM support.

View File

@ -29,7 +29,7 @@
* (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: src/sys/net80211/ieee80211_var.h,v 1.22 2005/07/06 15:38:27 sam Exp $
* $FreeBSD: src/sys/net80211/ieee80211_var.h,v 1.30 2005/08/10 16:22:29 sam Exp $
*/
#ifndef _NET80211_IEEE80211_VAR_H_
#define _NET80211_IEEE80211_VAR_H_
@ -65,13 +65,19 @@
#define IEEE80211_DTIM_MIN 1 /* min DTIM period */
#define IEEE80211_DTIM_DEFAULT 1 /* default DTIM period */
#define IEEE80211_BINTVAL_MAX 500 /* max beacon interval (TU's) */
/* NB: min+max come from WiFi requirements */
#define IEEE80211_BINTVAL_MAX 1000 /* max beacon interval (TU's) */
#define IEEE80211_BINTVAL_MIN 25 /* min beacon interval (TU's) */
#define IEEE80211_BINTVAL_DEFAULT 100 /* default beacon interval (TU's) */
#define IEEE80211_PS_SLEEP 0x1 /* STA is in power saving mode */
#define IEEE80211_PS_MAX_QUEUE 50 /* maximum saved packets */
#define IEEE80211_FIXED_RATE_NONE -1
#define IEEE80211_RTS_DEFAULT IEEE80211_RTS_MAX
#define IEEE80211_FRAG_DEFAULT IEEE80211_FRAG_MAX
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
#define IEEE80211_TU_TO_MS(x) (((x) * 1024) / 1000)
@ -95,11 +101,9 @@ struct ieee80211com {
struct ieee80211_node *, int, int);
int (*ic_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
void (*ic_newassoc)(struct ieee80211com *,
struct ieee80211_node *, int);
void (*ic_newassoc)(struct ieee80211_node *, int);
void (*ic_updateslot)(struct ifnet *);
void (*ic_set_tim)(struct ieee80211com *,
struct ieee80211_node *, int);
void (*ic_set_tim)(struct ieee80211_node *, int);
u_int8_t ic_myaddr[IEEE80211_ADDR_LEN];
struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1];
@ -109,6 +113,7 @@ struct ieee80211com {
struct ieee80211_node_table ic_scan; /* scan candidates */
struct ifqueue ic_mgtq;
u_int32_t ic_flags; /* state flags */
u_int32_t ic_flags_ext; /* extended state flags */
u_int32_t ic_caps; /* capabilities */
u_int16_t ic_modecaps; /* set of mode capabilities */
u_int16_t ic_curmode; /* current mode */
@ -131,6 +136,7 @@ struct ieee80211com {
struct bpf_if *ic_rawbpf; /* packet filter structure */
struct ieee80211_node *ic_bss; /* information for this node */
struct ieee80211_channel *ic_ibss_chan;
struct ieee80211_channel *ic_curchan; /* current channel */
int ic_fixed_rate; /* index to ic_sup_rates[] */
u_int16_t ic_rtsthreshold;
u_int16_t ic_fragthreshold;
@ -139,6 +145,7 @@ struct ieee80211com {
void (*ic_node_cleanup)(struct ieee80211_node *);
u_int8_t (*ic_node_getrssi)(const struct ieee80211_node*);
u_int16_t ic_lintval; /* listen interval */
u_int16_t ic_bintval; /* beacon interval */
u_int16_t ic_holdover; /* PM hold over duration */
u_int16_t ic_txmin; /* min tx retry count */
u_int16_t ic_txmax; /* max tx retry count */
@ -196,7 +203,9 @@ struct ieee80211com {
#define IEEE80211_ADDR_COPY(dst,src) memcpy(dst,src,IEEE80211_ADDR_LEN)
/* ic_flags */
/* NB: bits 0x4f available */
/* NB: bits 0x4c available */
#define IEEE80211_F_FF 0x00000001 /* CONF: ATH FF enabled */
#define IEEE80211_F_TURBOP 0x00000002 /* CONF: ATH Turbo enabled*/
/* NB: this is intentionally setup to be IEEE80211_CAPINFO_PRIVACY */
#define IEEE80211_F_PRIVACY 0x00000010 /* CONF: privacy enabled */
#define IEEE80211_F_PUREG 0x00000020 /* CONF: 11g w/o 11b sta's */
@ -208,7 +217,7 @@ struct ieee80211com {
#define IEEE80211_F_PMGTON 0x00000800 /* CONF: Power mgmt enable */
#define IEEE80211_F_DESBSSID 0x00001000 /* CONF: des_bssid is set */
#define IEEE80211_F_WME 0x00002000 /* CONF: enable WME use */
#define IEEE80211_F_ROAMING 0x00004000 /* CONF: roaming enabled (???)*/
#define IEEE80211_F_BGSCAN 0x00004000 /* CONF: bg scan enabled (???)*/
#define IEEE80211_F_SWRETRY 0x00008000 /* CONF: sw tx retry enabled */
#define IEEE80211_F_TXPOW_FIXED 0x00010000 /* TX Power: fixed rate */
#define IEEE80211_F_IBSSON 0x00020000 /* CONF: IBSS creation enable */
@ -226,12 +235,19 @@ struct ieee80211com {
#define IEEE80211_F_NOBRIDGE 0x10000000 /* CONF: dis. internal bridge */
#define IEEE80211_F_WMEUPDATE 0x20000000 /* STATUS: update beacon wme */
/* ic_flags_ext */
#define IEEE80211_FEXT_WDS 0x00000001 /* CONF: 4 addr allowed */
/* 0x00000006 reserved */
#define IEEE80211_FEXT_BGSCAN 0x00000008 /* STATUS: enable full bgscan completion */
/* ic_caps */
#define IEEE80211_C_WEP 0x00000001 /* CAPABILITY: WEP available */
#define IEEE80211_C_TKIP 0x00000002 /* CAPABILITY: TKIP available */
#define IEEE80211_C_AES 0x00000004 /* CAPABILITY: AES OCB avail */
#define IEEE80211_C_AES_CCM 0x00000008 /* CAPABILITY: AES CCM avail */
#define IEEE80211_C_CKIP 0x00000020 /* CAPABILITY: CKIP available */
#define IEEE80211_C_FF 0x00000040 /* CAPABILITY: ATH FF avail */
#define IEEE80211_C_TURBOP 0x00000080 /* CAPABILITY: ATH Turbo avail*/
#define IEEE80211_C_IBSS 0x00000100 /* CAPABILITY: IBSS available */
#define IEEE80211_C_PMGT 0x00000200 /* CAPABILITY: Power mgmt */
#define IEEE80211_C_HOSTAP 0x00000400 /* CAPABILITY: HOSTAP avail */
@ -247,6 +263,10 @@ struct ieee80211com {
#define IEEE80211_C_WPA 0x01800000 /* CAPABILITY: WPA1+WPA2 avail*/
#define IEEE80211_C_BURST 0x02000000 /* CAPABILITY: frame bursting */
#define IEEE80211_C_WME 0x04000000 /* CAPABILITY: WME avail */
#define IEEE80211_C_WDS 0x08000000 /* CAPABILITY: 4-addr support */
/* 0x10000000 reserved */
#define IEEE80211_C_BGSCAN 0x20000000 /* CAPABILITY: bg scanning */
#define IEEE80211_C_TXFRAG 0x40000000 /* CAPABILITY: tx fragments */
/* XXX protection/barker? */
#define IEEE80211_C_CRYPTO 0x0000002f /* CAPABILITY: crypto alg's */
@ -338,14 +358,36 @@ ieee80211_anyhdrspace(struct ieee80211com *ic, const void *data)
#define IEEE80211_MSG_WPA 0x00001000 /* WPA/RSN protocol */
#define IEEE80211_MSG_ACL 0x00000800 /* ACL handling */
#define IEEE80211_MSG_WME 0x00000400 /* WME protocol */
#define IEEE80211_MSG_SUPERG 0x00000200 /* Atheros SuperG protocol */
#define IEEE80211_MSG_DOTH 0x00000100 /* 802.11h support */
#define IEEE80211_MSG_INACT 0x00000080 /* inactivity handling */
#define IEEE80211_MSG_ROAM 0x00000040 /* sta-mode roaming */
#define IEEE80211_MSG_ANY 0xffffffff /* anything */
#ifdef IEEE80211_DEBUG
#define IEEE80211_DPRINTF(_ic, _m, _fmt, ...) do { \
if (_ic->ic_debug & (_m)) \
printf(_fmt, __VA_ARGS__); \
#define ieee80211_msg(_ic, _m) ((_ic)->ic_debug & (_m))
#define IEEE80211_DPRINTF(_ic, _m, _fmt, ...) do { \
if (ieee80211_msg(_ic, _m)) \
ieee80211_note(_ic, _fmt, __VA_ARGS__); \
} while (0)
#define IEEE80211_NOTE(_ic, _m, _ni, _fmt, ...) do { \
if (ieee80211_msg(_ic, _m)) \
ieee80211_note_mac(_ic, (_ni)->ni_macaddr, _fmt, __VA_ARGS__);\
} while (0)
#define IEEE80211_NOTE_MAC(_ic, _m, _mac, _fmt, ...) do { \
if (ieee80211_msg(_ic, _m)) \
ieee80211_note_mac(_ic, _mac, _fmt, __VA_ARGS__); \
} while (0)
#define IEEE80211_NOTE_FRAME(_ic, _m, _wh, _fmt, ...) do { \
if (ieee80211_msg(_ic, _m)) \
ieee80211_note_frame(_ic, _wh, _fmt, __VA_ARGS__); \
} while (0)
void ieee80211_note(struct ieee80211com *ic, const char *fmt, ...);
void ieee80211_note_mac(struct ieee80211com *ic,
const u_int8_t mac[IEEE80211_ADDR_LEN], const char *fmt, ...);
void ieee80211_note_frame(struct ieee80211com *ic,
const struct ieee80211_frame *wh, const char *fmt, ...);
#define ieee80211_msg_debug(_ic) \
((_ic)->ic_debug & IEEE80211_MSG_DEBUG)
#define ieee80211_msg_dumppkts(_ic) \
@ -360,8 +402,14 @@ ieee80211_anyhdrspace(struct ieee80211com *ic, const void *data)
((_ic)->ic_debug & IEEE80211_MSG_RADKEYS)
#define ieee80211_msg_scan(_ic) \
((_ic)->ic_debug & IEEE80211_MSG_SCAN)
#define ieee80211_msg_assoc(_ic) \
((_ic)->ic_debug & IEEE80211_MSG_ASSOC)
#else
#define IEEE80211_DPRINTF(_ic, _m, _fmt, ...)
#define IEEE80211_NOTE_FRAME(_ic, _m, _wh, _fmt, ...)
#define IEEE80211_NOTE_MAC(_ic, _m, _mac, _fmt, ...)
#define ieee80211_msg_dumppkts(_ic) 0
#define ieee80211_msg(_ic, _m) 0
#endif
#endif /* _NET80211_IEEE80211_VAR_H_ */