⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ieee80211_scan_sta.c

📁 Linux下wifi实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/*- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: ieee80211_scan_sta.c 1662 2006-07-02 07:19:37Z mrenzmann $ */#ifndef EXPORT_SYMTAB#define	EXPORT_SYMTAB#endif/* * IEEE 802.11 station scanning support. */#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/init.h>#include <linux/delay.h>#include "if_media.h"#include <net80211/ieee80211_var.h>/* * Parameters for managing cache entries: * * o a station with STA_FAILS_MAX failures is not considered *   when picking a candidate * o a station that hasn't had an update in STA_PURGE_SCANS *   (background) scans is discarded * o after STA_FAILS_AGE seconds we clear the failure count */#define	STA_FAILS_MAX	2		/* assoc failures before ignored */#define	STA_FAILS_AGE	(2 * 60)	/* time before clearing fails (secs) */#define	STA_PURGE_SCANS	2		/* age for purging entries (scans) *//* XXX tunable */#define	STA_RSSI_MIN	8		/* min acceptable rssi */#define RSSI_LPF_LEN	10#define	RSSI_EP_MULTIPLIER	(1<<7)	/* pow2 to optimize out * and / */#define RSSI_IN(x)		((x) * RSSI_EP_MULTIPLIER)#define LPF_RSSI(x, y, len)	(((x) * ((len) - 1) + (y)) / (len))#define RSSI_LPF(x, y) do {						\    if ((y) >= -20)							\    	x = LPF_RSSI((x), RSSI_IN((y)), RSSI_LPF_LEN);			\} while (0)#define	EP_RND(x, mul) \	((((x)%(mul)) >= ((mul)/2)) ? howmany(x, mul) : (x)/(mul))#define	RSSI_GET(x)	EP_RND(x, RSSI_EP_MULTIPLIER)struct sta_entry {	struct ieee80211_scan_entry base;	TAILQ_ENTRY(sta_entry) se_list;	LIST_ENTRY(sta_entry) se_hash;	u_int8_t	se_fails;		/* failure to associate count */	u_int8_t	se_seen;		/* seen during current scan */	u_int8_t	se_notseen;		/* not seen in previous scans */	u_int32_t se_avgrssi;		/* LPF rssi state */	unsigned long se_lastupdate;	/* time of last update */	unsigned long se_lastfail;	/* time of last failure */	unsigned long se_lastassoc;	/* time of last association */	u_int se_scangen;		/* iterator scan gen# */};#define	STA_HASHSIZE	32/* simple hash is enough for variation of macaddr */#define	STA_HASH(addr)	\	(((const u_int8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % STA_HASHSIZE)struct sta_table {	spinlock_t st_lock;			/* on scan table */	TAILQ_HEAD(, sta_entry) st_entry;	/* all entries */	ATH_LIST_HEAD(, sta_entry) st_hash[STA_HASHSIZE];	spinlock_t st_scanlock;			/* on st_scangen */	u_int st_scangen;			/* gen# for iterator */	int st_newscan;	struct IEEE80211_TQ_STRUCT st_actiontq;	/* tasklet for "action" */	struct ieee80211_scan_entry st_selbss;	/* selected bss for action tasklet */	int (*st_action)(struct ieee80211vap *, const struct ieee80211_scan_entry *);};static void sta_flush_table(struct sta_table *);static int match_bss(struct ieee80211vap *, const struct ieee80211_scan_state *,	const struct sta_entry *);static void action_tasklet(IEEE80211_TQUEUE_ARG);/* * Attach prior to any scanning work. */static intsta_attach(struct ieee80211_scan_state *ss){	struct sta_table *st;	_MOD_INC_USE(THIS_MODULE, return 0);	MALLOC(st, struct sta_table *, sizeof(struct sta_table),		M_80211_SCAN, M_NOWAIT | M_ZERO);	if (st == NULL)		return 0;	spin_lock_init(&st->st_lock);	spin_lock_init(&st->st_scanlock);	TAILQ_INIT(&st->st_entry);	IEEE80211_INIT_TQUEUE(&st->st_actiontq, action_tasklet, ss);	ss->ss_priv = st;	return 1;}/* * Cleanup any private state. */static intsta_detach(struct ieee80211_scan_state *ss){	struct sta_table *st = ss->ss_priv;	if (st != NULL) {		IEEE80211_CANCEL_TQUEUE(&st->st_actiontq);		sta_flush_table(st);		FREE(st, M_80211_SCAN);	}	_MOD_DEC_USE(THIS_MODULE);	return 1;}/* * Flush all per-scan state. */static intsta_flush(struct ieee80211_scan_state *ss){	struct sta_table *st = ss->ss_priv;	spin_lock(&st->st_lock);	sta_flush_table(st);	spin_unlock(&st->st_lock);	ss->ss_last = 0;	return 0;}/* * Flush all entries in the scan cache. */static voidsta_flush_table(struct sta_table *st){	struct sta_entry *se, *next;	TAILQ_FOREACH_SAFE(se, &st->st_entry, se_list, next) {		TAILQ_REMOVE(&st->st_entry, se, se_list);		LIST_REMOVE(se, se_hash);		FREE(se, M_80211_SCAN);	}}static voidsaveie(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; create an * entry in the scan cache or update any previous entry. */static intsta_add(struct ieee80211_scan_state *ss, 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)#define	PICK1ST(_ss) \	((ss->ss_flags & (IEEE80211_SCAN_PICK1ST | IEEE80211_SCAN_GOTPICK)) == \	IEEE80211_SCAN_PICK1ST)	struct sta_table *st = ss->ss_priv;	const u_int8_t *macaddr = wh->i_addr2;	struct ieee80211vap *vap = ss->ss_vap;	struct ieee80211com *ic = vap->iv_ic;	struct sta_entry *se;	struct ieee80211_scan_entry *ise;	int hash;	hash = STA_HASH(macaddr);	spin_lock(&st->st_lock);  	LIST_FOREACH(se, &st->st_hash[hash], se_hash)		if (IEEE80211_ADDR_EQ(se->base.se_macaddr, macaddr) &&		    sp->ssid[1] == se->base.se_ssid[1] && 		    !memcmp(se->base.se_ssid+2, sp->ssid+2, se->base.se_ssid[1]))			goto found;	MALLOC(se, struct sta_entry *, sizeof(struct sta_entry),		M_80211_SCAN, M_NOWAIT | M_ZERO);	if (se == NULL) {		spin_unlock(&st->st_lock);		return 0;	}	se->se_scangen = st->st_scangen-1;	IEEE80211_ADDR_COPY(se->base.se_macaddr, macaddr);	TAILQ_INSERT_TAIL(&st->st_entry, se, se_list);	LIST_INSERT_HEAD(&st->st_hash[hash], se, se_hash);found:	ise = &se->base;	/* XXX ap beaconing multiple ssid w/ same bssid */	if (sp->ssid[1] != 0 &&	    (ISPROBE(subtype) || ise->se_ssid[1] == 0))		memcpy(ise->se_ssid, sp->ssid, 2 + sp->ssid[1]);	KASSERT(sp->rates[1] <= IEEE80211_RATE_MAXSIZE,		("rate set too large: %u", sp->rates[1]));	memcpy(ise->se_rates, sp->rates, 2 + sp->rates[1]);	if (sp->xrates != NULL) {		/* XXX validate xrates[1] */		KASSERT(sp->xrates[1] <= IEEE80211_RATE_MAXSIZE,			("xrate set too large: %u", sp->xrates[1]));		memcpy(ise->se_xrates, sp->xrates, 2 + sp->xrates[1]);	} else		ise->se_xrates[1] = 0;	IEEE80211_ADDR_COPY(ise->se_bssid, wh->i_addr3);	/*	 * Record rssi data using extended precision LPF filter.	 */	if (se->se_lastupdate == 0)		/* first sample */		se->se_avgrssi = RSSI_IN(rssi);	else					/* avg w/ previous samples */		RSSI_LPF(se->se_avgrssi, rssi);	se->base.se_rssi = RSSI_GET(se->se_avgrssi);	ise->se_rstamp = rstamp;	memcpy(ise->se_tstamp.data, sp->tstamp, sizeof(ise->se_tstamp));	ise->se_intval = sp->bintval;	ise->se_capinfo = sp->capinfo;	ise->se_chan = ic->ic_curchan;	ise->se_fhdwell = sp->fhdwell;	ise->se_fhindex = sp->fhindex;	ise->se_erp = sp->erp;	ise->se_timoff = sp->timoff;	if (sp->tim != NULL) {		const struct ieee80211_tim_ie *tim =		    (const struct ieee80211_tim_ie *) sp->tim;		ise->se_dtimperiod = tim->tim_period;	}	saveie(&ise->se_wme_ie, sp->wme);	saveie(&ise->se_wpa_ie, sp->wpa);	saveie(&ise->se_rsn_ie, sp->rsn);	saveie(&ise->se_ath_ie, sp->ath);	/* clear failure count after STA_FAIL_AGE passes */	if (se->se_fails && (jiffies - se->se_lastfail) > STA_FAILS_AGE*HZ) {		se->se_fails = 0;		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_SCAN, macaddr,			"%s: fails %u", __func__, se->se_fails);	}	se->se_lastupdate = jiffies;		/* update time */	se->se_seen = 1;	se->se_notseen = 0;	spin_unlock(&st->st_lock);	/*	 * If looking for a quick choice and nothing's	 * been found check here.	 */	if (PICK1ST(ss) && match_bss(vap, ss, se) == 0)		ss->ss_flags |= IEEE80211_SCAN_GOTPICK;	return 1;#undef PICK1ST#undef ISPROBE}static struct ieee80211_channel *find11gchannel(struct ieee80211com *ic, int i, int freq){	struct ieee80211_channel *c;	int j;	/*	 * The normal ordering in the channel list is b channel	 * immediately followed by g so optimize the search for	 * this.  We'll still do a full search just in case.	 */	for (j = i+1; j < ic->ic_nchans; j++) {		c = &ic->ic_channels[j];		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))			return c;	}	for (j = 0; j < i; j++) {		c = &ic->ic_channels[j];		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))			return c;	}	return NULL;}static const u_int chanflags[] = {	IEEE80211_CHAN_B,	/* IEEE80211_MODE_AUTO */	IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */	IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */	IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */	IEEE80211_CHAN_A,	/* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_TURBO_G */	IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_STATIC_A */};static voidadd_channels(struct ieee80211com *ic,	struct ieee80211_scan_state *ss,	enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq){#define	N(a)	(sizeof(a) / sizeof(a[0]))	struct ieee80211_channel *c, *cg;	u_int modeflags;	int i;	KASSERT(mode < N(chanflags), ("Unexpected mode %u", mode));	modeflags = chanflags[mode];	for (i = 0; i < nfreq; i++) {		c = ieee80211_find_channel(ic, freq[i], modeflags);		if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))			continue;		if (mode == IEEE80211_MODE_AUTO) {			/*			 * XXX special-case 11b/g channels so we select			 *     the g channel if both are present.			 */			if (IEEE80211_IS_CHAN_B(c) &&			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)				c = cg;		}		if (ss->ss_last >= IEEE80211_SCAN_MAX)			break;		ss->ss_chans[ss->ss_last++] = c;	}#undef N}static const u_int16_t rcl1[] =		/* 8 FCC channel: 52, 56, 60, 64, 36, 40, 44, 48 */{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 };static const u_int16_t rcl2[] =		/* 4 MKK channels: 34, 38, 42, 46 */{ 5170, 5190, 5210, 5230 };static const u_int16_t rcl3[] =		/* 2.4Ghz ch: 1,6,11,7,13 */{ 2412, 2437, 2462, 2442, 2472 };static const u_int16_t rcl4[] =		/* 5 FCC channel: 149, 153, 161, 165 */{ 5745, 5765, 5785, 5805, 5825 };static const u_int16_t rcl7[] =		/* 11 ETSI channel: 100,104,108,112,116,120,124,128,132,136,140 */{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 };static const u_int16_t rcl8[] =		/* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 };static const u_int16_t rcl9[] =		/* 2.4Ghz ch: 14 */{ 2484 };static const u_int16_t rcl10[] =	/* Added Korean channels 2312-2372 */{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 };static const u_int16_t rcl11[] =	/* Added Japan channels in 4.9/5.0 spectrum */{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 };#ifdef ATH_TURBO_SCANstatic const u_int16_t rcl5[] =		/* 3 static turbo channels */{ 5210, 5250, 5290 };static const u_int16_t rcl6[] =		/* 2 static turbo channels */{ 5760, 5800 };static const u_int16_t rcl6x[] =		/* 4 FCC3 turbo channels */{ 5540, 5580, 5620, 5660 };static const u_int16_t rcl12[] =		/* 2.4Ghz Turbo channel 6 */{ 2437 };static const u_int16_t rcl13[] =		/* dynamic Turbo channels */{ 5200, 5240, 5280, 5765, 5805 };#endif /* ATH_TURBO_SCAN */struct scanlist {	u_int16_t	mode;	u_int16_t	count;	const u_int16_t	*list;};#define	IEEE80211_MODE_TURBO_STATIC_A	IEEE80211_MODE_MAX#define	X(a)	.count = sizeof(a)/sizeof(a[0]), .list = astatic const struct scanlist staScanTable[] = {	{ IEEE80211_MODE_11B,   		X(rcl3) },	{ IEEE80211_MODE_11A,   		X(rcl1) },	{ IEEE80211_MODE_11A,   		X(rcl2) },	{ IEEE80211_MODE_11B,   		X(rcl8) },	{ IEEE80211_MODE_11B,   		X(rcl9) },	{ IEEE80211_MODE_11A,   		X(rcl4) },#ifdef ATH_TURBO_SCAN	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl5) },	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl6) },	{ IEEE80211_MODE_TURBO_A,		X(rcl6x) },	{ IEEE80211_MODE_TURBO_A,		X(rcl13) },#endif /* ATH_TURBO_SCAN */	{ IEEE80211_MODE_11A,			X(rcl7) },	{ IEEE80211_MODE_11B,			X(rcl10) },	{ IEEE80211_MODE_11A,			X(rcl11) },#ifdef ATH_TURBO_SCAN	{ IEEE80211_MODE_TURBO_G,		X(rcl12) },#endif /* ATH_TURBO_SCAN */	{ .list = NULL }};#undef Xstatic intchecktable(const struct scanlist *scan, const struct ieee80211_channel *c){	int i;	for (; scan->list != NULL; scan++) {		for (i = 0; i < scan->count; i++)			if (scan->list[i] == c->ic_freq) 				return 1;	}	return 0;}/* * Start a station-mode scan by populating the channel list. */static intsta_start(struct ieee80211_scan_state *ss, struct ieee80211vap *vap){#define	N(a)	(sizeof(a)/sizeof(a[0]))	struct ieee80211com *ic = vap->iv_ic;	struct sta_table *st = ss->ss_priv;	const struct scanlist *scan;	enum ieee80211_phymode mode;	struct ieee80211_channel *c;	int i;		ss->ss_last = 0;	/*	 * Use the table of ordered channels to construct the list	 * of channels for scanning.  Any channels in the ordered	 * list not in the master list will be discarded.	 */	for (scan = staScanTable; scan->list != NULL; scan++) {		mode = scan->mode;		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {			/*			 * If a desired mode was specified, scan only 			 * channels that satisfy that constraint.			 */			if (vap->iv_des_mode != mode) {				/*				 * The scan table marks 2.4Ghz channels as b				 * so if the desired mode is 11g, then use				 * the 11b channel list but upgrade the mode.				 */				if (vap->iv_des_mode != IEEE80211_MODE_11G ||				    mode != IEEE80211_MODE_11B)					continue;				mode = IEEE80211_MODE_11G;	/* upgrade */			}		} else {			/*			 * This lets ieee80211_scan_add_channels			 * upgrade an 11b channel to 11g if available.			 */			if (mode == IEEE80211_MODE_11B)				mode = IEEE80211_MODE_AUTO;		}		/* XR does not operate on turbo channels */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -