📄 ieee80211_node.c.svn-base
字号:
/* * Return the node for the sender of a frame; if the sender is unknown return * NULL. The caller is expected to deal with this. (The frame is sent to all * VAPs in this case). * * NB: A node reference is acquired here; the caller MUST release it. */struct ieee80211_node *ieee80211_find_rxnode(struct ieee80211com *ic, const struct ieee80211_frame_min *wh){#define IS_CTL(wh) \ ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)#define IS_PSPOLL(wh) \ ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)#define IS_RTS(wh) \ ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_RTS) struct ieee80211_node_table *nt; struct ieee80211_node *ni; /* XXX: check ic_bss first in station mode */ /* XXX: 4-address frames? */ nt = &ic->ic_sta; IEEE80211_NODE_TABLE_LOCK_IRQ(nt); /* NB: Control frames typically have one address, except * for RTS and PSPOLL */ if (IS_CTL(wh) && !IS_PSPOLL(wh) && !IS_RTS(wh)) ni = ieee80211_find_node_locked(nt, wh->i_addr1); else ni = ieee80211_find_node_locked(nt, wh->i_addr2); IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); return ni;#undef IS_PSPOLL#undef IS_CTL#undef IS_RTS}EXPORT_SYMBOL(ieee80211_find_rxnode);/* * Return the appropriate node for sending a data frame. This handles node * discovery in adhoc networks. * * NB: A node reference is acquired here; the caller MUST release it. */struct ieee80211_node *ieee80211_find_txnode(struct ieee80211vap *vap, const u_int8_t *mac){ struct ieee80211_node_table *nt; struct ieee80211_node *ni = NULL; /* The destination address should be in the node table * unless we are operating in station mode or this is a * multicast/broadcast frame. */ if (vap->iv_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(mac)) return ieee80211_ref_node(vap->iv_bss); /* XXX: Can't hold lock across dup_bss due to recursive locking. */ nt = &vap->iv_ic->ic_sta; IEEE80211_NODE_TABLE_LOCK_IRQ(nt); ni = ieee80211_find_node_locked(nt, mac); IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); if (ni == NULL) { if (vap->iv_opmode == IEEE80211_M_IBSS || vap->iv_opmode == IEEE80211_M_AHDEMO) { /* In adhoc mode cons up a node for the destination. * Note that we need an additional reference for the * caller to be consistent with ieee80211_find_node. */ ni = ieee80211_fakeup_adhoc_node(vap, mac); if (ni != NULL) ieee80211_ref_node(ni); } else { IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, mac, "no node, discard frame (%s)", __func__); vap->iv_stats.is_tx_nonode++; } } return ni;}EXPORT_SYMBOL(ieee80211_find_txnode);/* Context: hwIRQ, softIRQ and process context. */voidieee80211_free_node(struct ieee80211_node *ni){ struct ieee80211vap *vap = ni->ni_vap; atomic_dec(&ni->ni_ic->ic_node_counter); node_print_message(IEEE80211_MSG_NODE | IEEE80211_MSG_NODE_REF, 1 /* show counter */, 0 /* adjust refcount */, ni, "free" /* message */); if (vap->iv_aid_bitmap != NULL) IEEE80211_AID_CLR(vap, ni->ni_associd); vap->iv_ic->ic_node_free(ni);}EXPORT_SYMBOL(ieee80211_free_node);static void _reset_node(void *arg, struct ieee80211_node *ni){ if (ni->ni_associd != 0) { struct ieee80211vap *vap = ni->ni_vap; if (vap->iv_auth->ia_node_leave != NULL) vap->iv_auth->ia_node_leave(ni); if (vap->iv_aid_bitmap != NULL) IEEE80211_AID_CLR(vap, ni->ni_associd); } ieee80211_node_leave(ni);}static voidieee80211_node_table_reset(struct ieee80211_node_table *nt, struct ieee80211vap *vap){ ieee80211_iterate_dev_nodes(vap->iv_dev, nt, _reset_node, NULL);}static voidieee80211_node_table_cleanup(struct ieee80211_node_table *nt){ struct ieee80211com *ic = nt->nt_ic; struct ieee80211_node *ni, *next; TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) { if (ni->ni_associd != 0) { struct ieee80211vap *vap = ni->ni_vap; if (vap->iv_auth->ia_node_leave != NULL) vap->iv_auth->ia_node_leave(ni); if (vap->iv_aid_bitmap != NULL) IEEE80211_AID_CLR(vap, ni->ni_associd); } ic->ic_node_cleanup(ni); } del_timer(&nt->nt_wds_aging_timer); IEEE80211_SCAN_LOCK_DESTROY(nt); IEEE80211_NODE_TABLE_LOCK_DESTROY(nt);}/* * Timeout inactive stations and do related housekeeping. * Note that we cannot hold the node lock while sending a * frame as this would lead to a LOR. Instead we use a * generation number to mark nodes that we've scanned and * drop the lock and restart a scan if we have to time out * a node. Since we are single-threaded by virtue of * controlling the inactivity timer we can be sure this will * process each node only once. * * Context: softIRQ (tasklet) */static voidieee80211_timeout_stations(struct ieee80211_node_table *nt){ struct ieee80211com *ic = nt->nt_ic; struct ieee80211_node *ni; u_int gen; int isadhoc; isadhoc = (ic->ic_opmode == IEEE80211_M_IBSS || ic->ic_opmode == IEEE80211_M_AHDEMO); IEEE80211_SCAN_LOCK_IRQ(nt); gen = ++nt->nt_scangen;restart: IEEE80211_NODE_TABLE_LOCK_IRQ(nt); TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { if (ni->ni_scangen == gen) /* previously handled */ continue; ni->ni_scangen = gen; /* * Free fragment if not needed anymore * (last fragment older than 1s). * XXX doesn't belong here */ if (ni->ni_rxfrag != NULL && time_after(jiffies, ni->ni_rxfragstamp + HZ)) { ieee80211_dev_kfree_skb(&ni->ni_rxfrag); } /* * Special case ourself; we may be idle for extended periods * of time and regardless reclaiming our state is wrong. * Special case a WDS link: it may be dead or idle, but it is * never ok to reclaim it, as this will block transmissions * and nobody will recreate the node when the WDS peer is * available again. */ if ((ni == ni->ni_vap->iv_bss) || (ni->ni_vap->iv_opmode == IEEE80211_M_WDS && !memcmp(ni->ni_macaddr, ni->ni_vap->wds_mac, ETH_ALEN))) { /* NB: don't permit it to go negative */ if (ni->ni_inact > 0) ni->ni_inact--; continue; } ni->ni_inact--; if (ni->ni_associd != 0 || isadhoc) { struct ieee80211vap *vap = ni->ni_vap; /* * Age frames on the power save queue. */ if (ieee80211_node_saveq_age(ni) != 0 && IEEE80211_NODE_SAVEQ_QLEN(ni) == 0 && vap->iv_set_tim != NULL) vap->iv_set_tim(ni, 0); /* * Probe the station before time it out. We * send a null data frame which may not be * universally supported by drivers (need it * for ps-poll support so it should be...). */ if (0 < ni->ni_inact && ni->ni_inact <= vap->iv_inact_probe) { IEEE80211_NOTE(vap, IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, "%s", "probe station due to inactivity"); /* * Grab a reference before unlocking the table * so the node cannot be reclaimed before we * send the frame. ieee80211_send_nulldata * understands we've done this and reclaims the * ref for us as needed. */ ieee80211_ref_node(ni); IEEE80211_NODE_TABLE_UNLOCK_IRQ_EARLY(nt); ieee80211_send_nulldata(ni); /* XXX stat? */ goto restart; } } if (ni->ni_inact <= 0) { IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, "station timed out due to inactivity (refcnt %u)", atomic_read(&ni->ni_refcnt)); /* * Send a deauthenticate frame and drop the station. * We grab a reference before unlocking the table so * the node cannot be reclaimed before we complete our * work. * * Separately we must drop the node lock before sending * in case the driver takes a lock, as this may result * in a LOR between the node lock and the driver lock. */ ni->ni_vap->iv_stats.is_node_timeout++; ieee80211_ref_node(ni); IEEE80211_NODE_TABLE_UNLOCK_IRQ_EARLY(nt); if (ni->ni_associd != 0) { IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_EXPIRE); } ieee80211_node_leave(ni); ieee80211_unref_node(&ni); goto restart; } } IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); IEEE80211_SCAN_UNLOCK_IRQ(nt);}/* * Per-ieee80211com inactivity timer callback. */static voidieee80211_node_timeout(unsigned long arg){ struct ieee80211com *ic = (struct ieee80211com *)arg; ieee80211_scan_timeout(ic); ieee80211_timeout_stations(&ic->ic_sta); mod_timer(&ic->ic_inact, jiffies + IEEE80211_INACT_WAIT * HZ);}voidieee80211_iterate_nodes(struct ieee80211_node_table *nt, ieee80211_iter_func *f, void *arg){ ieee80211_iterate_dev_nodes(NULL, nt, f, arg);}EXPORT_SYMBOL(ieee80211_iterate_nodes);voidieee80211_iterate_dev_nodes(struct net_device *dev, struct ieee80211_node_table *nt, ieee80211_iter_func *f, void *arg){ struct ieee80211_node *ni; u_int gen; IEEE80211_SCAN_LOCK_IRQ(nt); gen = ++nt->nt_scangen;restart: IEEE80211_NODE_TABLE_LOCK_IRQ(nt); TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { if (dev != NULL && ni->ni_vap->iv_dev != dev) continue; /* skip node not for this vap */ if (ni->ni_scangen != gen) { ni->ni_scangen = gen; (void)ieee80211_ref_node(ni); IEEE80211_NODE_TABLE_UNLOCK_IRQ_EARLY(nt); (*f)(arg, ni); ieee80211_unref_node(&ni); goto restart; } } IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); IEEE80211_SCAN_UNLOCK_IRQ(nt);}EXPORT_SYMBOL(ieee80211_iterate_dev_nodes);voidieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni){ int i; printk("0x%p: mac " MAC_FMT " (refcnt %d)\n", ni, MAC_ADDR(ni->ni_macaddr), atomic_read(&ni->ni_refcnt)); printk("\tscangen %u authmode %u flags 0x%x\n", ni->ni_scangen, ni->ni_authmode, ni->ni_flags); printk("\tassocid 0x%x txpower %u vlan %u\n", ni->ni_associd, ni->ni_txpower, ni->ni_vlan); printk ("rxfragstamp %lu\n", ni->ni_rxfragstamp); for (i = 0; i < 17; i++) { printk("\t%d: txseq %u rxseq %u fragno %u\n", i, ni->ni_txseqs[i], ni->ni_rxseqs[i] >> IEEE80211_SEQ_SEQ_SHIFT, ni->ni_rxseqs[i] & IEEE80211_SEQ_FRAG_MASK); } printk("\trtsf %10llu rssi %u intval %u capinfo 0x%x\n", ni->ni_rtsf, ni->ni_rssi, ni->ni_intval, ni->ni_capinfo); printk("\tbssid " MAC_FMT " essid \"%.*s\" channel %u:0x%x\n", MAC_ADDR(ni->ni_bssid), ni->ni_esslen, ni->ni_essid, ni->ni_chan != IEEE80211_CHAN_ANYC ? ni->ni_chan->ic_freq : IEEE80211_CHAN_ANY, ni->ni_chan != IEEE80211_CHAN_ANYC ? ni->ni_chan->ic_flags : 0); printk("\tinact %u txrate %u\n", ni->ni_inact, ni->ni_txrate);}voidieee80211_dump_nodes(struct ieee80211_node_table *nt){ ieee80211_iterate_nodes(nt, (ieee80211_iter_func *)ieee80211_dump_node, nt);}/* * Handle a station joining an 11g network. */static voidieee80211_node_join_11g(struct ieee80211_node *ni){ struct ieee80211com *ic = ni->ni_ic;#ifdef IEEE80211_DEBUG struct ieee80211vap *vap = ni->ni_vap;#endif IEEE80211_LOCK_ASSERT(ic); KASSERT(IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan), ("not in 11g, bss %u:0x%x, curmode %u", ic->ic_bsschan->ic_freq, ic->ic_bsschan->ic_flags, ic->ic_curmode)); /* * Station isn't capable of short slot time. Bump * the count of long slot time stations and disable * use of short slot time. Note that the actual switch * over to long slot time use may not occur until the * next beacon transmission (per sec. 7.3.1.4 of 11g). */ if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) { ic->ic_longslotsta++; IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, "station needs long slot time, count %d", ic->ic_longslotsta); /* XXX VAPs w/ conflicting needs won't work */ if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) { /* * Don't force slot time when switched to turbo * mode as non-ERP stations won't be present; this * need only be done when on the normal G channel. */ ieee80211_set_shortslottime(ic, 0); } } /* * If the new station is not an ERP station * then bump the counter and enable protection * if configured. */ if (!ieee80211_iserp_rateset(ic, &ni->ni_rates)) { ic->ic_nonerpsta++; IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, "station is !ERP, %d non-ERP stations associated", ic->ic_nonerpsta); /* * If protection is configured, enable it. */ if (ic->ic_protmode != IEEE80211_PROT_NONE) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, "%s: enable use of protection\n", __func__); ic->ic_flags |= IEEE80211_F_USEPROT; } /* * If station does not support short preamble * then we must enable use of Barker preamble. */ if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) { IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, "%s", "station needs long preamble"); ic->ic_flags |= IEEE80211_F_USEBARKER; ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; } /* Update ERP element if this is first non ERP station */ if (ic->ic_nonerpsta == 1) ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE; } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -