📄 ieee80211_node.c
字号:
if (vap->iv_flags & IEEE80211_F_PRIVACY) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) return 0; } else { /* XXX does this mean privacy is supported or required? */ if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) return 0; } rate = ieee80211_fix_rate(ni, IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); if (rate & IEEE80211_RATE_BASIC) return 0; if (vap->iv_des_nssid != 0 && !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) return 0; if ((vap->iv_flags & IEEE80211_F_DESBSSID) && !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid)) return 0; return 1;}#ifdef IEEE80211_DEBUG/* * Display node suitability/compatibility. */static voidcheck_bss_debug(struct ieee80211vap *vap, struct ieee80211_node *ni){ struct ieee80211com *ic = ni->ni_ic; u_int8_t rate; int fail; fail = 0; if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) fail |= 0x01; if (vap->iv_opmode == IEEE80211_M_IBSS) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) fail |= 0x02; } else { if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) fail |= 0x02; } if (vap->iv_flags & IEEE80211_F_PRIVACY) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) fail |= 0x04; } else { /* XXX does this mean privacy is supported or required? */ if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) fail |= 0x04; } rate = ieee80211_fix_rate(ni, IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); if (rate & IEEE80211_RATE_BASIC) fail |= 0x08; if (vap->iv_des_nssid != 0 && !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) fail |= 0x10; if ((vap->iv_flags & IEEE80211_F_DESBSSID) && !IEEE80211_ADDR_EQ(vap->iv_des_bssid, ni->ni_bssid)) fail |= 0x20; printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr)); printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' '); printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' '); printf(" %+4d", ni->ni_rssi); printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, fail & 0x08 ? '!' : ' '); printf(" %4s%c", (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : "????", fail & 0x02 ? '!' : ' '); printf(" %3s%c ", (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" : "no", fail & 0x04 ? '!' : ' '); ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); printf("%s\n", fail & 0x10 ? "!" : "");}#endif /* IEEE80211_DEBUG */ /* * Handle 802.11 ad hoc network merge. The * convention, set by the Wireless Ethernet Compatibility Alliance * (WECA), is that an 802.11 station will change its BSSID to match * the "oldest" 802.11 ad hoc network, on the same channel, that * has the station's desired SSID. The "oldest" 802.11 network * sends beacons with the greatest TSF timestamp. * * The caller is assumed to validate TSF's before attempting a merge. * * Return !0 if the BSSID changed, 0 otherwise. */intieee80211_ibss_merge(struct ieee80211_node *ni){ struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; if (ni == vap->iv_bss || IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) { /* unchanged, nothing to do */ return 0; } if (!check_bss(vap, ni)) { /* capabilities mismatch */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, "%s: merge failed, capabilities mismatch\n", __func__);#ifdef IEEE80211_DEBUG if (ieee80211_msg_assoc(vap)) check_bss_debug(vap, ni);#endif vap->iv_stats.is_ibss_capmismatch++; return 0; } IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, "%s: new bssid %s: %s preamble, %s slot time%s\n", __func__, ether_sprintf(ni->ni_bssid), ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long", ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : ""); return ieee80211_sta_join1(ieee80211_ref_node(ni));}EXPORT_SYMBOL(ieee80211_ibss_merge);static __inline intssid_equal(const struct ieee80211_node *a, const struct ieee80211_node *b){ return (a->ni_esslen == b->ni_esslen && memcmp(a->ni_essid, b->ni_bssid, a->ni_esslen) == 0);}/* * Join the specified IBSS/BSS network. The node is assumed to * be passed in with a reference already held for use in assigning * to iv_bss. */static intieee80211_sta_join1(struct ieee80211_node *selbs){ struct ieee80211vap *vap = selbs->ni_vap; struct ieee80211com *ic = selbs->ni_ic; struct ieee80211_node *obss; int canreassoc; if (vap->iv_opmode == IEEE80211_M_IBSS) { /* * Delete unusable rates; we've already checked * that the negotiated rate set is acceptable. */ ieee80211_fix_rate(selbs, IEEE80211_F_DODEL); } /* * Committed to selbs, setup state. */ obss = vap->iv_bss; /* * Check if old+new node have the same ssid in which * case we can reassociate when operating in sta mode. */ canreassoc = (obss != NULL && vap->iv_state == IEEE80211_S_RUN && ssid_equal(obss, selbs)); vap->iv_bss = selbs; if (obss != NULL) ieee80211_free_node(obss); ic->ic_bsschan = selbs->ni_chan; ic->ic_curchan = ic->ic_bsschan; ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); ic->ic_set_channel(ic); /* * Set the erp state (mostly the slot time) to deal with * the auto-select case; this should be redundant if the * mode is locked. */ ieee80211_reset_erp(ic, ic->ic_curmode); ieee80211_wme_initparams(vap); if (vap->iv_opmode == IEEE80211_M_STA) { /* * Act as if we received a DEAUTH frame in case we are * invoked from the RUN state. This will cause us to try * to re-authenticate if we are operating as a station. */ if (canreassoc) { vap->iv_nsparams.newstate = IEEE80211_S_ASSOC; vap->iv_nsparams.arg = 0; IEEE80211_SCHEDULE_TQUEUE(&vap->iv_stajoin1tq); } else { vap->iv_nsparams.newstate = IEEE80211_S_AUTH; vap->iv_nsparams.arg = IEEE80211_FC0_SUBTYPE_DEAUTH; IEEE80211_SCHEDULE_TQUEUE(&vap->iv_stajoin1tq); } } else { vap->iv_nsparams.newstate = IEEE80211_S_RUN; vap->iv_nsparams.arg = -1; IEEE80211_SCHEDULE_TQUEUE(&vap->iv_stajoin1tq); } return 1;}voidieee80211_sta_join1_tasklet(IEEE80211_TQUEUE_ARG data){ struct ieee80211vap *vap= (struct ieee80211vap *) data; int rc; rc = ieee80211_new_state(vap, vap->iv_nsparams.newstate, vap->iv_nsparams.arg); vap->iv_nsparams.result = rc; vap->iv_nsdone = 1;}EXPORT_SYMBOL(ieee80211_sta_join1_tasklet);intieee80211_sta_join(struct ieee80211vap *vap, const struct ieee80211_scan_entry *se){ struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni; ni = ieee80211_find_node(&ic->ic_sta, se->se_macaddr); if (ni == NULL) { ni = ieee80211_alloc_node(&ic->ic_sta, vap, se->se_macaddr); if (ni == NULL) { /* XXX msg */ return 0; } } else ieee80211_free_node(ni); /* * Expand scan state into node's format. * XXX may not need all this stuff */ ni->ni_authmode = vap->iv_bss->ni_authmode; /* inherit authmode from iv_bss */ /* inherit the WPA setup as well (structure copy!) */ ni->ni_rsn = vap->iv_bss->ni_rsn; IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid); ni->ni_esslen = se->se_ssid[1]; memcpy(ni->ni_essid, se->se_ssid + 2, ni->ni_esslen); ni->ni_rstamp = se->se_rstamp; ni->ni_tstamp.tsf = se->se_tstamp.tsf; ni->ni_intval = se->se_intval; ni->ni_capinfo = se->se_capinfo; ni->ni_chan = se->se_chan; ni->ni_timoff = se->se_timoff; ni->ni_fhdwell = se->se_fhdwell; ni->ni_fhindex = se->se_fhindex; ni->ni_erp = se->se_erp; ni->ni_rssi = se->se_rssi; if (se->se_wpa_ie != NULL) ieee80211_saveie(&ni->ni_wpa_ie, se->se_wpa_ie); if (se->se_rsn_ie != NULL) ieee80211_saveie(&ni->ni_rsn_ie, se->se_rsn_ie); if (se->se_wme_ie != NULL) ieee80211_saveie(&ni->ni_wme_ie, se->se_wme_ie); if (se->se_ath_ie != NULL) ieee80211_saveath(ni, se->se_ath_ie); vap->iv_dtim_period = se->se_dtimperiod; vap->iv_dtim_count = 0; /* NB: must be after ni_chan is setup */ ieee80211_setup_rates(ni, se->se_rates, se->se_xrates, IEEE80211_F_DOSORT | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "%s: %p<%s> refcnt %d\n", __func__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1); return ieee80211_sta_join1(ieee80211_ref_node(ni));}EXPORT_SYMBOL(ieee80211_sta_join);/* * Leave the specified IBSS/BSS network. The node is assumed to * be passed in with a held reference. */voidieee80211_sta_leave(struct ieee80211_node *ni){ struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = vap->iv_ic; /* WDS/Repeater: Stop software beacon timer for STA */ if (vap->iv_opmode == IEEE80211_M_STA && vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) { del_timer(&vap->iv_swbmiss); } ic->ic_node_cleanup(ni); ieee80211_notify_node_leave(ni);}/* * Node table support. */static voidieee80211_node_table_init(struct ieee80211com *ic, struct ieee80211_node_table *nt, const char *name, int inact){ nt->nt_ic = ic; IEEE80211_NODE_LOCK_INIT(nt, ic->ic_dev->name); IEEE80211_SCAN_LOCK_INIT(nt, ic->ic_dev->name); TAILQ_INIT(&nt->nt_node); nt->nt_name = name; nt->nt_scangen = 1; nt->nt_inact_init = inact; init_timer(&nt->nt_wds_aging_timer); nt->nt_wds_aging_timer.function = ieee80211_node_wds_ageout; nt->nt_wds_aging_timer.data = (unsigned long) nt; mod_timer(&nt->nt_wds_aging_timer, jiffies + HZ * WDS_AGING_TIMER_VAL);}static struct ieee80211_node *node_alloc(struct ieee80211_node_table *nt, struct ieee80211vap *vap){ struct ieee80211_node *ni; MALLOC(ni, struct ieee80211_node *, sizeof(struct ieee80211_node), M_80211_NODE, M_NOWAIT | M_ZERO); return ni;}/* * Reclaim any resources in a node and reset any critical * state. Typically nodes are free'd immediately after, * but in some cases the storage may be reused so we need * to ensure consistent state (should probably fix that). * * Context: hwIRQ, softIRQ and process context */static voidnode_cleanup(struct ieee80211_node *ni){#define N(a) (sizeof(a)/sizeof(a[0])) struct ieee80211vap *vap = ni->ni_vap; int i; /* NB: preserve ni_table */ if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { if (vap->iv_opmode != IEEE80211_M_STA) vap->iv_ps_sta--; ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "power save mode off, %u sta's in ps mode", vap->iv_ps_sta); if (ni->ni_flags & IEEE80211_NODE_UAPSD_TRIG) { ni->ni_flags &= ~IEEE80211_NODE_UAPSD_TRIG; IEEE80211_LOCK_IRQ(ni->ni_ic); ni->ni_ic->ic_uapsdmaxtriggers--; IEEE80211_UNLOCK_IRQ(ni->ni_ic); } } /* * Clear AREF flag that marks the authorization refcnt bump * has happened. This is probably not needed as the node * should always be removed from the table so not found but * do it just in case. */ ni->ni_flags &= ~IEEE80211_NODE_AREF; /* * Drain power save queue and, if needed, clear TIM. */ if (ieee80211_node_saveq_drain(ni) != 0 && vap->iv_set_tim != NULL) vap->iv_set_tim(ni, 0); ni->ni_associd = 0; if (ni->ni_challenge != NULL) { FREE(ni->ni_challenge, M_DEVBUF); ni->ni_challenge = NULL; } /* * Preserve SSID, WPA, and WME ie's so the bss node is * reusable during a re-auth/re-assoc state transition. * If we remove these data they will not be recreated * because they come from a probe-response or beacon frame * which cannot be expected prior to the association-response. * This should not be an issue when operating in other modes * as stations leaving always go through a full state transition * which will rebuild this state. * * XXX does this leave us open to inheriting old state? */ for (i = 0; i < N(ni->ni_rxfrag); i++) if (ni->ni_rxfrag[i] != NULL) { dev_kfree_skb_any(ni->ni_rxfrag[i]); ni->ni_rxfrag[i] = NULL; } ieee80211_crypto_delkey(vap, &ni->ni_ucastkey, ni); ni->ni_rxkeyoff = 0;#undef N}static voidnode_free(struct ieee80211_node *ni){ struct ieee80211com *ic = ni->ni_ic; ic->ic_node_cleanup(ni); if (ni->ni_wpa_ie != NULL) FREE(ni->ni_wpa_ie, M_DEVBUF); if (ni->ni_rsn_ie != NULL) FREE(ni->ni_rsn_ie, M_DEVBUF); if (ni->ni_wme_ie != NULL) FREE(ni->ni_wme_ie, M_DEVBUF); if (ni->ni_ath_ie != NULL) FREE(ni->ni_ath_ie, M_DEVBUF); IEEE80211_NODE_SAVEQ_DESTROY(ni); FREE(ni, M_80211_NODE);}static u_int8_tnode_getrssi(const struct ieee80211_node *ni){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -