📄 ieee80211_scan_ap.c.svn-base
字号:
/* * Flush all per-scan state. */static intap_flush(struct ieee80211_scan_state *ss){ struct ap_state *as = ss->ss_priv; struct scan_entry *se, *next; SCAN_AP_LOCK_IRQ(as); memset(as->as_maxrssi, 0, sizeof(as->as_maxrssi)); TAILQ_FOREACH_SAFE(se, &as->as_entry, se_list, next) { TAILQ_REMOVE(&as->as_entry, se, se_list); LIST_REMOVE(se, se_hash); FREE(se, M_80211_SCAN); } ss->ss_last = 0; /* ensure no channel will be picked */ SCAN_AP_UNLOCK_IRQ(as); return 0;}/* This function must be invoked with locks acquired */static voidsaveie(u_int8_t **iep, const u_int8_t *ie){ if (ie == NULL) *iep = NULL; else ieee80211_saveie(iep, ie);}/* This function must be invoked with locks acquired */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;}/* * Start an ap scan by populating the channel list. */static intap_start(struct ieee80211_scan_state *ss, struct ieee80211vap *vap){ struct ap_state *as = ss->ss_priv; struct ieee80211com *ic = NULL; const struct scanlist *sl = NULL; struct ieee80211_channel *c = NULL; int i; unsigned int mode = 0; SCAN_AP_LOCK_IRQ(as); ic = vap->iv_ic; /* Determine mode flags to match, or leave zero for auto mode */ as->as_vap_desired_mode = vap->iv_des_mode; as->as_required_mode = 0; if (as->as_vap_desired_mode != IEEE80211_MODE_AUTO) { as->as_required_mode = chanflags[as->as_vap_desired_mode]; if ((vap->iv_ath_cap & IEEE80211_ATHC_TURBOP) && (as->as_required_mode != IEEE80211_CHAN_ST)) { /* Fixup for dynamic turbo flags */ if (as->as_vap_desired_mode == IEEE80211_MODE_11G) as->as_required_mode = IEEE80211_CHAN_108G; else as->as_required_mode = IEEE80211_CHAN_108A; } } 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 (sl = staScanTable; sl->list != NULL; sl++) { mode = sl->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 (as->as_vap_desired_mode && (as->as_vap_desired_mode != mode) && (as->as_vap_desired_mode == IEEE80211_MODE_11G) && (mode == IEEE80211_MODE_11B)) mode = IEEE80211_MODE_11G; /* If we are in "AUTO" mode, upgrade the mode to auto. * This lets add_channels upgrade an 11b channel to * 11g if available. */ if (!as->as_vap_desired_mode && (mode == IEEE80211_MODE_11B)) mode = IEEE80211_MODE_AUTO; /* Add the list of the channels; any that are not * in the master channel list will be discarded. */ add_channels(ic, ss, mode, sl->list, sl->count); } /* Add the channels from the ic (from HAL) that are not present * in the staScanTable, assuming they pass the sanity checks... */ for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; /* XR is not supported on turbo channels */ if (IEEE80211_IS_CHAN_TURBO(c) && vap->iv_flags & IEEE80211_F_XR) continue; /* Dynamic channels are scanned in base mode */ if (!as->as_required_mode && !IEEE80211_IS_CHAN_ST(c)) continue; /* Use any 11g channel instead of 11b one. */ if (vap->iv_des_mode == IEEE80211_MODE_AUTO && IEEE80211_IS_CHAN_B(c) && find11gchannel(ic, i, c->ic_freq)) continue; /* Do not add channels already put into the scan list by the * scan table - these have already been filtered by mode * and for whether they are in the active channel list. */ if (checktable(staScanTable, c)) continue; /* Make sure the channel is active */ if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee)) continue; /* Don't overrun */ if (ss->ss_last >= IEEE80211_SCAN_MAX) break; ss->ss_chans[ss->ss_last++] = c; } ss->ss_next = 0; /* XXX tunables */ ss->ss_mindwell = msecs_to_jiffies(200); /* 200ms */ ss->ss_maxdwell = msecs_to_jiffies(300); /* 300ms */#ifdef IEEE80211_DEBUG if (ieee80211_msg_scan(vap)) { printk("%s: scan set ", vap->iv_dev->name); ieee80211_scan_dump_channels(ss); printk(" dwell min %ld max %ld\n", ss->ss_mindwell, ss->ss_maxdwell); }#endif /* IEEE80211_DEBUG */ as->as_newscan = 1; SCAN_AP_UNLOCK_IRQ(as); return 0;}/* * Restart a bg scan. */static intap_restart(struct ieee80211_scan_state *ss, struct ieee80211vap *vap){ struct ap_state *as = ss->ss_priv; as->as_newscan = 1; return 0;}/* * Cancel an ongoing scan. */static intap_cancel(struct ieee80211_scan_state *ss, struct ieee80211vap *vap){ struct ap_state *as = ss->ss_priv; IEEE80211_CANCEL_TQUEUE(&as->as_actiontq); return 0;}/* * Record max rssi on channel. */static intap_add(struct ieee80211_scan_state *ss, const struct ieee80211_scanparams *sp, const struct ieee80211_frame *wh, int subtype, int rssi, u_int64_t rtsf){ struct ap_state *as = ss->ss_priv; const u_int8_t *macaddr = wh->i_addr2; struct ieee80211vap *vap = ss->ss_vap; struct ieee80211com *ic = vap->iv_ic; struct scan_entry *se = NULL; struct ieee80211_scan_entry *ise = NULL; int hash = AP_HASH(macaddr); int chan; /* This section provides scan results to wireless extensions */ SCAN_AP_LOCK_IRQ(as); chan = ieee80211_chan2ieee(ic, ic->ic_curchan); /* This is the only information used for channel selection by AP */ if (rssi > as->as_maxrssi[chan]) as->as_maxrssi[chan] = rssi; LIST_FOREACH(se, &as->as_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 scan_entry *, sizeof(struct scan_entry), M_80211_SCAN, M_NOWAIT | M_ZERO); if (se == NULL) { SCAN_AP_UNLOCK_IRQ_EARLY(as); return 0; } se->se_scangen = as->as_scangen-1; IEEE80211_ADDR_COPY(se->base.se_macaddr, macaddr); TAILQ_INSERT_TAIL(&as->as_entry, se, se_list); LIST_INSERT_HEAD(&as->as_hash[hash], se, se_hash);found: ise = &se->base; /* XXX: AP beaconing multiple SSID w/ same BSSID */ if ((sp->ssid[1] != 0) && ((subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) || (ise->se_ssid[1] == 0))) memcpy(ise->se_ssid, sp->ssid, 2 + sp->ssid[1]); memcpy(ise->se_rates, sp->rates, IEEE80211_SANITISE_RATESIZE(2 + sp->rates[1])); if (sp->xrates != NULL) { memcpy(ise->se_xrates, sp->xrates, IEEE80211_SANITISE_RATESIZE(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_rtsf = rtsf; 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); se->se_lastupdate = jiffies; /* update time */ se->se_seen = 1; se->se_notseen = 0; SCAN_AP_UNLOCK_IRQ(as); return 1;}struct pc_params { struct ieee80211vap *vap; struct ieee80211_scan_state *ss; int flags;};struct channel { struct ieee80211_channel *chan; int orig; struct pc_params *params;};/* This function must be invoked with locks acquired */static intpc_cmp_radar(struct ieee80211_channel *a, struct ieee80211_channel *b){ /* a is better than b (return < 0) when b is marked while a is not */ return !!IEEE80211_IS_CHAN_RADAR(a) - !!IEEE80211_IS_CHAN_RADAR(b);}/* This function must be invoked with locks acquired */static intpc_cmp_keepmode(struct pc_params *params, struct ieee80211_channel *a, struct ieee80211_channel *b){ struct ieee80211com *ic = params->vap->iv_ic; struct ieee80211_channel *cur = ic->ic_bsschan; if (!(params->flags & IEEE80211_SCAN_KEEPMODE)) return 0; /* a is better than b (return < 0) when (a, cur) have the same mode * and (b, cur) do not. */ return !!IEEE80211_ARE_CHANS_SAME_MODE(b, cur) - !!IEEE80211_ARE_CHANS_SAME_MODE(a, cur);}/* This function must be invoked with locks acquired */static intpc_cmp_sc(struct ieee80211com *ic, struct ieee80211_channel *a, struct ieee80211_channel *b){ /* a is better than b (return < 0) when a has more chan nodes than b */ return ic->ic_chan_nodes[b->ic_ieee] - ic->ic_chan_nodes[a->ic_ieee];}/* This function must be invoked with locks acquired */static intpc_cmp_rssi(struct ap_state *as, struct ieee80211_channel *a, struct ieee80211_channel *b){ /* a is better than b (return < 0) when a has rssi less than b */ return as->as_maxrssi[a->ic_ieee] - as->as_maxrssi[b->ic_ieee];}/* This function must be invoked with locks acquired */static intpc_cmp_samechan(struct ieee80211com *ic, struct ieee80211_channel *a, struct ieee80211_channel *b){ struct ieee80211_channel *ic_bsschan = ic->ic_bsschan; if (ic_bsschan == IEEE80211_CHAN_ANYC) return 0; /* a is better than b (return < 0) when a is current (and b is not) */ return (b == ic_bsschan) - (a == ic_bsschan);}/* This function must be invoked with locks acquired */static intpc_cmp_orig(struct channel *a, struct channel *b){ return a->orig - b->orig;}/* This function must be invoked with locks acquired */static intpc_cmp(const void *_a, const void *_b){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -