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)
This commit is contained in:
parent
96831ae59b
commit
5b16c28c42
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195379
@ -268,6 +268,7 @@ ieee80211_ifattach(struct ieee80211com *ic,
|
||||
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
|
||||
|
236
sys/net80211/ieee80211_ageq.c
Normal file
236
sys/net80211/ieee80211_ageq.c
Normal file
@ -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;
|
||||
}
|
54
sys/net80211/ieee80211_ageq.h
Normal file
54
sys/net80211/ieee80211_ageq.h
Normal file
@ -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_ */
|
@ -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)
|
||||
@ -138,23 +125,15 @@ typedef struct mtx ieee80211_psq_lock_t;
|
||||
} 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.
|
||||
|
@ -99,6 +99,9 @@ MALLOC_DEFINE(M_80211_NODE_IE, "80211nodeie", "802.11 node ie");
|
||||
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 ieee80211com *ic)
|
||||
|
||||
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 */
|
||||
@ -946,6 +951,11 @@ node_cleanup(struct ieee80211_node *ni)
|
||||
else if (ni->ni_ath_flags & IEEE80211_NODE_ATH)
|
||||
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
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -1016,11 +1025,6 @@ node_age(struct ieee80211_node *ni)
|
||||
if (ieee80211_node_psq_age(ni) != 0 &&
|
||||
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_node_table *nt,
|
||||
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 *vap,
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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_channel_byieee(struct ieee80211com *,
|
||||
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,
|
||||
|
@ -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 *vap, struct ieee80211_channel *chan)
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,90 +316,23 @@ ieee80211_dwds_mcast(struct ieee80211vap *vap0, struct mbuf *m)
|
||||
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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user