Resolve conflicts and adapt to NetBSD.

Thanks to dyoung@, scw@, and perry@ for help testing.

2005-08-30 15:27  avatar

Properly set ic_curchan before calling back to device driver to do channel
switching(ifconfig devX channel Y).  This fix should make channel changing
works again in monitor mode.

Submitted by:	sam
X-MFC-With:	other ic_curchan changes

2005-08-13 18:50  sam

revert 1.64: we cannot use the channel characteristics to decide when to
do 11g erp sta accounting because b/g channels show up as false positives
when operating in 11b.

Noticed by:	Michal Mertl

2005-08-13 18:31  sam

Extend acl support to pass ioctl requests through and use this to
add support for getting the current policy setting and collecting
the list of mac addresses in the acl table.

Submitted by:	Michal Mertl (original version)
MFC after:	2 weeks

2005-08-10 18:42  sam

Don't use ic_curmode to decide when to do 11g station accounting,
use the station channel properties.  Fixes assert failure/bogus
operation when an ap is operating in 11a and has associated stations
then switches to 11g.

Noticed by:	Michal Mertl
Reviewed by:	avatar
MFC after:	2 weeks

2005-08-10 17:22  sam

Clarify/fix handling of the current channel:
o add ic_curchan and use it uniformly for specifying the current
  channel instead of overloading ic->ic_bss->ni_chan (or in some
  drivers ic_ibss_chan)
o add ieee80211_scanparams structure to encapsulate scanning-related
  state captured for rx frames
o move rx beacon+probe response frame handling into separate routines
o change beacon+probe response handling to treat the scan table
  more like a scan cache--look for an existing entry before adding
  a new one; this combined with ic_curchan use corrects handling of
  stations that were previously found at a different channel
o move adhoc neighbor discovery by beacon+probe response frames to
  a new ieee80211_add_neighbor routine

Reviewed by:	avatar
Tested by:	avatar, Michal Mertl
MFC after:	2 weeks

2005-08-09 11:19  rwatson

Propagate rename of IFF_OACTIVE and IFF_RUNNING to IFF_DRV_OACTIVE and
IFF_DRV_RUNNING, as well as the move from ifnet.if_flags to
ifnet.if_drv_flags.  Device drivers are now responsible for
synchronizing access to these flags, as they are in if_drv_flags.  This
helps prevent races between the network stack and device driver in
maintaining the interface flags field.

Many __FreeBSD__ and __FreeBSD_version checks maintained and continued;
some less so.

Reviewed by:	pjd, bz
MFC after:	7 days

2005-08-08 19:46  sam

Split crypto tx+rx key indices and add a key index -> node mapping table:

Crypto changes:
o change driver/net80211 key_alloc api to return tx+rx key indices; a
  driver can leave the rx key index set to IEEE80211_KEYIX_NONE or set
  it to be the same as the tx key index (the former disables use of
  the key index in building the keyix->node mapping table and is the
  default setup for naive drivers by null_key_alloc)
o add cs_max_keyid to crypto state to specify the max h/w key index a
  driver will return; this is used to allocate the key index mapping
  table and to bounds check table loookups
o while here introduce ieee80211_keyix (finally) for the type of a h/w
  key index
o change crypto notifiers for rx failures to pass the rx key index up
  as appropriate (michael failure, replay, etc.)

Node table changes:
o optionally allocate a h/w key index to node mapping table for the
  station table using the max key index setting supplied by drivers
  (note the scan table does not get a map)
o defer node table allocation to lateattach so the driver has a chance
  to set the max key id to size the key index map
o while here also defer the aid bitmap allocation
o add new ieee80211_find_rxnode_withkey api to find a sta/node entry
  on frame receive with an optional h/w key index to use in checking
  mapping table; also updates the map if it does a hash lookup and the
  found node has a rx key index set in the unicast key; note this work
  is separated from the old ieee80211_find_rxnode call so drivers do
  not need to be aware of the new mechanism
o move some node table manipulation under the node table lock to close
  a race on node delete
o add ieee80211_node_delucastkey to do the dirty work of deleting
  unicast key state for a node (deletes any key and handles key map
  references)

Ath driver:
o nuke private sc_keyixmap mechansim in favor of net80211 support
o update key alloc api

These changes close several race conditions for the ath driver operating
in ap mode.  Other drivers should see no change.  Station mode operation
for ath no longer uses the key index map but performance tests show no
noticeable change and this will be fixed when the scan table is eliminated
with the new scanning support.

Tested by:	Michal Mertl, avatar, others
Reviewed by:	avatar, others
MFC after:	2 weeks

2005-08-08 06:49  sam

use ieee80211_iterate_nodes to retrieve station data; the previous
code walked the list w/o locking

MFC after:	1 week

2005-08-08 04:30  sam

Cleanup beacon/listen interval handling:
o separate configured beacon interval from listen interval; this
  avoids potential use of one value for the other (e.g. setting
  powersavesleep to 0 clobbers the beacon interval used in hostap
  or ibss mode)
o bounds check the beacon interval received in probe response and
  beacon frames and drop frames with bogus settings; not clear
  if we should instead clamp the value as any alteration would
  result in mismatched sta+ap configuration and probably be more
  confusing (don't want to log to the console but perhaps ok with
  rate limiting)
o while here up max beacon interval to reflect WiFi standard

Noticed by:	Martin <nakal@nurfuerspam.de>
MFC after:	1 week

2005-08-06 05:57  sam

fix debug msg typo

MFC after:	3 days

2005-08-06 05:56  sam

Fix handling of frames sent prior to a station being authorized
when operating in ap mode.  Previously we allocated a node from the
station table, sent the frame (using the node), then released the
reference that "held the frame in the table".  But while the frame
was in flight the node might be reclaimed which could lead to
problems.  The solution is to add an ieee80211_tmp_node routine
that crafts a node that does exist in a table and so isn't ever
reclaimed; it exists only so long as the associated frame is in flight.

MFC after:	5 days

2005-07-31 07:12  sam

close a race between reclaiming a node when a station is inactive
and sending the null data frame used to probe inactive stations

MFC after:	5 days

2005-07-27 05:41  sam

when bridging internally bypass the bss node as traffic to it
must follow the normal input path

Submitted by:	Michal Mertl
MFC after:	5 days

2005-07-27 03:53  sam

bandaid ni_fails handling so ap's with association failures are
reconsidered after a bit; a proper fix involves more changes to
the scanning infrastructure

Reviewed by:	avatar, David Young
MFC after:	5 days

2005-07-23 01:16  sam

the AREF flag is only meaningful in ap mode; adhoc neighbors now
are timed out of the sta/neighbor table

2005-07-23 00:25  sam

o move inactivity-related debug msgs under IEEE80211_MSG_INACT
o probe inactive neighbors in adhoc mode (they don't have an
  association id so previously were being timed out)

MFC after:	3 days

2005-07-22 22:11  sam

split xmit of probe request frame out into a separate routine that
takes explicit parameters; this will be needed when scanning is
decoupled from the state machine to do bg scanning

MFC after:	3 days

2005-07-22 21:48  sam

split 802.11 frame xmit setup code into ieee80211_send_setup

MFC after:	3 days

2005-07-22 18:57  sam

simplify ic_newassoc callback

MFC after:	3 days

2005-07-22 18:54  sam

simplify ieee80211_ibss_merge api

MFC after:	3 days

2005-07-22 18:50  sam

add stats we know we'll need soon and some spare fields for future expansion

MFC after:	3 days

2005-07-22 18:45  sam

simplify tim callback api

MFC after:	3 days

2005-07-22 18:42  sam

don't include 802.3 header in min frame length calculation as it may
not be present for a frag; fixes problem with small (fragmented) frames
being dropped

Obtained from:	Atheros
MFC after:	3 days

2005-07-22 18:36  sam

simplify ieee80211_node_authorize and ieee80211_node_unauthorize api's

MFC after:	3 days

2005-07-22 18:31  sam

simplifiy ieee80211_send_nulldata api

MFC after:	3 days

2005-07-22 18:29  sam

simplify rate set api's by removing ic parameter (implicit in node reference)

MFC after:	3 days

2005-07-22 18:21  sam

reject association requests with a wpa/rsn ie when wpa/rsn is not
configured on the ap; previously we either ignored the ie or (possibly)
failed an assertion

Obtained from:	Atheros
MFC after:	3 days

2005-07-22 18:16  sam

missed one in last commit; add device name to discard msgs

2005-07-22 18:13  sam

include device name in discard msgs

2005-07-22 18:12  sam

add diag msgs for frames discarded because the direction field is wrong

2005-07-22 18:08  sam

split data frame delivery out to a new function ieee80211_deliver_data

2005-07-22 18:00  sam

o add IEEE80211_IOC_FRAGTHRESHOLD for getting+setting the
  tx fragmentation threshold
o fix bounds checking on IEEE80211_IOC_RTSTHRESHOLD

MFC after:	3 days

2005-07-22 17:55  sam

o add IEEE80211_FRAG_DEFAULT
o move default settings for RTS and frag thresholds to ieee80211_var.h

2005-07-22 17:50  sam

diff reduction against p4: define IEEE80211_FIXED_RATE_NONE and use
it instead of -1

2005-07-22 17:37  sam

add flags missed in last merge

2005-07-22 17:36  sam

Diff reduction against p4:
o add ic_flags_ext for eventual extention of ic_flags
o define/reserve flag+capabilities bits for superg,
  bg scan, and roaming support
o refactor debug msg macros

MFC after:	3 days

2005-07-22 06:17  sam

send a response when an auth request is denied due to an acl;
might be better to silently ignore the frame but this way we
give stations a chance of figuring out what's wrong

2005-07-22 06:15  sam

remove excess whitespace

2005-07-22 05:55  sam

use IF_HANDOFF when bridging frames internally so if_start gets
called; fixes communication between associated sta's

MFC after:	3 days

2005-07-11 04:06  sam

Handle encrypt of arbitarily fragmented mbuf chains: previously
we bailed if we couldn't collect the 16-bytes of data required
for an aes block cipher in 2 mbufs; now we deal with it.  While
here make space accounting signed so a sanity check does the
right thing for malformed mbuf chains.

Approved by:	re (scottl)

2005-07-11 04:00  sam

nuke assert that duplicates real check

Reviewed by:	avatar
Approved by:	re (scottl)
This commit is contained in:
skrll 2005-11-18 16:40:08 +00:00
parent 931fb40431
commit 87515e34ff
18 changed files with 1463 additions and 678 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: init_main.c,v 1.251 2005/08/05 11:03:18 junyoung Exp $ */
/* $NetBSD: init_main.c,v 1.252 2005/11/18 16:40:08 skrll Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993
@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.251 2005/08/05 11:03:18 junyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.252 2005/11/18 16:40:08 skrll Exp $");
#include "fs_nfs.h"
#include "opt_nfsserver.h"
@ -153,6 +153,7 @@ __KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.251 2005/08/05 11:03:18 junyoung Exp
#ifdef VERIFIED_EXEC
#include <sys/verified_exec.h>
#endif
#include <net80211/ieee80211_netbsd.h>
#include <sys/syscall.h>
#include <sys/sa.h>
@ -284,6 +285,9 @@ main(void)
/* Initialize signal-related data structures. */
signal_init();
/* Initialize the net80211 layer */
ieee80211_init();
/* Create process 0 (the swapper). */
proc0_init();

View File

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211.c,v 1.40 2005/07/26 22:52:48 dyoung Exp $ */
/* $NetBSD: ieee80211.c,v 1.41 2005/11/18 16:40:08 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -33,10 +33,10 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__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 $");
#endif
#ifdef __NetBSD__
__KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.40 2005/07/26 22:52:48 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.41 2005/11/18 16:40:08 skrll Exp $");
#endif
/*
@ -196,6 +196,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 */
@ -211,12 +215,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;
LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list);
@ -708,7 +714,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211.h,v 1.14 2005/07/26 22:52:48 dyoung Exp $ */
/* $NetBSD: ieee80211.h,v 1.15 2005/11/18 16:40:08 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -30,7 +30,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_
@ -626,11 +626,19 @@ 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
/*
* 802.11 frame duration definitions.

View File

@ -31,10 +31,10 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__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 $");
#endif
#ifdef __NetBSD__
__KERNEL_RCSID(0, "$NetBSD: ieee80211_acl.c,v 1.3 2005/07/26 22:52:48 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211_acl.c,v 1.4 2005/11/18 16:40:08 skrll Exp $");
#endif
/*
@ -79,6 +79,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;
@ -98,7 +99,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");
@ -142,6 +143,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
@ -190,6 +192,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,
@ -264,6 +267,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,
@ -274,4 +324,6 @@ 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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_crypto.c,v 1.9 2005/07/26 22:52:48 dyoung Exp $ */
/* $NetBSD: ieee80211_crypto.c,v 1.10 2005/11/18 16:40:08 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -33,10 +33,10 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__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 $");
#endif
#ifdef __NetBSD__
__KERNEL_RCSID(0, "$NetBSD: ieee80211_crypto.c,v 1.9 2005/07/26 22:52:48 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211_crypto.c,v 1.10 2005/11/18 16:40:08 skrll Exp $");
#endif
#include "opt_inet.h"
@ -81,7 +81,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])) {
@ -95,12 +96,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)
@ -135,9 +138,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
@ -165,11 +169,8 @@ ieee80211_crypto_attach(struct ieee80211com *ic)
/* NB: we assume everything is pre-zero'd */
cs->cs_def_txkey = IEEE80211_KEYIX_NONE;
ciphers[IEEE80211_CIPHER_AES_CCM] = &ieee80211_cipher_ccmp;
ciphers[IEEE80211_CIPHER_TKIP] = &ieee80211_cipher_tkip;
ciphers[IEEE80211_CIPHER_WEP] = &ieee80211_cipher_wep;
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],
IEEE80211_KEYIX_NONE);
@ -267,6 +268,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;
@ -380,8 +382,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
@ -408,6 +409,8 @@ again:
__func__, cip->ic_name);
return 0;
}
key->wk_keyix = keyix;
key->wk_rxkeyix = rxkeyix;
}
return 1;
#undef N
@ -419,7 +422,7 @@ again:
static int
_ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key)
{
u_int16_t keyix;
ieee80211_keyix keyix;
IASSERT(key->wk_cipher != NULL, ("No cipher!"));
@ -547,7 +550,7 @@ ieee80211_crypto_encap(struct ieee80211com *ic,
ether_sprintf(wh->i_addr1), __func__,
ic->ic_def_txkey);
ic->ic_stats.is_tx_nodefkey++;
goto bad;
return NULL;
}
keyid = ic->ic_def_txkey;
k = &ic->ic_nw_keys[ic->ic_def_txkey];
@ -556,10 +559,7 @@ ieee80211_crypto_encap(struct ieee80211com *ic,
k = &ni->ni_ucastkey;
}
cip = k->wk_cipher;
if (cip->ic_encap(k, m, keyid<<6))
return k;
bad:
return NULL;
return (cip->ic_encap(k, m, keyid<<6) ? k : NULL);
}
/*
@ -572,7 +572,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_crypto.h,v 1.6 2005/07/26 22:57:26 dyoung Exp $ */
/* $NetBSD: ieee80211_crypto.h,v 1.7 2005/11/18 16:40:08 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -30,7 +30,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_
@ -67,18 +67,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 */
@ -104,7 +105,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)
#define IEEE80211_KEY_UNDEFINED(k) ((k).wk_cipher == &ieee80211_cipher_none)
#if defined(__KERNEL__) || defined(_KERNEL)
@ -122,10 +123,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 *,
@ -209,11 +212,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

@ -31,10 +31,10 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__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 $");
#endif
#ifdef __NetBSD__
__KERNEL_RCSID(0, "$NetBSD: ieee80211_crypto_tkip.c,v 1.3 2005/07/26 22:52:48 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211_crypto_tkip.c,v 1.4 2005/11/18 16:40:08 skrll Exp $");
#endif
/*
@ -343,7 +343,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;
}
}
@ -968,3 +970,8 @@ tkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
}
return 1;
}
IEEE80211_CRYPTO_SETUP(tkip_register)
{
ieee80211_crypto_register(&tkip);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_input.c,v 1.46 2005/09/24 23:04:51 dyoung Exp $ */
/* $NetBSD: ieee80211_input.c,v 1.47 2005/11/18 16:40:08 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -33,10 +33,10 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__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 $");
#endif
#ifdef __NetBSD__
__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.46 2005/09/24 23:04:51 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.47 2005/11/18 16:40:08 skrll Exp $");
#endif
#include "opt_inet.h"
@ -140,6 +140,8 @@ 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);
#ifndef IEEE80211_NO_HOSTAP
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 *);
@ -325,6 +327,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;
}
@ -346,6 +350,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;
}
@ -354,6 +360,8 @@ ieee80211_input(struct ieee80211com *ic, struct mbuf *m,
case IEEE80211_M_HOSTAP:
#ifndef IEEE80211_NO_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;
}
@ -503,71 +511,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);
#ifndef IEEE80211_NO_HOSTAP
/* 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) {
int len;
#ifdef ALTQ
if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
altq_etherclassify(&ifp->if_snd, m1,
&pktattr);
}
#endif
len = m1->m_pkthdr.len;
IF_ENQUEUE(&ifp->if_snd, m1);
if (m != NULL)
ifp->if_omcasts++;
ifp->if_obytes += len;
}
}
#endif /* !IEEE80211_NO_HOSTAP */
if (m != NULL) {
#if NBPFILTER > 0
/*
* XXX If we forward packet into transmitter of the AP,
* we don't need to duplicate for DLT_EN10MB.
*/
if (ifp->if_bpf)
bpf_mtap(ifp->if_bpf, m);
#endif
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;
}
@ -749,6 +700,90 @@ 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) {
int len;
#ifdef ALTQ
if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
altq_etherclassify(&ifp->if_snd, m1,
&pktattr);
}
#endif
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 NBPFILTER > 0
/*
* XXX If we forward packet into transmitter of the AP,
* we don't need to duplicate for DLT_EN10MB.
*/
if (ifp->if_bpf)
bpf_mtap(ifp->if_bpf, m);
#endif
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)
{
@ -851,10 +886,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));
@ -877,7 +913,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
@ -940,7 +976,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);
#endif /* !IEEE80211_NO_HOSTAP */
break;
@ -981,7 +1017,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;
@ -1167,7 +1203,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,
@ -1429,8 +1465,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.
*/
IASSERT(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,
@ -1592,8 +1632,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.
*/
IASSERT(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,
@ -1720,7 +1764,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;
@ -1737,38 +1781,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,
@ -1788,10 +1800,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:
@ -1822,32 +1831,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:
@ -1856,17 +1862,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) {
@ -1876,16 +1882,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:
@ -1897,21 +1903,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;
@ -1922,17 +1930,28 @@ 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;
}
if (ni != ic->ic_bss) {
ni = ieee80211_refine_node_for_beacon(ic, ni,
&ic->ic_channels[chan], ssid);
&ic->ic_channels[scan.chan], scan.ssid);
}
/*
* Count frame now that we know it's to be processed.
@ -1953,27 +1972,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
@ -1981,105 +2000,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;
}
@ -2139,7 +2104,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;
@ -2149,7 +2114,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) {
@ -2191,6 +2156,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) {
@ -2232,7 +2202,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;
@ -2269,7 +2239,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;
@ -2289,10 +2259,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;
@ -2375,7 +2344,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);
/*
@ -2398,7 +2367,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;
@ -2496,7 +2465,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) {
@ -2615,7 +2584,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:
@ -2679,7 +2648,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,
@ -2704,7 +2673,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);
}
/*
@ -2748,10 +2717,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;
}
/*
@ -2769,7 +2738,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);
@ -2796,6 +2765,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,
@ -2803,11 +2814,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);
@ -2821,11 +2833,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);
@ -2839,11 +2852,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_ioctl.c,v 1.25 2005/07/27 20:31:24 dyoung Exp $ */
/* $NetBSD: ieee80211_ioctl.c,v 1.26 2005/11/18 16:40:08 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -33,10 +33,10 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__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 $");
#endif
#ifdef __NetBSD__
__KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.25 2005/07/27 20:31:24 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.26 2005/11/18 16:40:08 skrll Exp $");
#endif
/*
@ -68,8 +68,16 @@ __KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.25 2005/07/27 20:31:24 dyoung
#include <dev/ic/wi_ieee.h>
#ifdef __FreeBSD__
#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))
#endif
#ifdef __NetBSD__
#define IS_UP(_ic) \
(((_ic)->ic_ifp->if_flags & IFF_UP) && \
((_ic)->ic_ifp->if_flags & IFF_RUNNING))
#endif
#define IS_UP_AUTO(_ic) \
(IS_UP(_ic) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
@ -256,7 +264,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:
@ -278,7 +286,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(
@ -456,7 +464,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
@ -468,20 +475,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
@ -601,7 +594,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]);
@ -841,20 +834,6 @@ ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, caddr_t data)
return error;
}
#ifdef __FreeBSD__
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;
}
}
#endif /* __FreeBSD__ */
static int
cap2cipher(int flag)
{
@ -1091,18 +1070,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;
@ -1126,55 +1144,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;
}
@ -1241,6 +1264,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()
@ -1329,7 +1360,7 @@ ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
break;
#ifdef __FreeBSD__
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)
@ -1480,6 +1511,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;
@ -1609,7 +1646,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)
@ -1712,9 +1749,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:
@ -1749,7 +1786,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;
@ -1777,7 +1814,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;
}
@ -1823,9 +1863,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;
}
@ -2095,8 +2132,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) {
@ -2127,8 +2174,8 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
break;
#endif /* __FreeBSD__ */
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;
@ -2324,7 +2371,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);
@ -2354,7 +2401,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;
@ -2368,6 +2415,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_ioctl.h,v 1.14 2005/07/27 20:31:25 dyoung Exp $ */
/* $NetBSD: ieee80211_ioctl.h,v 1.15 2005/11/18 16:40:08 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -30,7 +30,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_
@ -196,6 +196,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 */
@ -220,6 +222,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];
};
/*
@ -290,6 +299,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];
};
/*
@ -487,6 +502,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_netbsd.c,v 1.7 2005/09/24 23:57:12 dyoung Exp $ */
/* $NetBSD: ieee80211_netbsd.c,v 1.8 2005/11/18 16:40:09 skrll Exp $ */
/*-
* Copyright (c) 2003-2005 Sam Leffler, Errno Consulting
* All rights reserved.
@ -28,9 +28,9 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_freebsd.c,v 1.6 2005/01/22 20:29:23 sam Exp $");
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_freebsd.c,v 1.8 2005/08/08 18:46:35 sam Exp $");
#else
__KERNEL_RCSID(0, "$NetBSD: ieee80211_netbsd.c,v 1.7 2005/09/24 23:57:12 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211_netbsd.c,v 1.8 2005/11/18 16:40:09 skrll Exp $");
#endif
/*
@ -70,6 +70,21 @@ static int ieee80211_sysctl_node(SYSCTLFN_ARGS);
int ieee80211_debug = 0;
#endif
typedef void (*ieee80211_setup_func)(void);
__link_set_decl(ieee80211_funcs, ieee80211_setup_func);
void
ieee80211_init(void)
{
ieee80211_setup_func * const *ieee80211_setup, f;
__link_set_foreach(ieee80211_setup, ieee80211_funcs) {
f = (void*)*ieee80211_setup;
(*f)();
}
}
static int
ieee80211_sysctl_inact(SYSCTLFN_ARGS)
{
@ -661,9 +676,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;
@ -671,7 +687,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_netbsd.h,v 1.6 2005/08/18 06:07:30 skrll Exp $ */
/* $NetBSD: ieee80211_netbsd.h,v 1.7 2005/11/18 16:40:09 skrll Exp $ */
/*-
* Copyright (c) 2003-2005 Sam Leffler, Errno Consulting
* All rights reserved.
@ -25,7 +25,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_NETBSD_H_
#define _NET80211_IEEE80211_NETBSD_H_
@ -53,6 +53,8 @@ struct ieee80211_lock {
if ((_ic)->_member.count++ == 0) \
(_ic)->_member.ipl = __s; \
} while (0)
#define IEEE80211_IS_LOCKED_IMPL(_ic, _member) \
((_ic)->_member.count != 0)
#define IEEE80211_UNLOCK_IMPL(_ic, _member) \
do { \
if (--(_ic)->_member.count == 0) \
@ -78,6 +80,7 @@ typedef struct ieee80211_lock ieee80211_beacon_lock_t;
/*
* Node locking definitions.
* NB: MTX_DUPOK is because we don't generate per-interface strings.
*/
typedef struct ieee80211_lock ieee80211_node_lock_t;
#define IEEE80211_NODE_LOCK_INIT(_nt, _name) \
@ -85,6 +88,8 @@ typedef struct ieee80211_lock ieee80211_node_lock_t;
#define IEEE80211_NODE_LOCK_DESTROY(_nt)
#define IEEE80211_NODE_LOCK(_nt) \
IEEE80211_LOCK_IMPL(_nt, nt_nodelock)
#define IEEE80211_NODE_IS_LOCKED(_nt) \
IEEE80211_IS_LOCKED_IMPL(_nt, nt_nodelock)
#define IEEE80211_NODE_UNLOCK(_nt) \
IEEE80211_UNLOCK_IMPL(_nt, nt_nodelock)
#define IEEE80211_NODE_LOCK_ASSERT(_nt) \
@ -262,4 +267,10 @@ void ieee80211_sysctl_attach(struct ieee80211com *);
void ieee80211_sysctl_detach(struct ieee80211com *);
void ieee80211_load_module(const char *);
void ieee80211_init(void);
#define IEEE80211_CRYPTO_SETUP(name) \
static void name(void); \
__link_set_add_text(ieee80211_funcs, name); \
static void name(void)
#endif /* _NET80211_IEEE80211_NETBSD_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_node.c,v 1.44 2005/09/25 00:03:06 dyoung Exp $ */
/* $NetBSD: ieee80211_node.c,v 1.45 2005/11/18 16:40:09 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -33,10 +33,10 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__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 $");
#endif
#ifdef __NetBSD__
__KERNEL_RCSID(0, "$NetBSD: ieee80211_node.c,v 1.44 2005/09/25 00:03:06 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211_node.c,v 1.45 2005/11/18 16:40:09 skrll Exp $");
#endif
#include "opt_inet.h"
@ -93,11 +93,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);
@ -107,11 +107,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;
@ -123,10 +118,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),
@ -145,22 +147,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);
IASSERT(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;
@ -192,8 +192,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
@ -221,14 +220,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;
}
@ -281,16 +282,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 */
}
@ -344,7 +341,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];
@ -352,28 +349,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;
}
@ -415,7 +403,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;
@ -424,7 +412,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) {
@ -443,6 +431,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.
@ -476,11 +465,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)
{
@ -508,8 +500,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 &&
@ -519,9 +510,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 ? '!' : ' ');
@ -568,6 +562,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) &&
@ -577,6 +572,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) {
@ -695,6 +695,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.
*/
@ -708,23 +719,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;
@ -756,8 +750,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)) {
@ -795,7 +790,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.
@ -821,6 +816,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);
@ -904,7 +900,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) {
@ -928,7 +924,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
}
@ -996,6 +995,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)
{
@ -1088,13 +1123,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
@ -1112,10 +1322,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;
@ -1133,12 +1339,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
@ -1157,15 +1428,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) {
@ -1360,22 +1632,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) {
IASSERT(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
@ -1384,11 +1720,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
@ -1478,7 +1833,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,
@ -1495,7 +1853,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
@ -1514,7 +1873,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
@ -1549,7 +1908,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);
}
}
/*
@ -1560,20 +1919,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
@ -1745,8 +2113,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;
@ -1763,7 +2130,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);
@ -1780,9 +2147,9 @@ static void
ieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni)
{
IASSERT(ic->ic_curmode == IEEE80211_MODE_11G ||
ic->ic_curmode == IEEE80211_MODE_TURBO_G,
("not in 11g, curmode %x", ic->ic_curmode));
IASSERT(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.
@ -1870,8 +2237,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
@ -1947,8 +2313,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;
IASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP ||
@ -1980,7 +2347,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 *))
{
@ -1996,6 +2363,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
@ -2018,7 +2396,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_node.h,v 1.18 2005/07/26 22:52:48 dyoung Exp $ */
/* $NetBSD: ieee80211_node.h,v 1.19 2005/11/18 16:40:09 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -30,7 +30,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_
@ -134,7 +134,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 */
@ -186,10 +186,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 *);
@ -197,7 +195,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 *);
@ -217,6 +215,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 *);
};
@ -224,6 +224,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
@ -235,6 +237,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);
@ -251,6 +257,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) \
@ -263,6 +271,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(
@ -272,6 +282,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 *);
struct ieee80211_node *ieee80211_refine_node_for_beacon(
struct ieee80211com *, struct ieee80211_node *,
@ -289,4 +300,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_output.c,v 1.38 2005/09/25 00:04:01 dyoung Exp $ */
/* $NetBSD: ieee80211_output.c,v 1.39 2005/11/18 16:40:09 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -33,10 +33,10 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__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 $");
#endif
#ifdef __NetBSD__
__KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.38 2005/09/25 00:04:01 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.39 2005/11/18 16:40:09 skrll Exp $");
#endif
#include "opt_inet.h"
@ -95,6 +95,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
@ -132,30 +188,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,
@ -172,7 +207,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);
@ -184,10 +219,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;
@ -196,27 +236,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 */
(*ifp->if_start)(ifp);
@ -1116,6 +1158,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;
IASSERT(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);
(*ic->ic_ifp->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
@ -1128,7 +1255,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;
@ -1148,38 +1274,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
@ -1224,7 +1318,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;
@ -1241,14 +1335,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) {
@ -1339,7 +1433,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:
@ -1380,7 +1474,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))
@ -1436,7 +1530,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;
@ -1803,14 +1897,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_proto.c,v 1.22 2005/08/15 23:37:10 dyoung Exp $ */
/* $NetBSD: ieee80211_proto.c,v 1.23 2005/11/18 16:40:09 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -33,10 +33,10 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__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 $");
#endif
#ifdef __NetBSD__
__KERNEL_RCSID(0, "$NetBSD: ieee80211_proto.c,v 1.22 2005/08/15 23:37:10 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211_proto.c,v 1.23 2005/11/18 16:40:09 skrll Exp $");
#endif
/*
@ -116,13 +116,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;
@ -345,9 +341,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;
@ -357,7 +354,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;
@ -958,9 +956,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:
@ -1076,7 +1077,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
@ -1104,7 +1105,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_proto.h,v 1.12 2005/07/26 22:52:48 dyoung Exp $ */
/* $NetBSD: ieee80211_proto.h,v 1.13 2005/11/18 16:40:09 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -30,7 +30,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.9 2005/01/24 20:38:26 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_
@ -60,9 +60,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 *,
@ -136,6 +145,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
@ -154,6 +164,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 *);
@ -164,7 +176,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

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_var.h,v 1.20 2005/07/26 22:52:48 dyoung Exp $ */
/* $NetBSD: ieee80211_var.h,v 1.21 2005/11/18 16:40:09 skrll Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@ -30,7 +30,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_
@ -68,13 +68,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)
@ -102,11 +108,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];
@ -116,6 +120,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 */
@ -138,6 +143,7 @@ struct ieee80211com {
caddr_t 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;
@ -146,6 +152,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 */
@ -207,7 +214,9 @@ extern struct ieee80211com_head ieee80211com_head;
#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 */
@ -219,7 +228,7 @@ extern struct ieee80211com_head ieee80211com_head;
#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 */
@ -237,12 +246,19 @@ extern struct ieee80211com_head ieee80211com_head;
#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 */
@ -258,6 +274,10 @@ extern struct ieee80211com_head ieee80211com_head;
#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 */
@ -350,14 +370,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) \
@ -372,8 +414,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_ */