⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ieee80211_node.c

📁 Linux下wifi实现
💻 C
📖 第 1 页 / 共 5 页
字号:
			 * us to use QoS to disable ACK's and to use short			 * preamble on 2.4G channels.			 */			if (vap->iv_flags & IEEE80211_F_WME)				ni->ni_flags |= IEEE80211_NODE_QOS;			if (vap->iv_flags & IEEE80211_F_SHPREAMBLE)				ni->ni_capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;		}		IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 		"%s: %p<%s> refcnt %d\n", __func__, ni, ether_sprintf(ni->ni_macaddr), 		ieee80211_node_refcnt(ni));	}	return ni;}/* * Locate the node for sender, track state, and then pass the * (referenced) node up to the 802.11 layer for its use.  We * return NULL when the sender is unknown; the driver is required * locate the appropriate virtual ap in that case; possibly * sending it to all (using ieee80211_input_all). */struct ieee80211_node *#ifdef IEEE80211_DEBUG_REFCNTieee80211_find_rxnode_debug(struct ieee80211com *ic,	const struct ieee80211_frame_min *wh, const char *func, int line)#elseieee80211_find_rxnode(struct ieee80211com *ic,	const struct ieee80211_frame_min *wh)#endif{#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)	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_LOCK_IRQ(nt);	if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/)		ni = _ieee80211_find_node(nt, wh->i_addr1);	else		ni = _ieee80211_find_node(nt, wh->i_addr2);	IEEE80211_NODE_UNLOCK_IRQ(nt);	return ni;#undef IS_PSPOLL#undef IS_CTL}#ifdef IEEE80211_DEBUG_REFCNTEXPORT_SYMBOL(ieee80211_find_rxnode_debug);#elseEXPORT_SYMBOL(ieee80211_find_rxnode);#endif/* * Return a reference to the appropriate node for sending * a data frame.  This handles node discovery in adhoc networks. */struct ieee80211_node *#ifdef IEEE80211_DEBUG_REFCNTieee80211_find_txnode_debug(struct ieee80211vap *vap, const u_int8_t *mac,	const char *func, int line)#elseieee80211_find_txnode(struct ieee80211vap *vap, const u_int8_t *mac)#endif{	struct ieee80211_node_table *nt;	struct ieee80211_node *ni;	/*	 * 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_LOCK_IRQ(nt);	ni = _ieee80211_find_node(nt, mac);	IEEE80211_NODE_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)				(void) 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;}#ifdef IEEE80211_DEBUG_REFCNTEXPORT_SYMBOL(ieee80211_find_txnode_debug);#elseEXPORT_SYMBOL(ieee80211_find_txnode);#endif/* Caller must lock the IEEE80211_NODE_LOCK * * Context: hwIRQ, softIRQ and process context */static void_ieee80211_free_node(struct ieee80211_node *ni){	struct ieee80211vap *vap = ni->ni_vap;	struct ieee80211_node_table *nt = ni->ni_table;	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,		"%s: %p<%s> in %s table, refcnt %d\n", __func__, ni,		ether_sprintf(ni->ni_macaddr),		nt != NULL ? nt->nt_name : "<gone>",		ieee80211_node_refcnt(ni));	if (vap->iv_aid_bitmap != NULL)		IEEE80211_AID_CLR(vap, ni->ni_associd);	if (nt != NULL) {		TAILQ_REMOVE(&nt->nt_node, ni, ni_list);		LIST_REMOVE(ni, ni_hash);	}	vap->iv_ic->ic_node_free(ni);}void#ifdef IEEE80211_DEBUG_REFCNTieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line)#elseieee80211_free_node(struct ieee80211_node *ni)#endif{	struct ieee80211_node_table *nt = ni->ni_table;	struct ieee80211com *ic = ni->ni_ic;#ifdef IEEE80211_DEBUG_REFCNT	IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,		"%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni,		 ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni) - 1);#endif	/*	 * XXX: may need to lock out the following race. we dectestref	 *      and determine it's time to free the node. between the if()	 *      and lock, we take an rx intr to receive a frame from this	 *      node. the rx path (tasklet or intr) bumps this node's	 *      refcnt and xmits a response frame. eventually that response	 *      will get reaped, and the reaping code will attempt to use	 *      the node. the code below will delete the node prior	 *      to the reap and we could get a crash.	 *	 *      as a stopgap before delving deeper, lock intrs to	 *      prevent this case.	 */	IEEE80211_LOCK_IRQ(ic);	if (ieee80211_node_dectestref(ni)) {		/*		 * Beware; if the node is marked gone then it's already		 * been removed from the table and we cannot assume the		 * table still exists.  Regardless, there's no need to lock		 * the table.		 */		if (ni->ni_table != NULL) {			IEEE80211_NODE_LOCK(nt);			_ieee80211_free_node(ni);			IEEE80211_NODE_UNLOCK(nt);		} else			_ieee80211_free_node(ni);	}	IEEE80211_UNLOCK_IRQ(ic);}#ifdef IEEE80211_DEBUG_REFCNTEXPORT_SYMBOL(ieee80211_free_node_debug);#elseEXPORT_SYMBOL(ieee80211_free_node);#endif/* * Reclaim a node.  If this is the last reference count then * do the normal free work.  Otherwise remove it from the node * table and mark it gone by clearing the back-reference. */static voidnode_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni){	IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,		"%s: remove %p<%s> from %s table, refcnt %d\n",		__func__, ni, ether_sprintf(ni->ni_macaddr),		nt->nt_name, ieee80211_node_refcnt(ni)-1);	if (!ieee80211_node_dectestref(ni)) {		/*		 * Other references are present, just remove the		 * node from the table so it cannot be found.  When		 * the references are dropped storage will be		 * reclaimed.  This normally only happens for ic_bss.		 */		TAILQ_REMOVE(&nt->nt_node, ni, ni_list);		LIST_REMOVE(ni, ni_hash);		ni->ni_table = NULL;		/* clear reference */	} else		_ieee80211_free_node(ni);}static voidieee80211_node_table_reset(struct ieee80211_node_table *nt,	struct ieee80211vap *match){	struct ieee80211_node *ni, *next;	IEEE80211_NODE_LOCK_IRQ(nt);	TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) {		if (match != NULL && ni->ni_vap != match)			continue;		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);		}		node_reclaim(nt, ni);	}	IEEE80211_NODE_UNLOCK_IRQ(nt);}static voidieee80211_node_table_cleanup(struct ieee80211_node_table *nt){	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);		}		node_reclaim(nt, ni);	}	del_timer(&nt->nt_wds_aging_timer);	IEEE80211_SCAN_LOCK_DESTROY(nt);	IEEE80211_NODE_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_LOCK_IRQ(nt);	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {		if (ni->ni_scangen == gen)	/* previously handled */			continue;		/*		 * Ignore entries for which have yet to receive an		 * authentication frame.  These are transient and		 * will be reclaimed when the last reference to them		 * goes away (when frame xmits complete).		 */		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&		    (ni->ni_flags & IEEE80211_NODE_AREF) == 0)			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[0] != NULL &&		    jiffies > ni->ni_rxfragstamp + HZ) {			dev_kfree_skb(ni->ni_rxfrag[0]);			ni->ni_rxfrag[0] = NULL;		}		/*		 * Special case ourself; we may be idle for extended periods		 * of time and regardless reclaiming our state is wrong.		 */		if (ni == ni->ni_vap->iv_bss) {			/* 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_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)",				ieee80211_node_refcnt(ni));			/*			 * 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_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_free_node(ni);			goto restart;		}	}	IEEE80211_NODE_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);	ic->ic_inact.expires = jiffies + IEEE80211_INACT_WAIT * HZ;	add_timer(&ic->ic_inact);}voidieee80211_iterate_nodes(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_LOCK(nt);	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {		if (ni->ni_scangen != gen) {			ni->ni_scangen = gen;			(void) ieee80211_ref_node(ni);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -