📄 ieee80211_scan_sta.c
字号:
* Scan cache contents is too old; check about updating it. */ if (curRate < roamRate || curRssi < roamRssi) { /* * Thresholds exceeded, force a scan now so we * have current state to make a decision with. */ ieee80211_bg_scan(vap); } else if (time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle)) { /* * We're not in need of a new ap, but idle; * kick off a bg scan to replenish the cache. */ ieee80211_bg_scan(vap); } } else { /* * Scan cache contents are warm enough to use; * check if a new ap should be used and switch. * XXX deauth current ap */ if (curRate < roamRate || curRssi < roamRssi) { se->base.se_rssi = curRssi; selbs = select_bss(ss, vap); if (selbs != NULL && selbs != se) ieee80211_sta_join(vap, &selbs->base); } }}/* * Age entries in the scan cache. * XXX also do roaming since it's convenient */static voidsta_age(struct ieee80211_scan_state *ss){ struct ieee80211vap *vap = ss->ss_vap; struct sta_table *st = ss->ss_priv; struct sta_entry *se, *next; spin_lock(&st->st_lock); TAILQ_FOREACH_SAFE(se, &st->st_entry, se_list, next) { if (se->se_notseen > STA_PURGE_SCANS) { TAILQ_REMOVE(&st->st_entry, se, se_list); LIST_REMOVE(se, se_hash); FREE(se, M_80211_SCAN); } } spin_unlock(&st->st_lock); /* * If rate control is enabled check periodically to see if * we should roam from our current connection to one that * might be better. This only applies when we're operating * in sta mode and automatic roaming is set. * XXX defer if busy * XXX repeater station */ KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode %u", vap->iv_opmode)); /* XXX turn this off until the ap release is cut */ if (0 && vap->iv_ic->ic_roaming == IEEE80211_ROAMING_AUTO && vap->iv_state >= IEEE80211_S_RUN) /* XXX vap is implicit */ sta_roam_check(ss, vap);}/* * Iterate over the entries in the scan cache, invoking * the callback function on each one. */static voidsta_iterate(struct ieee80211_scan_state *ss, ieee80211_scan_iter_func *f, void *arg){ struct sta_table *st = ss->ss_priv; struct sta_entry *se; u_int gen; spin_lock(&st->st_scanlock); gen = st->st_scangen++;restart: spin_lock(&st->st_lock); TAILQ_FOREACH(se, &st->st_entry, se_list) { if (se->se_scangen != gen) { se->se_scangen = gen; /* update public state */ se->base.se_age = jiffies - se->se_lastupdate; spin_unlock(&st->st_lock); (*f)(arg, &se->base); goto restart; } } spin_unlock(&st->st_lock); spin_unlock(&st->st_scanlock);}static voidsta_assoc_fail(struct ieee80211_scan_state *ss, const u_int8_t macaddr[IEEE80211_ADDR_LEN], int reason){ struct sta_table *st = ss->ss_priv; struct sta_entry *se; se = sta_lookup(st, macaddr); if (se != NULL) { se->se_fails++; se->se_lastfail = jiffies; IEEE80211_NOTE_MAC(ss->ss_vap, IEEE80211_MSG_SCAN, macaddr, "%s: reason %u fails %u", __func__, reason, se->se_fails); }}static voidsta_assoc_success(struct ieee80211_scan_state *ss, const u_int8_t macaddr[IEEE80211_ADDR_LEN]){ struct sta_table *st = ss->ss_priv; struct sta_entry *se; se = sta_lookup(st, macaddr); if (se != NULL) {#if 0 se->se_fails = 0; IEEE80211_NOTE_MAC(ss->ss_vap, IEEE80211_MSG_SCAN, macaddr, "%s: fails %u", __func__, se->se_fails);#endif se->se_lastassoc = jiffies; }}static const struct ieee80211_scanner sta_default = { .scan_name = "default", .scan_attach = sta_attach, .scan_detach = sta_detach, .scan_start = sta_start, .scan_restart = sta_restart, .scan_cancel = sta_cancel, .scan_end = sta_pick_bss, .scan_flush = sta_flush, .scan_add = sta_add, .scan_age = sta_age, .scan_iterate = sta_iterate, .scan_assoc_fail = sta_assoc_fail, .scan_assoc_success = sta_assoc_success, .scan_default = ieee80211_sta_join,};/* * Start an adhoc-mode scan by populating the channel list. */static intadhoc_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; 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 */ 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); } ss->ss_next = 0; /* XXX tunables */ ss->ss_mindwell = msecs_to_jiffies(200); /* 200ms */ 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}/* * Select a channel to start an adhoc network on. * The channel list was populated with appropriate * channels so select one that looks least occupied. * XXX need regulatory domain constraints */static struct ieee80211_channel *adhoc_pick_channel(struct ieee80211_scan_state *ss){ struct sta_table *st = ss->ss_priv; struct sta_entry *se; struct ieee80211_channel *c, *bestchan; int i, bestrssi, maxrssi; bestchan = NULL; bestrssi = -1; spin_lock(&st->st_lock); for (i = 0; i < ss->ss_last; i++) { c = ss->ss_chans[i]; maxrssi = 0; TAILQ_FOREACH(se, &st->st_entry, se_list) { if (se->base.se_chan != c) continue; if (se->base.se_rssi > maxrssi) maxrssi = se->base.se_rssi; } if (bestchan == NULL || maxrssi < bestrssi) bestchan = c; } spin_unlock(&st->st_lock); return bestchan;}/* * Pick an ibss network to join or find a channel * to use to start an ibss network. */static intadhoc_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 *selbs; struct ieee80211_channel *chan; KASSERT(vap->iv_opmode == IEEE80211_M_IBSS || vap->iv_opmode == IEEE80211_M_AHDEMO, ("wrong opmode %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; } st->st_action = ss->ss_ops->scan_default; if (action) st->st_action = action; /* * 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 || (selbs = select_bss(ss, vap)) == NULL ) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: no scan candidate\n", __func__); if (vap->iv_des_nssid) { /* * No existing adhoc network to join and we have * an ssid; start one up. If no channel was * specified, try to select a channel. */ if (vap->iv_des_chan == IEEE80211_CHAN_ANYC) chan = adhoc_pick_channel(ss); else chan = vap->iv_des_chan; if (chan != NULL) { struct ieee80211_scan_entry se; memset(&se, 0, sizeof(se)); se.se_chan = chan; st->st_selbss = se; /* defer action */ IEEE80211_SCHEDULE_TQUEUE(&st->st_actiontq); return 1; } } /* * 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 */ } /* * Must defer action to avoid possible recursive call through 80211 * state machine, which would result in recursive locking. */ st->st_selbss = selbs->base; IEEE80211_SCHEDULE_TQUEUE(&st->st_actiontq); return 1; /* terminate scan */}/* * Age entries in the scan cache. */static voidadhoc_age(struct ieee80211_scan_state *ss){ struct sta_table *st = ss->ss_priv; struct sta_entry *se, *next; spin_lock(&st->st_lock); TAILQ_FOREACH_SAFE(se, &st->st_entry, se_list, next) { if (se->se_notseen > STA_PURGE_SCANS) { TAILQ_REMOVE(&st->st_entry, se, se_list); LIST_REMOVE(se, se_hash); FREE(se, M_80211_SCAN); } } spin_unlock(&st->st_lock);}/* * Default action to execute when a scan entry is found for adhoc * mode. Return 1 on success, 0 on failure */static intadhoc_default_action(struct ieee80211vap *vap, const struct ieee80211_scan_entry *se){ u_int8_t zeroMacAddr[IEEE80211_ADDR_LEN]; memset(&zeroMacAddr, 0, IEEE80211_ADDR_LEN); if (IEEE80211_ADDR_EQ(se->se_bssid, &zeroMacAddr[0])) { ieee80211_create_ibss(vap, se->se_chan); return 1; } else return ieee80211_sta_join(vap,se);}static const struct ieee80211_scanner adhoc_default = { .scan_name = "default", .scan_attach = sta_attach, .scan_detach = sta_detach, .scan_start = adhoc_start, .scan_restart = sta_restart, .scan_cancel = sta_cancel, .scan_end = adhoc_pick_bss, .scan_flush = sta_flush, .scan_add = sta_add, .scan_age = adhoc_age, .scan_iterate = sta_iterate, .scan_assoc_fail = sta_assoc_fail, .scan_assoc_success = sta_assoc_success, .scan_default = adhoc_default_action,};static voidaction_tasklet(IEEE80211_TQUEUE_ARG data){ struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *)data; struct sta_table *st = (struct sta_table *)ss->ss_priv; struct ieee80211vap *vap = ss->ss_vap; struct ieee80211_channel *chan; if ((*ss->ss_ops->scan_default)(vap, &st->st_selbss)) return; switch (vap->iv_opmode) { case IEEE80211_M_STA: sta_dec_fails(st); st->st_newscan = 1; break; default: /* ADHOC */ if (vap->iv_des_nssid) { /* * No existing adhoc network to join and we have * an ssid; start one up. If no channel was * specified, try to select a channel. */ if (vap->iv_des_chan == IEEE80211_CHAN_ANYC) chan = adhoc_pick_channel(ss); else chan = vap->iv_des_chan; if (chan != NULL) { struct ieee80211_scan_entry se; memset(&se, 0, sizeof(se)); se.se_chan = chan; if ((*ss->ss_ops->scan_default)(vap, &se)) return; } } /* * 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; break; } /* * restart scan */ /* no ap, clear the flag for a new scan */ vap->iv_ic->ic_flags &= ~IEEE80211_F_SCAN; if ((ss->ss_flags & IEEE80211_SCAN_USECACHE) == 0) ieee80211_start_scan(vap, ss->ss_flags, ss->ss_duration, ss->ss_nssid, ss->ss_ssid);}/* * Module glue. */MODULE_AUTHOR("Errno Consulting, Sam Leffler");MODULE_DESCRIPTION("802.11 wireless support: default station scanner");#ifdef MODULE_LICENSEMODULE_LICENSE("Dual BSD/GPL");#endifstatic int __initinit_scanner_sta(void){ ieee80211_scanner_register(IEEE80211_M_STA, &sta_default); ieee80211_scanner_register(IEEE80211_M_IBSS, &adhoc_default); ieee80211_scanner_register(IEEE80211_M_AHDEMO, &adhoc_default); return 0;}module_init(init_scanner_sta);static void __exitexit_scanner_sta(void){ ieee80211_scanner_unregister_all(&sta_default); ieee80211_scanner_unregister_all(&adhoc_default);}module_exit(exit_scanner_sta);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -