svn commit: r195079 - in projects/mesh11s/sys: conf net80211

Sam Leffler sam at FreeBSD.org
Fri Jun 26 21:31:08 UTC 2009


Author: sam
Date: Fri Jun 26 21:31:07 2009
New Revision: 195079
URL: http://svn.freebsd.org/changeset/base/195079

Log:
  Add generic "age queue" and use it to replace dwds pending q and to
  hold mesh frames waiting for path discovery:
  o add ieee80211_ageq support; frames are ordered by age (seconds) and
    tagged with either a node reference or an opaque 32-bit tag (if marked
    with M_ENCAP then a node ref is assumed and free's reclaim the ref)
  o add ic_stageq as a global repository for various frame staging requirments;
    init, flush, and age (using the inactivity timer)
  o remove ni_wdsq and use ic_stageq instead to handle dwds frames q'd on
    dwds discovery
  o add queueing of mesh packets on hwmp discovery; queue is flushed on
    prepv recv
  o change ieee80211_hwmp_discover to pass the mbuf down so it can be queued

Added:
  projects/mesh11s/sys/net80211/ieee80211_ageq.c   (contents, props changed)
  projects/mesh11s/sys/net80211/ieee80211_ageq.h   (contents, props changed)
Modified:
  projects/mesh11s/sys/conf/files
  projects/mesh11s/sys/net80211/ieee80211_freebsd.h
  projects/mesh11s/sys/net80211/ieee80211_hwmp.c
  projects/mesh11s/sys/net80211/ieee80211_hwmp.h
  projects/mesh11s/sys/net80211/ieee80211_node.c
  projects/mesh11s/sys/net80211/ieee80211_node.h
  projects/mesh11s/sys/net80211/ieee80211_output.c
  projects/mesh11s/sys/net80211/ieee80211_var.h
  projects/mesh11s/sys/net80211/ieee80211_wds.c

Modified: projects/mesh11s/sys/conf/files
==============================================================================
--- projects/mesh11s/sys/conf/files	Fri Jun 26 20:39:36 2009	(r195078)
+++ projects/mesh11s/sys/conf/files	Fri Jun 26 21:31:07 2009	(r195079)
@@ -2231,6 +2231,7 @@ net/zlib.c			optional crypto | geom_uzip
 net80211/ieee80211.c		optional wlan
 net80211/ieee80211_acl.c	optional wlan wlan_acl
 net80211/ieee80211_adhoc.c	optional wlan
+net80211/ieee80211_ageq.c	optional wlan
 net80211/ieee80211_amrr.c	optional wlan wlan_amrr
 net80211/ieee80211_crypto.c	optional wlan
 net80211/ieee80211_crypto_ccmp.c optional wlan wlan_ccmp

Added: projects/mesh11s/sys/net80211/ieee80211_ageq.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/mesh11s/sys/net80211/ieee80211_ageq.c	Fri Jun 26 21:31:07 2009	(r195079)
@@ -0,0 +1,202 @@
+/*-
+ * 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>
+
+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 */
+}
+
+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 */
+}
+
+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);
+}
+
+void
+ieee80211_ageq_mfree(struct mbuf *m)
+{
+	struct mbuf *next;
+
+	for (; m != NULL; m = next) {
+		next = m->m_nextpkt;
+		ageq_mfree(m);
+	}
+}
+
+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;
+	}
+}
+
+void
+ieee80211_ageq_drain(struct ieee80211_ageq *aq)
+{
+	ieee80211_ageq_mfree(ieee80211_ageq_remove(aq, NULL));
+}
+
+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 stage queue.  We store ages as time
+ * deltas so we can check and/or adjust only the head of the list.
+ * If a frame's age exceeds the tick then discard it.
+ * The number of frames discarded is returned to the caller.
+ */
+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;
+}
+
+struct mbuf *
+ieee80211_ageq_remove(struct ieee80211_ageq *aq,
+	struct ieee80211_node *match)
+{
+	struct mbuf *m, **prev;
+	struct mbuf *head, **phead;
+
+	IEEE80211_AGEQ_LOCK(aq);
+	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;
+	}
+	/* XXX fix age */
+	IEEE80211_AGEQ_UNLOCK(aq);
+
+	*phead = NULL;
+	return head;
+}

Added: projects/mesh11s/sys/net80211/ieee80211_ageq.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/mesh11s/sys/net80211/ieee80211_ageq.h	Fri Jun 26 21:31:07 2009	(r195079)
@@ -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: projects/mesh11s/sys/net80211/ieee80211_freebsd.h
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_freebsd.h	Fri Jun 26 20:39:36 2009	(r195078)
+++ projects/mesh11s/sys/net80211/ieee80211_freebsd.h	Fri Jun 26 21:31:07 2009	(r195079)
@@ -100,19 +100,6 @@ 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. 
  */
@@ -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: projects/mesh11s/sys/net80211/ieee80211_hwmp.c
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_hwmp.c	Fri Jun 26 20:39:36 2009	(r195078)
+++ projects/mesh11s/sys/net80211/ieee80211_hwmp.c	Fri Jun 26 21:31:07 2009	(r195079)
@@ -804,7 +804,23 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 	 * update the proxy information table.
 	 */
 
-
+	if (fi != NULL) {
+		struct ieee80211com *ic = vap->iv_ic;
+		struct ifnet *ifp = vap->iv_ifp;
+		struct mbuf *m, *next;
+		/*
+		 * Check for frames queued awaiting path discovery.
+		 * XXX how can we tell 
+		 */
+		m = ieee80211_ageq_remove(&ic->ic_stageq, 
+		    (struct ieee80211_node *)(uintptr_t)
+			IEEE80211_NODE_HASH(fi->fi_dest));
+		for (; m != NULL; m = next) {
+			next = m->m_nextpkt;
+			m->m_nextpkt = NULL;
+			ifp->if_transmit(ifp, m);
+		}
+	}
 }
 
 static inline int
@@ -970,12 +986,13 @@ hwmp_send_rann(struct ieee80211_node *ni
 #define	PREQ_TSEQ(n)	preq.preq_targets[n].target_seq
 struct ieee80211_node *
 ieee80211_hwmp_discover(struct ieee80211vap *vap,
-    uint8_t dest[IEEE80211_ADDR_LEN])
+    uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
 {
 	struct ieee80211_mesh_state *ms = vap->iv_mesh;
 	struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
 	struct ieee80211_hwmp_fi *fi = NULL;
 	struct ieee80211_meshpreq_ie preq;
+	struct ieee80211_node *ni;
 	int sendpreq = 0, unknowndst = 0;
 
 	KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
@@ -984,56 +1001,81 @@ ieee80211_hwmp_discover(struct ieee80211
 	KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
 	    ("discovering self!"));
 
-	if (IEEE80211_IS_MULTICAST(dest))
-		return ieee80211_find_txnode(vap, dest);
-	fi = hwmp_rt_find(vap, dest);
-	if (fi == NULL) {
-		fi = hwmp_rt_add(vap, dest);
-		fi->fi_seq = ++hs->hs_seq;
-		fi->fi_preqid = ++hs->hs_preqid;
-		fi->fi_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
-		fi->fi_lifetime = timeval2msecs(ieee80211_hwmp_pathtimeout);
-		sendpreq = 1;
-		unknowndst = 1;
-	} else if (IEEE80211_ADDR_EQ(fi->fi_nexthop, invalidaddr)) {
-		/* XXX check preq retries */
-		sendpreq = 1;
-		unknowndst = 1;
+	ni = NULL;
+	if (!IEEE80211_IS_MULTICAST(dest)) {
+		fi = hwmp_rt_find(vap, dest);
+		if (fi == NULL) {
+			fi = hwmp_rt_add(vap, dest);
+			if (fi == NULL) {
+				/* XXX stat+msg */
+				goto done;
+			}
+			fi->fi_seq = ++hs->hs_seq;
+			fi->fi_preqid = ++hs->hs_preqid;
+			fi->fi_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
+			fi->fi_lifetime =
+			    timeval2msecs(ieee80211_hwmp_pathtimeout);
+			sendpreq = 1;
+			unknowndst = 1;
+		} else if (IEEE80211_ADDR_EQ(fi->fi_nexthop, invalidaddr)) {
+			/* XXX check preq retries */
+			sendpreq = 1;
+			unknowndst = 1;
+		}
+		if (sendpreq) {
+			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
+			    "%s", "initiating path discovery");
+			/*
+			 * Try to discover the path for this node.
+			 */
+			preq.preq_flags = 0;
+			preq.preq_hopcount = 0;
+			preq.preq_ttl = ms->ms_ttl;
+			preq.preq_id = fi->fi_preqid;
+			IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
+			preq.preq_origseq = fi->fi_seq;
+			preq.preq_lifetime = fi->fi_lifetime;
+			preq.preq_metric = fi->fi_metric;
+			preq.preq_tcount = 1;
+			IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
+			PREQ_TFLAGS(0) = 0;
+			if (ieee80211_hwmp_targetonly)
+				PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
+			if (ieee80211_hwmp_replyforward)
+				PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
+			if (unknowndst) {
+				PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
+				PREQ_TSEQ(0) = 0;
+			} else
+				PREQ_TSEQ(0) = fi->fi_seq;
+			/* XXX check return value */
+			hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
+			    broadcastaddr, &preq);
+		}
+		if (!IEEE80211_ADDR_EQ(fi->fi_nexthop, invalidaddr))
+			ni = ieee80211_find_txnode(vap, fi->fi_nexthop);
+	} else {
+		ni = ieee80211_find_txnode(vap, dest);
 	}
-	if (sendpreq) {
-		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
-		    "%s", "initiating path discovery");
-		/*
-		 * Try to discover the path for this node.
-		 */
-		preq.preq_flags = 0;
-		preq.preq_hopcount = 0;
-		preq.preq_ttl = ms->ms_ttl;
-		preq.preq_id = fi->fi_preqid;
-		IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
-		preq.preq_origseq = fi->fi_seq;
-		preq.preq_lifetime = fi->fi_lifetime;
-		preq.preq_metric = fi->fi_metric;
-		preq.preq_tcount = 1;
-		IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
-		PREQ_TFLAGS(0) = 0;
-		if (ieee80211_hwmp_targetonly)
-			PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
-		if (ieee80211_hwmp_replyforward)
-			PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
-		if (unknowndst) {
-			PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
-			PREQ_TSEQ(0) = 0;
+done:
+	if (ni == NULL && m != NULL) {
+		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
+		    dest, NULL, "%s", "no valid path to this node");
+		if (sendpreq) {
+			/*
+			 * Queue packet for transmit when path discovery
+			 * completes.  If discovery never completes the
+			 * frame will be flushed by way of the aging timer.
+			 */
+			m->m_pkthdr.rcvif = (void *)(uintptr_t)
+			    IEEE80211_NODE_HASH(dest);
+			/* XXX age chosen randomly */
+			ieee80211_ageq_append(&vap->iv_ic->ic_stageq, m,
+			    IEEE80211_INACT_WAIT);
 		} else
-			PREQ_TSEQ(0) = fi->fi_seq;
-		hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
-		    &preq);
+			m_freem(m);
 	}
-	if (!IEEE80211_ADDR_EQ(fi->fi_nexthop, invalidaddr))
-		return ieee80211_find_txnode(vap, fi->fi_nexthop);
-	IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
-	    dest, NULL, "%s", "no valid path to this node");
-	return NULL;
+	return ni;
 }
 #undef	PREQ_TFLAGS
 #undef	PREQ_TADDR

Modified: projects/mesh11s/sys/net80211/ieee80211_hwmp.h
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_hwmp.h	Fri Jun 26 20:39:36 2009	(r195078)
+++ projects/mesh11s/sys/net80211/ieee80211_hwmp.h	Fri Jun 26 21:31:07 2009	(r195079)
@@ -72,9 +72,8 @@ int	ieee80211_hwmp_newstate(struct ieee8
     int);
 void	ieee80211_hwmp_recv_action(struct ieee80211vap *,
     struct ieee80211_node *, struct mbuf *);
-struct ieee80211_node *
-	ieee80211_hwmp_discover(struct ieee80211vap *,
-    uint8_t [IEEE80211_ADDR_LEN]);
+struct ieee80211_node *ieee80211_hwmp_discover(struct ieee80211vap *,
+    uint8_t [IEEE80211_ADDR_LEN], struct mbuf *);
 struct ieee80211_node *
 ieee80211_hwmp_find_txnode(struct ieee80211vap *vap,
     uint8_t dest[IEEE80211_ADDR_LEN]);

Modified: projects/mesh11s/sys/net80211/ieee80211_node.c
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_node.c	Fri Jun 26 20:39:36 2009	(r195078)
+++ projects/mesh11s/sys/net80211/ieee80211_node.c	Fri Jun 26 21:31:07 2009	(r195079)
@@ -100,6 +100,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);
@@ -128,6 +131,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
@@ -932,6 +936,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 */
@@ -952,6 +957,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
@@ -1004,7 +1014,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);
 }
 
@@ -1022,11 +1031,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).
 	 */
@@ -1091,7 +1095,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);
@@ -1141,7 +1144,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++;
@@ -2087,6 +2089,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: projects/mesh11s/sys/net80211/ieee80211_node.h
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_node.h	Fri Jun 26 20:39:36 2009	(r195078)
+++ projects/mesh11s/sys/net80211/ieee80211_node.h	Fri Jun 26 21:31:07 2009	(r195079)
@@ -217,8 +217,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: projects/mesh11s/sys/net80211/ieee80211_output.c
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_output.c	Fri Jun 26 20:39:36 2009	(r195078)
+++ projects/mesh11s/sys/net80211/ieee80211_output.c	Fri Jun 26 21:31:07 2009	(r195079)
@@ -212,27 +212,36 @@ ieee80211_start(struct ifnet *ifp)
 				ieee80211_dwds_mcast(vap, m);
 			}
 		}
-		if (vap->iv_opmode == IEEE80211_M_MBSS)
-			ni = ieee80211_hwmp_discover(vap, eh->ether_dhost);
-		else
+		if (vap->iv_opmode != IEEE80211_M_MBSS) {
 			ni = ieee80211_find_txnode(vap, eh->ether_dhost);
-		if (ni == NULL) {
-			/* NB: ieee80211_find_txnode does stat+msg */
-			ifp->if_oerrors++;
-			m_freem(m);
-			continue;
-		}
-		if (ni->ni_associd == 0 &&
-		    (ni->ni_flags & IEEE80211_NODE_ASSOCID)) {
-			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
-			    eh->ether_dhost, NULL,
-			    "sta not associated (type 0x%04x)",
-			    htons(eh->ether_type));
-			vap->iv_stats.is_tx_notassoc++;
-			ifp->if_oerrors++;
-			m_freem(m);
-			ieee80211_free_node(ni);
-			continue;
+			if (ni == NULL) {
+				/* NB: ieee80211_find_txnode does stat+msg */
+				ifp->if_oerrors++;
+				m_freem(m);
+				continue;
+			}
+			if (ni->ni_associd == 0 &&
+			    (ni->ni_flags & IEEE80211_NODE_ASSOCID)) {
+				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
+				    eh->ether_dhost, NULL,
+				    "sta not associated (type 0x%04x)",
+				    htons(eh->ether_type));
+				vap->iv_stats.is_tx_notassoc++;
+				ifp->if_oerrors++;
+				m_freem(m);
+				ieee80211_free_node(ni);
+				continue;
+			}
+		} else {
+			ni = ieee80211_hwmp_discover(vap, eh->ether_dhost, m);
+			if (ni == NULL) {
+				/*
+				 * NB: ieee80211_hwmp_discover holds/disposes
+				 *     frame (e.g. queueing on path discovery.
+				 */
+				ifp->if_oerrors++;
+				continue;
+			}
 		}
 
 		if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&

Modified: projects/mesh11s/sys/net80211/ieee80211_var.h
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_var.h	Fri Jun 26 20:39:36 2009	(r195078)
+++ projects/mesh11s/sys/net80211/ieee80211_var.h	Fri Jun 26 21:31:07 2009	(r195079)
@@ -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 */
@@ -193,6 +194,7 @@ 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 */
 
 	/* XXX multi-bss: split out common/vap parts */
 	struct ieee80211_wme_state ic_wme;	/* WME/WMM state */

Modified: projects/mesh11s/sys/net80211/ieee80211_wds.c
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_wds.c	Fri Jun 26 20:39:36 2009	(r195078)
+++ projects/mesh11s/sys/net80211/ieee80211_wds.c	Fri Jun 26 21:31:07 2009	(r195079)
@@ -97,6 +97,27 @@ 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, ni);
+	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 +216,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 +315,22 @@ 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?
+	 */
+	(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-projects mailing list