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

📄 ieee80211_scan_sta.c

📁 Linux下wifi实现
💻 C
📖 第 1 页 / 共 3 页
字号:
		if ((vap->iv_flags & IEEE80211_F_XR) &&		    (mode == IEEE80211_MODE_TURBO_A ||		     mode == IEEE80211_MODE_TURBO_G))			continue;		/*		 * Add the list of the channels; any that are not		 * in the master channel list will be discarded.		 */		add_channels(ic, ss, mode, scan->list, scan->count);	}	/*	 * Add the channels from the ic (from HAL) that are not present	 * in the staScanTable.	 */	for (i = 0; i < ic->ic_nchans; i++) {		c = &ic->ic_channels[i];		/*		 * scan dynamic turbo channels in normal mode.		 */		if (IEEE80211_IS_CHAN_DTURBO(c))			continue;		mode = ieee80211_chan2mode(c);		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) 				continue;					} 		if (!checktable(staScanTable, c))			ss->ss_chans[ss->ss_last++] = c;	}	ss->ss_next = 0;	/* XXX tunables */	ss->ss_mindwell = msecs_to_jiffies(20);		/* 20ms */	ss->ss_maxdwell = msecs_to_jiffies(200);	/* 200ms */#ifdef IEEE80211_DEBUG	if (ieee80211_msg_scan(vap)) {		printf("%s: scan set ", vap->iv_dev->name);		ieee80211_scan_dump_channels(ss);		printf(" dwell min %ld max %ld\n",			ss->ss_mindwell, ss->ss_maxdwell);	}#endif /* IEEE80211_DEBUG */	st->st_newscan = 1;	return 0;#undef N}/* * Restart a bg scan. */static intsta_restart(struct ieee80211_scan_state *ss, struct ieee80211vap *vap){	struct sta_table *st = ss->ss_priv;	st->st_newscan = 1;	return 0;}/* * Cancel an ongoing scan. */static intsta_cancel(struct ieee80211_scan_state *ss, struct ieee80211vap *vap){	struct sta_table *st = ss->ss_priv;	IEEE80211_CANCEL_TQUEUE(&st->st_actiontq);	return 0;}static u_int8_tmaxrate(const struct ieee80211_scan_entry *se){	u_int8_t max, r;	int i;	max = 0;	for (i = 0; i < se->se_rates[1]; i++) {		r = se->se_rates[2+i] & IEEE80211_RATE_VAL;		if (r > max)			max = r;	}	for (i = 0; i < se->se_xrates[1]; i++) {		r = se->se_xrates[2+i] & IEEE80211_RATE_VAL;		if (r > max)			max = r;	}	return max;}/* * Compare the capabilities of two entries and decide which is * more desirable (return >0 if a is considered better).  Note * that we assume compatibility/usability has already been checked * so we don't need to (e.g. validate whether privacy is supported). * Used to select the best scan candidate for association in a BSS. */static intsta_compare(const struct sta_entry *a, const struct sta_entry *b){	u_int8_t maxa, maxb;	int weight;	/* privacy support preferred */	if ((a->base.se_capinfo & IEEE80211_CAPINFO_PRIVACY) &&	    (b->base.se_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)		return 1;	if ((a->base.se_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0 &&	    (b->base.se_capinfo & IEEE80211_CAPINFO_PRIVACY))		return -1;	/* compare count of previous failures */	weight = b->se_fails - a->se_fails;	if (abs(weight) > 1)		return weight;	if (abs(b->base.se_rssi - a->base.se_rssi) < 5) {		/* best/max rate preferred if signal level close enough XXX */		maxa = maxrate(&a->base);		maxb = maxrate(&b->base);		if (maxa != maxb)			return maxa - maxb;		/* XXX use freq for channel preference */		/* for now just prefer 5Ghz band to all other bands */		if (IEEE80211_IS_CHAN_5GHZ(a->base.se_chan) &&		   !IEEE80211_IS_CHAN_5GHZ(b->base.se_chan))			return 1;		if (!IEEE80211_IS_CHAN_5GHZ(a->base.se_chan) &&		    IEEE80211_IS_CHAN_5GHZ(b->base.se_chan))			return -1;	}	/* all things being equal, use signal level */	return a->base.se_rssi - b->base.se_rssi;}/* * Check rate set suitability and return the best supported rate. */static intcheck_rate(struct ieee80211vap *vap, const struct ieee80211_scan_entry *se){#define	RV(v)	((v) & IEEE80211_RATE_VAL)	struct ieee80211com *ic = vap->iv_ic;	const struct ieee80211_rateset *srs;	int i, j, nrs, r, okrate, badrate, fixedrate;	const u_int8_t *rs;	okrate = badrate = fixedrate = 0;		if (IEEE80211_IS_CHAN_HALF(se->se_chan))		srs = &ic->ic_sup_half_rates;	else if (IEEE80211_IS_CHAN_QUARTER(se->se_chan))		srs = &ic->ic_sup_quarter_rates;	else		srs = &ic->ic_sup_rates[ieee80211_chan2mode(se->se_chan)];	nrs = se->se_rates[1];	rs = se->se_rates + 2;	fixedrate = IEEE80211_FIXED_RATE_NONE;again:	for (i = 0; i < nrs; i++) {		r = RV(rs[i]);		badrate = r;		/*		 * Check any fixed rate is included. 		 */		if (r == vap->iv_fixed_rate)			fixedrate = r;		/*		 * Check against our supported rates.		 */		for (j = 0; j < srs->rs_nrates; j++)			if (r == RV(srs->rs_rates[j])) {				if (r > okrate)		/* NB: track max */					okrate = r;				break;			}	}	if (rs == se->se_rates+2) {		/* scan xrates too; sort of an algol68-style for loop */		nrs = se->se_xrates[1];		rs = se->se_xrates + 2;		goto again;	}	if (okrate == 0 || vap->iv_fixed_rate != fixedrate)		return badrate | IEEE80211_RATE_BASIC;	else		return RV(okrate);#undef RV}static intmatch_ssid(const u_int8_t *ie,	int nssid, const struct ieee80211_scan_ssid ssids[]){	int i;	for (i = 0; i < nssid; i++) {		if (ie[1] == ssids[i].len &&		     memcmp(ie + 2, ssids[i].ssid, ie[1]) == 0)			return 1;	}	return 0;}/* * Test a scan candidate for suitability/compatibility. */static intmatch_bss(struct ieee80211vap *vap,	const struct ieee80211_scan_state *ss, const struct sta_entry *se0){	struct ieee80211com *ic = vap->iv_ic;	const struct ieee80211_scan_entry *se = &se0->base;        u_int8_t rate;        int fail;	fail = 0;	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, se->se_chan)))		fail |= 0x01;	/*	 * NB: normally the desired mode is used to construct	 * the channel list, but it's possible for the scan	 * cache to include entries for stations outside this	 * list so we check the desired mode here to weed them	 * out.	 */	if (vap->iv_des_mode != IEEE80211_MODE_AUTO &&	    (se->se_chan->ic_flags & IEEE80211_CHAN_ALLTURBO) !=	    chanflags[vap->iv_des_mode])		fail |= 0x01;	if (vap->iv_opmode == IEEE80211_M_IBSS) {		if ((se->se_capinfo & IEEE80211_CAPINFO_IBSS) == 0)			fail |= 0x02;	} else {		if ((se->se_capinfo & IEEE80211_CAPINFO_ESS) == 0)			fail |= 0x02;	}	if (vap->iv_flags & IEEE80211_F_PRIVACY) {		if ((se->se_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)			fail |= 0x04;	} else {		/* XXX does this mean privacy is supported or required? */		if (se->se_capinfo & IEEE80211_CAPINFO_PRIVACY)			fail |= 0x04;	}	rate = check_rate(vap, se);	if (rate & IEEE80211_RATE_BASIC)		fail |= 0x08;	if (ss->ss_nssid != 0 &&	    !match_ssid(se->se_ssid, ss->ss_nssid, ss->ss_ssid))		fail |= 0x10;	if ((vap->iv_flags & IEEE80211_F_DESBSSID) &&	    !IEEE80211_ADDR_EQ(vap->iv_des_bssid, se->se_bssid))		fail |= 0x20;	if (se0->se_fails >= STA_FAILS_MAX)		fail |= 0x40;	if (se0->se_notseen >= STA_PURGE_SCANS)		fail |= 0x80;	if (se->se_rssi < STA_RSSI_MIN)		fail |= 0x100;#ifdef IEEE80211_DEBUG	if (ieee80211_msg(vap, IEEE80211_MSG_SCAN | IEEE80211_MSG_ROAM)) {		printf(" %03x", fail);		printf(" %c %s",			fail & 0x40 ? '=' : fail & 0x80 ? '^' : fail ? '-' : '+',			ether_sprintf(se->se_macaddr));		printf(" %s%c", ether_sprintf(se->se_bssid),			fail & 0x20 ? '!' : ' ');		printf(" %3d%c", ieee80211_chan2ieee(ic, se->se_chan),			fail & 0x01 ? '!' : ' ');		printf(" %+4d%c", se->se_rssi, fail & 0x100 ? '!' : ' ');		printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,			fail & 0x08 ? '!' : ' ');		printf(" %4s%c",			(se->se_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :			(se->se_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : "????",			fail & 0x02 ? '!' : ' ');		printf(" %3s%c ",			(se->se_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" : "no",			fail & 0x04 ? '!' : ' ');		ieee80211_print_essid(se->se_ssid + 2, se->se_ssid[1]);		printf("%s\n", fail & 0x10 ? "!" : "");	}#endif	return fail;}static voidsta_update_notseen(struct sta_table *st){	struct sta_entry *se;	unsigned long stlockflags;	spin_lock_irqsave(&st->st_lock, stlockflags);	TAILQ_FOREACH(se, &st->st_entry, se_list) {		/*		 * If seen then reset and don't bump the count;		 * otherwise bump the ``not seen'' count.  Note		 * that this ensures that stations for which we		 * see frames while not scanning but not during		 * this scan will not be penalized.		 */		if (se->se_seen)			se->se_seen = 0;		else			se->se_notseen++;	}	spin_unlock_irqrestore(&st->st_lock, stlockflags);}static voidsta_dec_fails(struct sta_table *st){	struct sta_entry *se;	unsigned long stlockflags;	spin_lock_irqsave(&st->st_lock, stlockflags);	TAILQ_FOREACH(se, &st->st_entry, se_list)		if (se->se_fails)			se->se_fails--;	spin_unlock_irqrestore(&st->st_lock, stlockflags);}static struct sta_entry *select_bss(struct ieee80211_scan_state *ss, struct ieee80211vap *vap){	struct sta_table *st = ss->ss_priv;	struct sta_entry *se, *selbs = NULL;	unsigned long stlockflags;	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN | IEEE80211_MSG_ROAM, " %s\n",		"macaddr          bssid         chan  rssi  rate flag  wep  essid");	spin_lock_irqsave(&st->st_lock, stlockflags);	TAILQ_FOREACH(se, &st->st_entry, se_list) {		if (match_bss(vap, ss, se) == 0) {			if (selbs == NULL)				selbs = se;			else if (sta_compare(se, selbs) > 0)				selbs = se;		}	}	spin_unlock_irqrestore(&st->st_lock, stlockflags);	return selbs;}/* * Pick an ap or ibss network to join or find a channel * to use to start an ibss network. */static intsta_pick_bss(struct ieee80211_scan_state *ss, struct ieee80211vap *vap,	int (*action)(struct ieee80211vap *, const struct ieee80211_scan_entry *),	u_int32_t flags){	struct sta_table *st = ss->ss_priv;	struct sta_entry *selbss;	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s Checking scan results\n",		__func__);	KASSERT(vap->iv_opmode == IEEE80211_M_STA,		("wrong mode %u", vap->iv_opmode));	if (st->st_newscan) {		sta_update_notseen(st);		st->st_newscan = 0;	}	if (ss->ss_flags & IEEE80211_SCAN_NOPICK) {		/*		 * Manual/background scan, don't select+join the		 * bss, just return.  The scanning framework will		 * handle notification that this has completed.		 */		ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;		return 1;	}	/*	 * Automatic sequencing; look for a candidate and	 * if found join the network.	 */	/* NB: unlocked read should be ok */	if (TAILQ_FIRST(&st->st_entry) == NULL) {		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,			"%s: no scan candidate\n", __func__);notfound:		/*		 * If nothing suitable was found 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.		 */		sta_dec_fails(st);		st->st_newscan = 1;		return 0;			/* restart scan */	}	st->st_action = ss->ss_ops->scan_default;	if (action)		st->st_action = action;	if ((selbss = select_bss(ss, vap)) == NULL ) {		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,			"%s: select_bss failed\n", __func__);		goto notfound;	}	st->st_selbss = selbss->base;	/* 	 * Must defer action to avoid possible recursive call through 80211	 * state machine, which would result in recursive locking.	 */	IEEE80211_SCHEDULE_TQUEUE(&st->st_actiontq);	return 1;				/* terminate scan */}/* * Lookup an entry in the scan cache.  We assume we're * called from the bottom half or such that we don't need * to block the bottom half so that it's safe to return * a reference to an entry w/o holding the lock on the table. */static struct sta_entry *sta_lookup(struct sta_table *st, const u_int8_t macaddr[IEEE80211_ADDR_LEN]){	struct sta_entry *se;	int 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))			break;	spin_unlock(&st->st_lock);	return se;		/* NB: unlocked */}static voidsta_roam_check(struct ieee80211_scan_state *ss, struct ieee80211vap *vap){	struct ieee80211_node *ni = vap->iv_bss;	struct ieee80211com *ic = vap->iv_ic;	struct sta_table *st = ss->ss_priv;	struct sta_entry *se, *selbs;	u_int8_t roamRate, curRate;	int8_t roamRssi, curRssi;	se = sta_lookup(st, ni->ni_macaddr);	if (se == NULL) {		/* XXX something is wrong */		return;	}	/* XXX do we need 11g too? */	if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) {		roamRate = vap->iv_roam.rate11b;		roamRssi = vap->iv_roam.rssi11b;	} else if (IEEE80211_IS_CHAN_B(ic->ic_bsschan)) {		roamRate = vap->iv_roam.rate11bOnly;		roamRssi = vap->iv_roam.rssi11bOnly;	} else {		roamRate = vap->iv_roam.rate11a;		roamRssi = vap->iv_roam.rssi11a;	}	/* NB: the most up to date rssi is in the node, not the scan cache */	curRssi = ic->ic_node_getrssi(ni);	if (vap->iv_fixed_rate == IEEE80211_FIXED_RATE_NONE) {		curRate = ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL;		IEEE80211_DPRINTF(vap, IEEE80211_MSG_ROAM,			"%s: currssi %d currate %u roamrssi %d roamrate %u\n",			__func__, curRssi, curRate, roamRssi, roamRate);	} else {		curRate = roamRate;		/* NB: ensure compare below fails */		IEEE80211_DPRINTF(vap, IEEE80211_MSG_ROAM,			"%s: currssi %d roamrssi %d\n",			__func__, curRssi, roamRssi);	}	if ((vap->iv_flags & IEEE80211_F_BGSCAN) &&	    time_after(jiffies, ic->ic_lastscan + vap->iv_scanvalid)) {		/*

⌨️ 快捷键说明

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