svn commit: r195379 - head/sys/net80211

Sam Leffler sam at FreeBSD.org
Sun Jul 5 18:17:38 UTC 2009


Author: sam
Date: Sun Jul  5 18:17:37 2009
New Revision: 195379
URL: http://svn.freebsd.org/changeset/base/195379

Log:
  Add ieee80211_ageq; a facility for staging packets that require
  long-term work before they can be serviced.  Packets are tagged and
  assigned an age (in seconds) at the point they are added to the
  queue.  If a packet is not retrieved before it's age expires it is
  reclaimed.  Tagging can take two forms: a reference to an ieee80211_node
  (as happens in the tx path) or an opaque token in cases where there
  is no reference or the node structure is not stable (i.e. it's going
  to be destroyed).
  
  o add ic_stageq to replace the per-node wds staging queue used for
    dynamic wds
  o add ieee80211_mac_hash for building ageq tokens; this computes a
    32-bit hash from an 802.11 mac address (copied from the bridge)
  o while here fix a stray ';' noticed in IEEE80211_PSQ_INIT
  
  Reviewed by:	rpaulo
  Approved by:	re (kensmith)

Added:
  head/sys/net80211/ieee80211_ageq.c   (contents, props changed)
  head/sys/net80211/ieee80211_ageq.h   (contents, props changed)
Modified:
  head/sys/net80211/ieee80211.c
  head/sys/net80211/ieee80211_freebsd.h
  head/sys/net80211/ieee80211_node.c
  head/sys/net80211/ieee80211_node.h
  head/sys/net80211/ieee80211_var.h
  head/sys/net80211/ieee80211_wds.c

Modified: head/sys/net80211/ieee80211.c
==============================================================================
--- head/sys/net80211/ieee80211.c	Sun Jul  5 18:15:06 2009	(r195378)
+++ head/sys/net80211/ieee80211.c	Sun Jul  5 18:17:37 2009	(r195379)
@@ -268,6 +268,7 @@ ieee80211_ifattach(struct ieee80211com *
 	ic->ic_update_mcast = null_update_mcast;
 	ic->ic_update_promisc = null_update_promisc;
 
+	ic->ic_hash_key = arc4random();
 	ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
 	ic->ic_lintval = ic->ic_bintval;
 	ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
@@ -1568,3 +1569,39 @@ ieee80211_media2rate(int mword)
 		ieeerates[IFM_SUBTYPE(mword)] : 0;
 #undef N
 }
+
+/*
+ * The following hash function is adapted from "Hash Functions" by Bob Jenkins
+ * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
+ */
+#define	mix(a, b, c)							\
+do {									\
+	a -= b; a -= c; a ^= (c >> 13);					\
+	b -= c; b -= a; b ^= (a << 8);					\
+	c -= a; c -= b; c ^= (b >> 13);					\
+	a -= b; a -= c; a ^= (c >> 12);					\
+	b -= c; b -= a; b ^= (a << 16);					\
+	c -= a; c -= b; c ^= (b >> 5);					\
+	a -= b; a -= c; a ^= (c >> 3);					\
+	b -= c; b -= a; b ^= (a << 10);					\
+	c -= a; c -= b; c ^= (b >> 15);					\
+} while (/*CONSTCOND*/0)
+
+uint32_t
+ieee80211_mac_hash(const struct ieee80211com *ic,
+	const uint8_t addr[IEEE80211_ADDR_LEN])
+{
+	uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = ic->ic_hash_key;
+
+	b += addr[5] << 8;
+	b += addr[4];
+	a += addr[3] << 24;
+	a += addr[2] << 16;
+	a += addr[1] << 8;
+	a += addr[0];
+
+	mix(a, b, c);
+
+	return c;
+}
+#undef mix

Added: head/sys/net80211/ieee80211_ageq.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/net80211/ieee80211_ageq.c	Sun Jul  5 18:17:37 2009	(r195379)
@@ -0,0 +1,236 @@
+/*-
+ * Copyright (c) 2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * IEEE 802.11 age queue support.
+ */
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h> 
+#include <sys/kernel.h>
+ 
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/ethernet.h>
+
+#include <net80211/ieee80211_var.h>
+
+/*
+ * Initialize an ageq.
+ */
+void
+ieee80211_ageq_init(struct ieee80211_ageq *aq, int maxlen, const char *name)
+{
+	memset(aq, 0, sizeof(aq));
+	aq->aq_maxlen = maxlen;
+	IEEE80211_AGEQ_INIT(aq, name);		/* OS-dependent setup */
+}
+
+/*
+ * Cleanup an ageq initialized with ieee80211_ageq_init.  Note
+ * the queue is assumed empty; this can be done with ieee80211_ageq_drain.
+ */
+void
+ieee80211_ageq_cleanup(struct ieee80211_ageq *aq)
+{
+	KASSERT(aq->aq_len == 0, ("%d frames on ageq", aq->aq_len));
+	IEEE80211_AGEQ_DESTROY(aq);		/* OS-dependent cleanup */
+}
+
+/*
+ * Free an mbuf according to ageq rules: if marked as holding
+ * and 802.11 frame then also reclaim a node reference from
+ * the packet header; this handles packets q'd in the tx path.
+ */
+static void
+ageq_mfree(struct mbuf *m)
+{
+	if (m->m_flags & M_ENCAP) {
+		struct ieee80211_node *ni = (void *) m->m_pkthdr.rcvif;
+		ieee80211_free_node(ni);
+	}
+	m->m_nextpkt = NULL;
+	m_freem(m);
+}
+
+/*
+ * Free a list of mbufs using ageq rules (see above).
+ */
+void
+ieee80211_ageq_mfree(struct mbuf *m)
+{
+	struct mbuf *next;
+
+	for (; m != NULL; m = next) {
+		next = m->m_nextpkt;
+		ageq_mfree(m);
+	}
+}
+
+/*
+ * Append an mbuf to the ageq and mark it with the specified max age
+ * If the frame is not removed before the age (in seconds) expires
+ * then it is reclaimed (along with any node reference).
+ */
+int
+ieee80211_ageq_append(struct ieee80211_ageq *aq, struct mbuf *m, int age)
+{
+	IEEE80211_AGEQ_LOCK(aq);
+	if (__predict_true(aq->aq_len < aq->aq_maxlen)) {
+		if (aq->aq_tail == NULL) {
+			aq->aq_head = m;
+		} else {
+			aq->aq_tail->m_nextpkt = m;
+			age -= M_AGE_GET(aq->aq_head);
+		}
+		KASSERT(age >= 0, ("age %d", age));
+		M_AGE_SET(m, age);
+		m->m_nextpkt = NULL;
+		aq->aq_tail = m;
+		aq->aq_len++;
+		IEEE80211_AGEQ_UNLOCK(aq);
+		return 0;
+	} else {
+		/*
+		 * No space, drop and cleanup references.
+		 */
+		aq->aq_drops++;
+		IEEE80211_AGEQ_UNLOCK(aq);
+		/* XXX tail drop? */
+		ageq_mfree(m);
+		return ENOSPC;
+	}
+}
+
+/*
+ * Drain/reclaim all frames from an ageq.
+ */
+void
+ieee80211_ageq_drain(struct ieee80211_ageq *aq)
+{
+	ieee80211_ageq_mfree(ieee80211_ageq_remove(aq, NULL));
+}
+
+/*
+ * Drain/reclaim frames associated with a specific node from an ageq.
+ */
+void
+ieee80211_ageq_drain_node(struct ieee80211_ageq *aq,
+	struct ieee80211_node *ni)
+{
+	ieee80211_ageq_mfree(ieee80211_ageq_remove(aq, ni));
+}
+
+/*
+ * Age frames on the age queue.  Ages are stored as time
+ * deltas (in seconds) relative to the head so we can check
+ * and/or adjust only the head of the list.  If a frame's age
+ * exceeds the time quanta then remove it.  The list of removed
+ * frames is is returned to the caller joined by m_nextpkt.
+ */
+struct mbuf *
+ieee80211_ageq_age(struct ieee80211_ageq *aq, int quanta)
+{
+	struct mbuf *head, **phead;
+	struct mbuf *m;
+
+	phead = &head;
+	if (aq->aq_len != 0) {
+		IEEE80211_AGEQ_LOCK(aq);
+		while ((m = aq->aq_head) != NULL && M_AGE_GET(m) < quanta) {
+			if ((aq->aq_head = m->m_nextpkt) == NULL)
+				aq->aq_tail = NULL;
+			KASSERT(aq->aq_len > 0, ("aq len %d", aq->aq_len));
+			aq->aq_len--;
+			/* add to private list for return */
+			*phead = m;
+			phead = &m->m_nextpkt;
+		}
+		if (m != NULL)
+			M_AGE_SUB(m, quanta);
+		IEEE80211_AGEQ_UNLOCK(aq);
+	}
+	*phead = NULL;
+	return head;
+}
+
+/*
+ * Remove all frames matching the specified node identifier
+ * (NULL matches all).  Frames are returned as a list joined
+ * by m_nextpkt.
+ */
+struct mbuf *
+ieee80211_ageq_remove(struct ieee80211_ageq *aq,
+	struct ieee80211_node *match)
+{
+	struct mbuf *m, **prev, *ohead;
+	struct mbuf *head, **phead;
+
+	IEEE80211_AGEQ_LOCK(aq);
+	ohead = aq->aq_head;
+	prev = &aq->aq_head;
+	phead = &head;
+	while ((m = *prev) != NULL) {
+		if (match != NULL && m->m_pkthdr.rcvif != (void *) match) {
+			prev = &m->m_nextpkt;
+			continue;
+		}
+		/*
+		 * Adjust q length.
+		 */
+		KASSERT(aq->aq_len > 0, ("aq len %d", aq->aq_len));
+		aq->aq_len--;
+		/*
+		 * Remove from forward list; tail pointer is harder.
+		 */
+		*prev = m->m_nextpkt;
+		if (aq->aq_tail == m) {
+			KASSERT(m->m_nextpkt == NULL, ("not last"));
+			if (aq->aq_head == m) {		/* list empty */
+				KASSERT(aq->aq_len == 0,
+				    ("not empty, len %d", aq->aq_len));
+				aq->aq_tail = NULL;
+			} else {			/* must be one before */
+				aq->aq_tail = (struct mbuf *)((uintptr_t)prev -
+				    offsetof(struct mbuf, m_nextpkt));
+			}
+		}
+		/* add to private list for return */
+		*phead = m;
+		phead = &m->m_nextpkt;
+	}
+	if (head == ohead && aq->aq_head != NULL)	/* correct age */
+		M_AGE_SET(aq->aq_head, M_AGE_GET(head));
+	IEEE80211_AGEQ_UNLOCK(aq);
+
+	*phead = NULL;
+	return head;
+}

Added: head/sys/net80211/ieee80211_ageq.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/net80211/ieee80211_ageq.h	Sun Jul  5 18:17:37 2009	(r195379)
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NET80211_IEEE80211_STAGEQ_H_
+#define _NET80211_IEEE80211_STAGEQ_H_
+
+struct ieee80211_node;
+struct mbuf;
+
+struct ieee80211_ageq {
+	ieee80211_ageq_lock_t	aq_lock;
+	int			aq_len;		/* # items on queue */
+	int			aq_maxlen;	/* max queue length */
+	int			aq_drops;	/* frames dropped */
+	struct mbuf		*aq_head;	/* frames linked w/ m_nextpkt */
+	struct mbuf		*aq_tail;	/* last frame in queue */
+};
+
+void	ieee80211_ageq_init(struct ieee80211_ageq *, int maxlen,
+	    const char *name);
+void	ieee80211_ageq_cleanup(struct ieee80211_ageq *);
+void	ieee80211_ageq_mfree(struct mbuf *);
+int	ieee80211_ageq_append(struct ieee80211_ageq *, struct mbuf *,
+	    int age);
+void	ieee80211_ageq_drain(struct ieee80211_ageq *);
+void	ieee80211_ageq_drain_node(struct ieee80211_ageq *,
+	    struct ieee80211_node *);
+struct mbuf *ieee80211_ageq_age(struct ieee80211_ageq *, int quanta);
+struct mbuf *ieee80211_ageq_remove(struct ieee80211_ageq *,
+	    struct ieee80211_node *match);
+#endif /* _NET80211_IEEE80211_STAGEQ_H_ */

Modified: head/sys/net80211/ieee80211_freebsd.h
==============================================================================
--- head/sys/net80211/ieee80211_freebsd.h	Sun Jul  5 18:15:06 2009	(r195378)
+++ head/sys/net80211/ieee80211_freebsd.h	Sun Jul  5 18:17:37 2009	(r195379)
@@ -100,25 +100,12 @@ typedef struct {
 #define	IEEE80211_NODE_ITERATE_UNLOCK(_nt) \
 	mtx_unlock(IEEE80211_NODE_ITERATE_LOCK_OBJ(_nt))
 
-#define	_AGEQ_ENQUEUE(_ifq, _m, _qlen, _age) do {		\
-	(_m)->m_nextpkt = NULL;					\
-	if ((_ifq)->ifq_tail != NULL) { 			\
-		_age -= M_AGE_GET((_ifq)->ifq_head);		\
-		(_ifq)->ifq_tail->m_nextpkt = (_m);		\
-	} else { 						\
-		(_ifq)->ifq_head = (_m); 			\
-	}							\
-	M_AGE_SET(_m, _age);					\
-	(_ifq)->ifq_tail = (_m); 				\
-	(_qlen) = ++(_ifq)->ifq_len; 				\
-} while (0)
-
 /*
  * Power-save queue definitions. 
  */
 typedef struct mtx ieee80211_psq_lock_t;
 #define	IEEE80211_PSQ_INIT(_psq, _name) \
-	mtx_init(&(_psq)->psq_lock, _name, "802.11 ps q", MTX_DEF);
+	mtx_init(&(_psq)->psq_lock, _name, "802.11 ps q", MTX_DEF)
 #define	IEEE80211_PSQ_DESTROY(_psq)	mtx_destroy(&(_psq)->psq_lock)
 #define	IEEE80211_PSQ_LOCK(_psq)	mtx_lock(&(_psq)->psq_lock)
 #define	IEEE80211_PSQ_UNLOCK(_psq)	mtx_unlock(&(_psq)->psq_lock)
@@ -137,24 +124,16 @@ typedef struct mtx ieee80211_psq_lock_t;
 	IF_UNLOCK(ifq);						\
 } while (0)
 #endif /* IF_PREPEND_LIST */
-
-/* XXX temporary */
-#define	IEEE80211_NODE_WDSQ_INIT(_ni, _name) do {		\
-	mtx_init(&(_ni)->ni_wdsq.ifq_mtx, _name, "802.11 wds queue", MTX_DEF);\
-	(_ni)->ni_wdsq.ifq_maxlen = IEEE80211_PS_MAX_QUEUE;	\
-} while (0)
-#define	IEEE80211_NODE_WDSQ_DESTROY(_ni) do { \
-	mtx_destroy(&(_ni)->ni_wdsq.ifq_mtx); \
-} while (0)
-#define	IEEE80211_NODE_WDSQ_QLEN(_ni)	_IF_QLEN(&(_ni)->ni_wdsq)
-#define	IEEE80211_NODE_WDSQ_LOCK(_ni)	IF_LOCK(&(_ni)->ni_wdsq)
-#define	IEEE80211_NODE_WDSQ_UNLOCK(_ni)	IF_UNLOCK(&(_ni)->ni_wdsq)
-#define	_IEEE80211_NODE_WDSQ_DEQUEUE_HEAD(_ni, _m) do {		\
-	_IF_DEQUEUE(&(_ni)->ni_wdsq, m);			\
-} while (0)
-#define	_IEEE80211_NODE_WDSQ_ENQUEUE(_ni, _m, _qlen, _age) do {	\
-	_AGEQ_ENQUEUE(&ni->ni_wdsq, _m, _qlen, _age);		\
-} while (0)
+ 
+/*
+ * Age queue definitions.
+ */
+typedef struct mtx ieee80211_ageq_lock_t;
+#define	IEEE80211_AGEQ_INIT(_aq, _name) \
+	mtx_init(&(_aq)->aq_lock, _name, "802.11 age q", MTX_DEF)
+#define	IEEE80211_AGEQ_DESTROY(_aq)	mtx_destroy(&(_aq)->aq_lock)
+#define	IEEE80211_AGEQ_LOCK(_aq)	mtx_lock(&(_aq)->aq_lock)
+#define	IEEE80211_AGEQ_UNLOCK(_aq)	mtx_unlock(&(_aq)->aq_lock)
 
 /*
  * 802.1x MAC ACL database locking definitions.

Modified: head/sys/net80211/ieee80211_node.c
==============================================================================
--- head/sys/net80211/ieee80211_node.c	Sun Jul  5 18:15:06 2009	(r195378)
+++ head/sys/net80211/ieee80211_node.c	Sun Jul  5 18:17:37 2009	(r195379)
@@ -99,6 +99,9 @@ MALLOC_DEFINE(M_80211_NODE_IE, "80211nod
 void
 ieee80211_node_attach(struct ieee80211com *ic)
 {
+	/* XXX really want maxlen enforced per-sta */
+	ieee80211_ageq_init(&ic->ic_stageq, ic->ic_max_keyix * 8,
+	    "802.11 staging q");
 	ieee80211_node_table_init(ic, &ic->ic_sta, "station",
 		IEEE80211_INACT_INIT, ic->ic_max_keyix);
 	callout_init(&ic->ic_inact, CALLOUT_MPSAFE);
@@ -127,6 +130,7 @@ ieee80211_node_detach(struct ieee80211co
 
 	callout_drain(&ic->ic_inact);
 	ieee80211_node_table_cleanup(&ic->ic_sta);
+	ieee80211_ageq_cleanup(&ic->ic_stageq);
 }
 
 void
@@ -927,6 +931,7 @@ node_cleanup(struct ieee80211_node *ni)
 {
 #define	N(a)	(sizeof(a)/sizeof(a[0]))
 	struct ieee80211vap *vap = ni->ni_vap;
+	struct ieee80211com *ic = ni->ni_ic;
 	int i;
 
 	/* NB: preserve ni_table */
@@ -947,6 +952,11 @@ node_cleanup(struct ieee80211_node *ni)
 		ieee80211_ff_node_cleanup(ni);
 #endif
 	/*
+	 * Clear any staging queue entries.
+	 */
+	ieee80211_ageq_drain_node(&ic->ic_stageq, ni);
+
+	/*
 	 * 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
@@ -999,7 +1009,6 @@ node_free(struct ieee80211_node *ni)
 	ic->ic_node_cleanup(ni);
 	ieee80211_ies_cleanup(&ni->ni_ies);
 	ieee80211_psq_cleanup(&ni->ni_psq);
-	IEEE80211_NODE_WDSQ_DESTROY(ni);
 	free(ni, M_80211_NODE);
 }
 
@@ -1017,11 +1026,6 @@ node_age(struct ieee80211_node *ni)
 	    ni->ni_psq.psq_len == 0 && vap->iv_set_tim != NULL)
 		vap->iv_set_tim(ni, 0);
 	/*
-	 * Age frames on the wds pending queue.
-	 */
-	if (IEEE80211_NODE_WDSQ_QLEN(ni) != 0)
-		ieee80211_node_wdsq_age(ni);
-	/*
 	 * Age out HT resources (e.g. frames on the
 	 * A-MPDU reorder queues).
 	 */
@@ -1086,7 +1090,6 @@ ieee80211_alloc_node(struct ieee80211_no
 	ni->ni_inact = ni->ni_inact_reload;
 	ni->ni_ath_defkeyix = 0x7fff;
 	ieee80211_psq_init(&ni->ni_psq, "unknown");
-	IEEE80211_NODE_WDSQ_INIT(ni, "unknown");
 
 	IEEE80211_NODE_LOCK(nt);
 	TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
@@ -1136,7 +1139,6 @@ ieee80211_tmp_node(struct ieee80211vap *
 		ni->ni_txpower = bss->ni_txpower;
 		/* XXX optimize away */
 		ieee80211_psq_init(&ni->ni_psq, "unknown");
-		IEEE80211_NODE_WDSQ_INIT(ni, "unknown");
 	} else {
 		/* XXX msg */
 		vap->iv_stats.is_rx_nodealloc++;
@@ -2075,6 +2077,7 @@ ieee80211_node_timeout(void *arg)
 	if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) {
 		ieee80211_scan_timeout(ic);
 		ieee80211_timeout_stations(ic);
+		ieee80211_ageq_age(&ic->ic_stageq, IEEE80211_INACT_WAIT);
 
 		IEEE80211_LOCK(ic);
 		ieee80211_erp_timeout(ic);

Modified: head/sys/net80211/ieee80211_node.h
==============================================================================
--- head/sys/net80211/ieee80211_node.h	Sun Jul  5 18:15:06 2009	(r195378)
+++ head/sys/net80211/ieee80211_node.h	Sun Jul  5 18:17:37 2009	(r195379)
@@ -193,8 +193,6 @@ struct ieee80211_node {
 	struct ieee80211_nodestats ni_stats;	/* per-node statistics */
 
 	struct ieee80211vap	*ni_wdsvap;	/* associated WDS vap */
-	/* XXX move to vap? */
-	struct ifqueue		ni_wdsq;	/* wds pending queue */
 	uint64_t		ni_spare[4];
 };
 MALLOC_DECLARE(M_80211_NODE);

Modified: head/sys/net80211/ieee80211_var.h
==============================================================================
--- head/sys/net80211/ieee80211_var.h	Sun Jul  5 18:15:06 2009	(r195378)
+++ head/sys/net80211/ieee80211_var.h	Sun Jul  5 18:17:37 2009	(r195379)
@@ -44,6 +44,7 @@
 
 #include <net80211/_ieee80211.h>
 #include <net80211/ieee80211.h>
+#include <net80211/ieee80211_ageq.h>
 #include <net80211/ieee80211_crypto.h>
 #include <net80211/ieee80211_dfs.h>
 #include <net80211/ieee80211_ioctl.h>		/* for ieee80211_stats */
@@ -194,6 +195,8 @@ struct ieee80211com {
 	/* NB: this is the union of all vap stations/neighbors */
 	int			ic_max_keyix;	/* max h/w key index */
 	struct ieee80211_node_table ic_sta;	/* stations/neighbors */
+	struct ieee80211_ageq	ic_stageq;	/* frame staging queue */
+	uint32_t		ic_hash_key;	/* random key for mac hash */
 
 	/* XXX multi-bss: split out common/vap parts */
 	struct ieee80211_wme_state ic_wme;	/* WME/WMM state */
@@ -659,6 +662,8 @@ struct ieee80211_channel *ieee80211_find
 		int ieee, int flags);
 int	ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode);
 enum ieee80211_phymode ieee80211_chan2mode(const struct ieee80211_channel *);
+uint32_t ieee80211_mac_hash(const struct ieee80211com *,
+		const uint8_t addr[IEEE80211_ADDR_LEN]);
 
 void	ieee80211_radiotap_attach(struct ieee80211com *,
 	    struct ieee80211_radiotap_header *th, int tlen,

Modified: head/sys/net80211/ieee80211_wds.c
==============================================================================
--- head/sys/net80211/ieee80211_wds.c	Sun Jul  5 18:15:06 2009	(r195378)
+++ head/sys/net80211/ieee80211_wds.c	Sun Jul  5 18:17:37 2009	(r195379)
@@ -97,6 +97,28 @@ wds_vattach(struct ieee80211vap *vap)
 	vap->iv_opdetach = wds_vdetach;
 }
 
+static void
+wds_flush(struct ieee80211_node *ni)
+{
+	struct ieee80211com *ic = ni->ni_ic;
+	struct mbuf *m, *next;
+	int8_t rssi, nf;
+
+	m = ieee80211_ageq_remove(&ic->ic_stageq,
+	    (void *)(uintptr_t) ieee80211_mac_hash(ic, ni->ni_macaddr));
+	if (m == NULL)
+		return;
+
+	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_WDS, ni,
+	    "%s", "flush wds queue");
+	ic->ic_node_getsignal(ni, &rssi, &nf);
+	for (; m != NULL; m = next) {
+		next = m->m_nextpkt;
+		m->m_nextpkt = NULL;
+		ieee80211_input(ni, m, rssi, nf);
+	}
+}
+
 static int
 ieee80211_create_wds(struct ieee80211vap *vap, struct ieee80211_channel *chan)
 {
@@ -195,26 +217,10 @@ ieee80211_create_wds(struct ieee80211vap
 	}
 
 	/*
-	 * Flush pending frames now that were setup.
+	 * Flush any pending frames now that were setup.
 	 */
-	if (ni != NULL && IEEE80211_NODE_WDSQ_QLEN(ni) != 0) {
-		int8_t rssi, nf;
-
-		IEEE80211_NOTE(vap, IEEE80211_MSG_WDS, ni,
-		    "flush wds queue, %u packets queued",
-		    IEEE80211_NODE_WDSQ_QLEN(ni));
-		ic->ic_node_getsignal(ni, &rssi, &nf);
-		for (;;) {
-			struct mbuf *m;
-
-			IEEE80211_NODE_WDSQ_LOCK(ni);
-			_IEEE80211_NODE_WDSQ_DEQUEUE_HEAD(ni, m);
-			IEEE80211_NODE_WDSQ_UNLOCK(ni);
-			if (m == NULL)
-				break;
-			ieee80211_input(ni, m, rssi, nf);
-		}
-	}
+	if (ni != NULL)
+		wds_flush(ni);
 	return (ni == NULL ? ENOENT : 0);
 }
 
@@ -310,91 +316,24 @@ ieee80211_dwds_mcast(struct ieee80211vap
 void
 ieee80211_dwds_discover(struct ieee80211_node *ni, struct mbuf *m)
 {
-	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
-	int qlen, age;
-
-	IEEE80211_NODE_WDSQ_LOCK(ni);
-	if (!_IF_QFULL(&ni->ni_wdsq)) {
-		/*
-		 * Tag the frame with it's expiry time and insert
-		 * it in the queue.  The aging interval is 4 times
-		 * the listen interval specified by the station. 
-		 * Frames that sit around too long are reclaimed
-		 * using this information.
-		 */
-		/* XXX handle overflow? */
-		/* XXX per/vap beacon interval? */
-		/* NB: TU -> secs */
-		age = ((ni->ni_intval * ic->ic_lintval) << 2) / 1024;
-		_IEEE80211_NODE_WDSQ_ENQUEUE(ni, m, qlen, age);
-		IEEE80211_NODE_WDSQ_UNLOCK(ni);
 
-		IEEE80211_NOTE(vap, IEEE80211_MSG_WDS, ni,
-		    "save frame, %u now queued", qlen);
-	} else {
-		vap->iv_stats.is_dwds_qdrop++;
-		_IF_DROP(&ni->ni_wdsq);
-		IEEE80211_NODE_WDSQ_UNLOCK(ni);
-
-		IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT | IEEE80211_MSG_WDS,
-		    mtod(m, struct ieee80211_frame *), "wds data",
-		    "pending q overflow, drops %d (len %d)",
-		    ni->ni_wdsq.ifq_drops, ni->ni_wdsq.ifq_len);
-
-#ifdef IEEE80211_DEBUG
-		if (ieee80211_msg_dumppkts(vap))
-			ieee80211_dump_pkt(ic, mtod(m, caddr_t),
-			    m->m_len, -1, -1);
-#endif
-		/* XXX tail drop? */
-		m_freem(m);
-	}
+	/*
+	 * Save the frame with an aging interval 4 times
+	 * the listen interval specified by the station. 
+	 * Frames that sit around too long are reclaimed
+	 * using this information.
+	 * XXX handle overflow?
+	 * XXX per/vap beacon interval?
+	 */
+	m->m_pkthdr.rcvif = (void *)(uintptr_t)
+	    ieee80211_mac_hash(ic, ni->ni_macaddr);
+	(void) ieee80211_ageq_append(&ic->ic_stageq, m,
+	    ((ni->ni_intval * ic->ic_lintval) << 2) / 1024);
 	ieee80211_notify_wds_discover(ni);
 }
 
 /*
- * Age frames on the WDS pending queue. The aging interval is
- * 4 times the listen interval specified by the station.  This
- * number is factored into the age calculations when the frame
- * is placed on the queue.  We store ages as time differences
- * so we can check and/or adjust only the head of the list.
- * If a frame's age exceeds the threshold then discard it.
- * The number of frames discarded is returned to the caller.
- */
-int
-ieee80211_node_wdsq_age(struct ieee80211_node *ni)
-{
-#ifdef IEEE80211_DEBUG
-	struct ieee80211vap *vap = ni->ni_vap;
-#endif
-	struct mbuf *m;
-	int discard = 0;
-
-	IEEE80211_NODE_WDSQ_LOCK(ni);
-	while (_IF_POLL(&ni->ni_wdsq, m) != NULL &&
-	     M_AGE_GET(m) < IEEE80211_INACT_WAIT) {
-		IEEE80211_NOTE(vap, IEEE80211_MSG_WDS, ni,
-			"discard frame, age %u", M_AGE_GET(m));
-
-		/* XXX could be optimized */
-		_IEEE80211_NODE_WDSQ_DEQUEUE_HEAD(ni, m);
-		m_freem(m);
-		discard++;
-	}
-	if (m != NULL)
-		M_AGE_SUB(m, IEEE80211_INACT_WAIT);
-	IEEE80211_NODE_WDSQ_UNLOCK(ni);
-
-	IEEE80211_NOTE(vap, IEEE80211_MSG_WDS, ni,
-	    "discard %u frames for age", discard);
-#if 0
-	IEEE80211_NODE_STAT_ADD(ni, wds_discard, discard);
-#endif
-	return discard;
-}
-
-/*
  * IEEE80211_M_WDS vap state machine handler.
  */
 static int


More information about the svn-src-all mailing list