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