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

📄 ieee80211_scan.c

📁 Linux下wifi实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * 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.c 1520 2006-04-21 16:57:59Z dyqith $ */#ifndef EXPORT_SYMTAB#define	EXPORT_SYMTAB#endif/* * IEEE 802.11 scanning support. */#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/random.h>#include <linux/interrupt.h>#include <linux/delay.h>#include "if_media.h"#include <net80211/ieee80211_var.h>#include <net80211/if_athproto.h>struct scan_state {	struct ieee80211_scan_state base;	/* public state */	u_int ss_iflags;				/* flags used internally */#define	ISCAN_MINDWELL 	0x0001		/* min dwell time reached */#define	ISCAN_DISCARD	0x0002		/* discard rx'd frames */#define	ISCAN_CANCEL	0x0004		/* cancel current scan */#define	ISCAN_START	0x0008		/* 1st time through next_scan */	unsigned long ss_chanmindwell;		/* min dwell on curchan */	unsigned long ss_scanend;		/* time scan must stop */	u_int ss_duration;			/* duration for next scan */	struct tasklet_struct ss_pwrsav;	/* sta ps ena tasklet */	struct timer_list ss_scan_timer;	/* scan timer */};#define	SCAN_PRIVATE(ss)	((struct scan_state *) ss)/* * Amount of time to go off-channel during a background * scan.  This value should be large enough to catch most * ap's but short enough that we can return on-channel * before our listen interval expires. * * XXX tunable * XXX check against configured listen interval */#define	IEEE80211_SCAN_OFFCHANNEL	msecs_to_jiffies(150)/* * Roaming-related defaults.  RSSI thresholds are as returned by the * driver (dBm).  Transmit rate thresholds are IEEE rate codes (i.e * .5M units). */#define	SCAN_VALID_DEFAULT		60	/* scan cache valid age (secs) */#define	ROAM_RSSI_11A_DEFAULT		24	/* rssi threshold for 11a bss */#define	ROAM_RSSI_11B_DEFAULT		24	/* rssi threshold for 11b bss */#define	ROAM_RSSI_11BONLY_DEFAULT	24	/* rssi threshold for 11b-only bss */#define	ROAM_RATE_11A_DEFAULT		2*24	/* tx rate threshold for 11a bss */#define	ROAM_RATE_11B_DEFAULT		2*9	/* tx rate threshold for 11b bss */#define	ROAM_RATE_11BONLY_DEFAULT	2*5	/* tx rate threshold for 11b-only bss */static void scan_restart_pwrsav(unsigned long);static void scan_next(unsigned long);voidieee80211_scan_attach(struct ieee80211com *ic){	struct scan_state *ss;	ic->ic_roaming = IEEE80211_ROAMING_AUTO;	MALLOC(ss, struct scan_state *, sizeof(struct scan_state),		M_80211_SCAN, M_NOWAIT | M_ZERO);	if (ss != NULL) {		init_timer(&ss->ss_scan_timer);		ss->ss_scan_timer.function = scan_next;		ss->ss_scan_timer.data = (unsigned long) ss;		tasklet_init(&ss->ss_pwrsav, scan_restart_pwrsav,			(unsigned long) ss);		ic->ic_scan = &ss->base;	} else		ic->ic_scan = NULL;}voidieee80211_scan_detach(struct ieee80211com *ic){	struct ieee80211_scan_state *ss = ic->ic_scan;	if (ss != NULL) {		del_timer(&SCAN_PRIVATE(ss)->ss_scan_timer);		tasklet_kill(&SCAN_PRIVATE(ss)->ss_pwrsav);		if (ss->ss_ops != NULL) {			ss->ss_ops->scan_detach(ss);			ss->ss_ops = NULL;		}		ic->ic_flags &= ~IEEE80211_F_SCAN;		ic->ic_scan = NULL;		FREE(SCAN_PRIVATE(ss), M_80211_SCAN);	}}voidieee80211_scan_vattach(struct ieee80211vap *vap){	vap->iv_bgscanidle = msecs_to_jiffies(IEEE80211_BGSCAN_IDLE_DEFAULT);	vap->iv_bgscanintvl = IEEE80211_BGSCAN_INTVAL_DEFAULT * HZ;	vap->iv_scanvalid = SCAN_VALID_DEFAULT * HZ;	vap->iv_roam.rssi11a = ROAM_RSSI_11A_DEFAULT;	vap->iv_roam.rssi11b = ROAM_RSSI_11B_DEFAULT;	vap->iv_roam.rssi11bOnly = ROAM_RSSI_11BONLY_DEFAULT;	vap->iv_roam.rate11a = ROAM_RATE_11A_DEFAULT;	vap->iv_roam.rate11b = ROAM_RATE_11B_DEFAULT;	vap->iv_roam.rate11bOnly = ROAM_RATE_11BONLY_DEFAULT;}voidieee80211_scan_vdetach(struct ieee80211vap *vap){	struct ieee80211com *ic = vap->iv_ic;	struct ieee80211_scan_state *ss = ic->ic_scan;	IEEE80211_LOCK_IRQ(ic);	if (ss->ss_vap == vap) {		if (ic->ic_flags & IEEE80211_F_SCAN) {			del_timer(&SCAN_PRIVATE(ss)->ss_scan_timer);			ic->ic_flags &= ~IEEE80211_F_SCAN;		}		if (ss->ss_ops != NULL) {			ss->ss_ops->scan_detach(ss);			ss->ss_ops = NULL;		}	}	IEEE80211_UNLOCK_IRQ(ic);}/* * Simple-minded scanner module support. */#define	IEEE80211_SCANNER_MAX	(IEEE80211_M_MONITOR+1)static const char *scan_modnames[IEEE80211_SCANNER_MAX] = {	"wlan_scan_sta",	/* IEEE80211_M_IBSS */	"wlan_scan_sta",	/* IEEE80211_M_STA */	"wlan_scan_wds",	/* IEEE80211_M_WDS */	"wlan_scan_sta",	/* IEEE80211_M_AHDEMO */	"wlan_scan_4",		/* n/a */	"wlan_scan_5",		/* n/a */	"wlan_scan_ap",		/* IEEE80211_M_HOSTAP */	"wlan_scan_7",		/* n/a */	"wlan_scan_monitor",	/* IEEE80211_M_MONITOR */};static const struct ieee80211_scanner *scanners[IEEE80211_SCANNER_MAX];const struct ieee80211_scanner *ieee80211_scanner_get(enum ieee80211_opmode mode, int tryload){	int err;	if (mode >= IEEE80211_SCANNER_MAX)		return NULL;	if (scanners[mode] == NULL && tryload) {		err = ieee80211_load_module(scan_modnames[mode]);		if (scanners[mode] == NULL || err)			printk(KERN_WARNING "unable to load %s\n", scan_modnames[mode]);	}	return scanners[mode];}EXPORT_SYMBOL(ieee80211_scanner_get);voidieee80211_scanner_register(enum ieee80211_opmode mode,	const struct ieee80211_scanner *scan){	if (mode >= IEEE80211_SCANNER_MAX)		return;	scanners[mode] = scan;}EXPORT_SYMBOL(ieee80211_scanner_register);voidieee80211_scanner_unregister(enum ieee80211_opmode mode,	const struct ieee80211_scanner *scan){	if (mode >= IEEE80211_SCANNER_MAX)		return;	if (scanners[mode] == scan)		scanners[mode] = NULL;}EXPORT_SYMBOL(ieee80211_scanner_unregister);voidieee80211_scanner_unregister_all(const struct ieee80211_scanner *scan){	int m;	for (m = 0; m < IEEE80211_SCANNER_MAX; m++)		if (scanners[m] == scan)			scanners[m] = NULL;}EXPORT_SYMBOL(ieee80211_scanner_unregister_all);static voidchange_channel(struct ieee80211com *ic,	struct ieee80211_channel *chan){	ic->ic_curchan = chan;	ic->ic_set_channel(ic);}static charchannel_type(const struct ieee80211_channel *c){	if (IEEE80211_IS_CHAN_ST(c))		return 'S';	if (IEEE80211_IS_CHAN_108A(c))		return 'T';	if (IEEE80211_IS_CHAN_108G(c))		return 'G';	if (IEEE80211_IS_CHAN_A(c))		return 'a';	if (IEEE80211_IS_CHAN_ANYG(c))		return 'g';	if (IEEE80211_IS_CHAN_B(c))		return 'b';	return 'f';}voidieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss){	struct ieee80211com *ic = ss->ss_vap->iv_ic;	const char *sep;	int i;	sep = "";	for (i = ss->ss_next; i < ss->ss_last; i++) {		const struct ieee80211_channel *c = ss->ss_chans[i];		printf("%s%u%c", sep, ieee80211_chan2ieee(ic, c),			channel_type(c));		sep = ", ";	}}EXPORT_SYMBOL(ieee80211_scan_dump_channels);/* * Enable station power save mode and start/restart the scanning thread. */static voidscan_restart_pwrsav(unsigned long arg){	struct scan_state *ss = (struct scan_state *) arg;	struct ieee80211vap *vap = ss->base.ss_vap;	struct ieee80211com *ic = vap->iv_ic;	int delay;	ieee80211_sta_pwrsave(vap, 1);	/*	 * Use an initial 1ms delay to ensure the null	 * data frame has a chance to go out.	 * XXX 1ms is a lot, better to trigger scan	 * on tx complete.	 */	delay = msecs_to_jiffies(1);	if (delay < 1)		delay = 1;	ic->ic_scan_start(ic);			/* notify driver */	ss->ss_scanend = jiffies + delay + ss->ss_duration;	ss->ss_iflags |= ISCAN_START;	mod_timer(&ss->ss_scan_timer, jiffies + delay);}/* * Start/restart scanning.  If we're operating in station mode * and associated notify the ap we're going into power save mode * and schedule a callback to initiate the work (where there's a * better context for doing the work).  Otherwise, start the scan * directly. */static intscan_restart(struct scan_state *ss, u_int duration){	struct ieee80211vap *vap = ss->base.ss_vap;	struct ieee80211com *ic = vap->iv_ic;	int defer = 0;	if (ss->base.ss_next == ss->base.ss_last) {		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,			"%s: no channels to scan\n", __func__);		return 0;	}	if (vap->iv_opmode == IEEE80211_M_STA &&	    vap->iv_state == IEEE80211_S_RUN) {		if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) {			/*			 * Initiate power save before going off-channel.			 * Note that we cannot do this directly because			 * of locking issues; instead we defer it to a			 * tasklet.			 */			ss->ss_duration = duration;			tasklet_schedule(&ss->ss_pwrsav);			defer = 1;		}	}	if (!defer) {		ic->ic_scan_start(ic);		/* notify driver */		ss->ss_scanend = jiffies + duration;		ss->ss_iflags |= ISCAN_START;		mod_timer(&ss->ss_scan_timer, jiffies);	}	return 1;}static voidcopy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss,	int nssid, const struct ieee80211_scan_ssid ssids[]){	if (nssid > IEEE80211_SCAN_MAX_SSID) {		/* XXX printf */		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,			"%s: too many ssid %d, ignoring all of them\n",			__func__, nssid);		return;	}	memcpy(ss->ss_ssid, ssids, nssid * sizeof(ssids[0]));	ss->ss_nssid = nssid;}/* * Start a scan unless one is already going. */intieee80211_start_scan(struct ieee80211vap *vap, int flags, u_int duration,	u_int nssid, const struct ieee80211_scan_ssid ssids[]){	struct ieee80211com *ic = vap->iv_ic;	const struct ieee80211_scanner *scan;	struct ieee80211_scan_state *ss = ic->ic_scan;	scan = ieee80211_scanner_get(vap->iv_opmode, 0);	if (scan == NULL) {		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,			"%s: no scanner support for mode %u\n",			__func__, vap->iv_opmode);		/* XXX stat */		return 0;	}	IEEE80211_LOCK_IRQ(ic);	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,			"%s: %s scan, duration %lu, desired mode %s, %s%s%s%s\n",			__func__,			flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive",		 	duration,			ieee80211_phymode_name[vap->iv_des_mode],			flags & IEEE80211_SCAN_FLUSH ? "flush" : "append",			flags & IEEE80211_SCAN_NOPICK ? ", nopick" : "",			flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : "",			flags & IEEE80211_SCAN_ONCE ? ", once" : "");		ss->ss_vap = vap;		if (ss->ss_ops != scan) {			/* switch scanners; detach old, attach new */			if (ss->ss_ops != NULL)				ss->ss_ops->scan_detach(ss);			if (!scan->scan_attach(ss)) {				/* XXX attach failure */				/* XXX stat+msg */				ss->ss_ops = NULL;			} else				ss->ss_ops = scan;		}		if (ss->ss_ops != NULL) {			if ((flags & IEEE80211_SCAN_NOSSID) == 0)				copy_ssid(vap, ss, nssid, ssids);			/* NB: top 4 bits for internal use */			ss->ss_flags = flags & 0xfff;			if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)				vap->iv_stats.is_scan_active++;			else				vap->iv_stats.is_scan_passive++;			if (flags & IEEE80211_SCAN_FLUSH)				ss->ss_ops->scan_flush(ss);			/* NB: flush frames rx'd before 1st channel change */			SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;			ss->ss_ops->scan_start(ss, vap);			if (scan_restart(SCAN_PRIVATE(ss), duration))				ic->ic_flags |= IEEE80211_F_SCAN;		}	} else {		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,			"%s: %s scan already in progress\n", __func__,			ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive");	}	IEEE80211_UNLOCK_IRQ(ic);	/* NB: racey, does it matter? */	return (ic->ic_flags & IEEE80211_F_SCAN);}EXPORT_SYMBOL(ieee80211_start_scan);/* * Check the scan cache for an ap/channel to use; if that * fails then kick off a new scan. */intieee80211_check_scan(struct ieee80211vap *vap, int flags, u_int duration,	u_int nssid, const struct ieee80211_scan_ssid ssids[],	int (*action)(struct ieee80211vap *, const struct ieee80211_scan_entry *)){	struct ieee80211com *ic = vap->iv_ic;	struct ieee80211_scan_state *ss = ic->ic_scan;	int checkscanlist = 0;	/*	 * Check if there's a list of scan candidates already.	 * XXX want more than the ap we're currently associated with	 */	IEEE80211_LOCK_IRQ(ic);	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,		"%s: %s scan, duration %lu, desired mode %s, %s%s%s%s\n",		__func__,		flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive",		duration,		ieee80211_phymode_name[vap->iv_des_mode],		flags & IEEE80211_SCAN_FLUSH ? "flush" : "append",		flags & IEEE80211_SCAN_NOPICK ? ", nopick" : "",		flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : "",		flags & IEEE80211_SCAN_ONCE ? ", once" : "",		flags & IEEE80211_SCAN_USECACHE ? ", usecache" : "");	if (ss->ss_ops != NULL) {		/* XXX verify ss_ops matches vap->iv_opmode */		if ((flags & IEEE80211_SCAN_NOSSID) == 0) {			/*			 * Update the ssid list and mark flags so if			 * we call start_scan it doesn't duplicate work.			 */			copy_ssid(vap, ss, nssid, ssids);			flags |= IEEE80211_SCAN_NOSSID;		}		if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&		     time_before(jiffies, ic->ic_lastscan + vap->iv_scanvalid)) {			/*			 * We're not currently scanning and the cache is			 * deemed hot enough to consult.  Lock out others			 * by marking IEEE80211_F_SCAN while we decide if			 * something is already in the scan cache we can			 * use.  Also discard any frames that might come			 * in while temporarily marked as scanning.			 */			SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;			ic->ic_flags |= IEEE80211_F_SCAN;			checkscanlist = 1;		}	}	IEEE80211_UNLOCK_IRQ(ic);	if (checkscanlist) {		/*		 * ss must be filled out so scan may be restarted "outside"		 * of the current callstack.		 */		ss->ss_flags = flags;		ss->ss_duration = duration;		if (ss->ss_ops->scan_end(ss, ss->ss_vap, action, flags & IEEE80211_SCAN_KEEPMODE)) {			/* found an ap, just clear the flag */			ic->ic_flags &= ~IEEE80211_F_SCAN;			return 1;		}		/* no ap, clear the flag before starting a scan */

⌨️ 快捷键说明

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