📄 ieee80211_scan_ap.c.svn-base
字号:
struct ieee80211_channel *a = ((struct channel *)_a)->chan; struct ieee80211_channel *b = ((struct channel *)_b)->chan; struct pc_params *params = ((struct channel *)_a)->params; struct ieee80211com *ic = params->vap->iv_ic; int res;#define EVALUATE_CRITERION(name, ...) do { \ if ((res = pc_cmp_##name(__VA_ARGS__)) != 0) \ return res; \} while (0) EVALUATE_CRITERION(radar, a, b); EVALUATE_CRITERION(keepmode, params, a, b); EVALUATE_CRITERION(sc, ic, a, b); /* XXX: rssi useless? pick_channel evaluates it anyway */ EVALUATE_CRITERION(rssi, params->ss->ss_priv, a, b); EVALUATE_CRITERION(samechan, ic, a, b); EVALUATE_CRITERION(orig, (struct channel *)_a, (struct channel *)_b);#undef EVALUATE_CRITERION return res;}/* This function must be invoked with locks acquired */static voidpc_swap(void *a, void *b, int n){ struct ieee80211_channel *t = ((struct channel *)a)->chan; int i; ((struct channel *)a)->chan = ((struct channel *)b)->chan; ((struct channel *)b)->chan = t; i = ((struct channel *)a)->orig; ((struct channel *)a)->orig = ((struct channel *)b)->orig; ((struct channel *)b)->orig = i; /* (struct channel *)x->params doesn't have to be swapped, because it * is the same across all channels */}/* Pick a quiet channel to use for ap operation. * Must be invoked while we hold the locks. */static struct ieee80211_channel *pick_channel(struct ieee80211_scan_state *ss, struct ieee80211vap *vap, u_int32_t flags){ struct ieee80211com *ic = vap->iv_ic; unsigned int i, best_rssi; int ss_last = ss->ss_last; struct ieee80211_channel *best; struct ap_state *as = ss->ss_priv; struct channel chans[ss_last]; /* actually ss_last-1 is required */ struct channel *c = NULL; struct pc_params params = { vap, ss, flags }; int benefit = 0; int sta_assoc = 0; for (i = 0; i < ss_last; i++) { chans[i].chan = ss->ss_chans[i]; chans[i].orig = i; chans[i].params = ¶ms; } sort(chans, ss_last, sizeof(*chans), pc_cmp, pc_swap);#ifdef IEEE80211_DEBUG for (i = 0; i < ss_last; i++) { int chan = ieee80211_chan2ieee(ic, chans[i].chan); IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: channel %u, " "rssi %d, radar %d, cn %d, km %d\n", __func__, chan, as->as_maxrssi[chan], IEEE80211_IS_CHAN_RADAR(chans[i].chan), ic->ic_chan_nodes[chans[i].chan->ic_ieee], !!IEEE80211_ARE_CHANS_SAME_MODE(chans[i].chan, ic->ic_bsschan)); }#endif /* IEEE80211_DEBUG */ best = NULL; best_rssi = 0xff; /* If signal is bigger than 0xff, we'd be melting. */ for (i = 0; i < ss_last; i++) { c = &chans[i]; benefit = best_rssi - as->as_maxrssi[c->chan->ic_ieee]; sta_assoc = ic->ic_sta_assoc; /* Don't switch... */ if (benefit <= 0) continue; /* Verify channel is not marked for non-occupancy */ if (IEEE80211_IS_CHAN_RADAR(c->chan)) continue; /* Do not select 802.11a ST if mode is specified and is not * 802.11a ST */ if (as->as_required_mode && IEEE80211_IS_CHAN_STURBO(c->chan) && (as->as_vap_desired_mode != IEEE80211_MODE_TURBO_STATIC_A)) continue; /* Verify mode matches any fixed mode specified */ if ((c->chan->ic_flags & as->as_required_mode) != as->as_required_mode) continue; if ((ic->ic_bsschan != NULL) && (ic->ic_bsschan != IEEE80211_CHAN_ANYC)) { /* Make sure the channels are the same mode */ if ((flags & IEEE80211_SCAN_KEEPMODE) && !IEEE80211_ARE_CHANS_SAME_MODE(c->chan, ic->ic_bsschan)) /* break the loop as the subsequent chans won't be * better */ break; } if (sta_assoc != 0) { int sl = ic->ic_cn_total - ic->ic_chan_nodes[c->chan->ic_ieee]; /* count */ if (ic->ic_sc_algorithm == IEEE80211_SC_LOOSE) { int sl_max = ic->ic_sc_sldg * benefit; sl = 1000 * sl / sta_assoc; /* permil */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: chan %d, dB gained: %d, " "STAs lost: %d permil (max %d)\n", __func__, c->chan->ic_ieee, benefit, sl, sl_max); if (sl > sl_max) continue; } else if (((ic->ic_sc_algorithm == IEEE80211_SC_TIGHT) || (ic->ic_sc_algorithm == IEEE80211_SC_STRICT)) && (sl > 0)) { /* Break the loop as the subsequent chans * won't be better. */ break; } } best = c->chan; best_rssi = as->as_maxrssi[best->ic_ieee]; } if (best != NULL) { i = best->ic_ieee; IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: best: channel %u rssi %d\n", __func__, i, as->as_maxrssi[i]); } return best;}static intap_end(struct ieee80211_scan_state *ss, struct ieee80211vap *vap, int (*action)(struct ieee80211vap *, const struct ieee80211_scan_entry *), u_int32_t flags){ struct ap_state *as = ss->ss_priv; struct ieee80211_channel *bestchan = NULL; struct ieee80211com *ic = NULL; int res = 1; SCAN_AP_LOCK_IRQ(as); KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP, ("wrong opmode %u", vap->iv_opmode)); ic = vap->iv_ic; bestchan = pick_channel(ss, vap, flags); if (bestchan == NULL) { if (ss->ss_last > 0) { /* no suitable channel, should not happen */ printk(KERN_ERR "%s: %s: no suitable channel! " "(should not happen)\n", DEV_NAME(vap->iv_dev), __func__); } res = 1; /* Do NOT restart scan */ } else { struct ieee80211_scan_entry se; /* XXX: notify all VAPs? */ /* if this is a dynamic turbo frequency , start with normal * mode first */ if (IEEE80211_IS_CHAN_TURBO(bestchan) && !IEEE80211_IS_CHAN_STURBO(bestchan)) { if ((bestchan = ieee80211_find_channel(ic, bestchan->ic_freq, bestchan->ic_flags & ~IEEE80211_CHAN_TURBO)) == NULL) { /* should never happen ?? */ SCAN_AP_UNLOCK_IRQ_EARLY(as); return 0; } } memset(&se, 0, sizeof(se)); se.se_chan = bestchan; as->as_action = ss->ss_ops->scan_default; if (action) as->as_action = action; as->as_selbss = se; /* Must defer action to avoid possible recursive call through * 80211 state machine, which would result in recursive * locking. */ IEEE80211_SCHEDULE_TQUEUE(&as->as_actiontq); res = 1; } SCAN_AP_UNLOCK_IRQ(as); return res;}static voidap_age(struct ieee80211_scan_state *ss){ struct ap_state *as = ss->ss_priv; struct scan_entry *se, *next; SCAN_AP_LOCK_IRQ(as); TAILQ_FOREACH_SAFE(se, &as->as_entry, se_list, next) { if (se->se_notseen > AP_PURGE_SCANS) { TAILQ_REMOVE(&as->as_entry, se, se_list); LIST_REMOVE(se, se_hash); FREE(se, M_80211_SCAN); } } SCAN_AP_UNLOCK_IRQ(as);}static intap_iterate(struct ieee80211_scan_state *ss, ieee80211_scan_iter_func *f, void *arg){ struct ap_state *as = ss->ss_priv; struct scan_entry *se; u_int gen; int res = 0; SCAN_AP_GEN_LOCK(as); gen = as->as_scangen++;restart: SCAN_AP_LOCK_IRQ(as); TAILQ_FOREACH(se, &as->as_entry, se_list) { if (se->se_scangen != gen) { se->se_scangen = gen; /* update public state */ se->base.se_age = jiffies - se->se_lastupdate; SCAN_AP_UNLOCK_IRQ_EARLY(as); res = (*f)(arg, &se->base); /* We probably ran out of buffer space. */ if (res != 0) goto done; goto restart; } } SCAN_AP_UNLOCK_IRQ(as);done: SCAN_AP_GEN_UNLOCK(as); return res;}static voidap_assoc_success(struct ieee80211_scan_state *ss, const u_int8_t macaddr[IEEE80211_ADDR_LEN]){ /* should not be called */}static voidap_assoc_fail(struct ieee80211_scan_state *ss, const u_int8_t macaddr[IEEE80211_ADDR_LEN], int reason){ /* should not be called */}/* * Default action to execute when a scan entry is found for ap * mode. Return 1 on success, 0 on failure */static intap_default_action(struct ieee80211vap *vap, const struct ieee80211_scan_entry *se){ ieee80211_create_ibss(vap, se->se_chan); return 1;}static voidaction_tasklet(IEEE80211_TQUEUE_ARG data){ struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *)data; struct ap_state *as = (struct ap_state *)ss->ss_priv; struct ieee80211vap *vap = ss->ss_vap; SCAN_AP_LOCK_IRQ(as); if (as->as_newscan) { struct scan_entry *se; TAILQ_FOREACH(se, &as->as_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++; } as->as_newscan = 0; } SCAN_AP_UNLOCK_IRQ(as); (*ss->ss_ops->scan_default)(vap, &as->as_selbss);}/* * Module glue. */MODULE_AUTHOR("Errno Consulting, Sam Leffler");MODULE_DESCRIPTION("802.11 wireless support: default ap scanner");#ifdef MODULE_LICENSEMODULE_LICENSE("Dual BSD/GPL");#endifstatic const struct ieee80211_scanner ap_default = { .scan_name = "default", .scan_attach = ap_attach, .scan_detach = ap_detach, .scan_start = ap_start, .scan_restart = ap_restart, .scan_cancel = ap_cancel, .scan_end = ap_end, .scan_flush = ap_flush, .scan_add = ap_add, .scan_age = ap_age, .scan_iterate = ap_iterate, .scan_assoc_success = ap_assoc_success, .scan_assoc_fail = ap_assoc_fail, .scan_default = ap_default_action,};static int __initinit_scanner_ap(void){ ieee80211_scanner_register(IEEE80211_M_HOSTAP, &ap_default); return 0;}module_init(init_scanner_ap);static void __exitexit_scanner_ap(void){ ieee80211_scanner_unregister_all(&ap_default);}module_exit(exit_scanner_ap);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -