Date: Fri, 26 Jun 2009 21:31:07 +0000 (UTC) From: Sam Leffler <sam@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r195079 - in projects/mesh11s/sys: conf net80211 Message-ID: <200906262131.n5QLV7Dk005490@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906262131.n5QLV7Dk005490>