net80211: add one-vap version of ieee80211_iterate_nodes()
- Add a counter into 'struct ieee80211_node_table' to save current number of allocated nodes. (allows to remove array overflow checking in ieee80211_iterate_nodes()). - Add ieee80211_iterate_nodes_vap() function; unlike non-vap version, it iterates on nodes for specified vap only. In addition to the above: - Remove ieee80211_iterate_nt(); it is not used by drivers / net80211 outside ieee80211_iterate_nodes() function + cannot be separated due to structural changes in code. Since size of 'struct ieee80211_node_table' (part of ieee80211com, which is a part of driver's softc) is changed all wireless drivers / kernel need to be recompiled. Tested with wpi(4), STA mode. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D7996
This commit is contained in:
parent
604d83bdce
commit
d2e877f0fa
@ -1214,13 +1214,44 @@ node_getmimoinfo(const struct ieee80211_node *ni,
|
||||
/* XXX EVM? */
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_add_node_nt(struct ieee80211_node_table *nt,
|
||||
struct ieee80211_node *ni)
|
||||
{
|
||||
struct ieee80211com *ic = nt->nt_ic;
|
||||
int hash;
|
||||
|
||||
IEEE80211_NODE_LOCK_ASSERT(nt);
|
||||
|
||||
hash = IEEE80211_NODE_HASH(ic, ni->ni_macaddr);
|
||||
(void) ic; /* XXX IEEE80211_NODE_HASH */
|
||||
TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
|
||||
LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
|
||||
nt->nt_count++;
|
||||
ni->ni_table = nt;
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_del_node_nt(struct ieee80211_node_table *nt,
|
||||
struct ieee80211_node *ni)
|
||||
{
|
||||
|
||||
IEEE80211_NODE_LOCK_ASSERT(nt);
|
||||
|
||||
TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
|
||||
LIST_REMOVE(ni, ni_hash);
|
||||
nt->nt_count--;
|
||||
KASSERT(nt->nt_count >= 0,
|
||||
("nt_count is negative (%d)!\n", nt->nt_count));
|
||||
ni->ni_table = NULL;
|
||||
}
|
||||
|
||||
struct ieee80211_node *
|
||||
ieee80211_alloc_node(struct ieee80211_node_table *nt,
|
||||
struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN])
|
||||
{
|
||||
struct ieee80211com *ic = nt->nt_ic;
|
||||
struct ieee80211_node *ni;
|
||||
int hash;
|
||||
|
||||
ni = ic->ic_node_alloc(vap, macaddr);
|
||||
if (ni == NULL) {
|
||||
@ -1233,7 +1264,6 @@ ieee80211_alloc_node(struct ieee80211_node_table *nt,
|
||||
ether_sprintf(macaddr), nt->nt_name);
|
||||
|
||||
IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
|
||||
hash = IEEE80211_NODE_HASH(ic, macaddr);
|
||||
ieee80211_node_initref(ni); /* mark referenced */
|
||||
ni->ni_chan = IEEE80211_CHAN_ANYC;
|
||||
ni->ni_authmode = IEEE80211_AUTH_OPEN;
|
||||
@ -1250,9 +1280,7 @@ ieee80211_alloc_node(struct ieee80211_node_table *nt,
|
||||
ieee80211_mesh_node_init(vap, ni);
|
||||
#endif
|
||||
IEEE80211_NODE_LOCK(nt);
|
||||
TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
|
||||
LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
|
||||
ni->ni_table = nt;
|
||||
ieee80211_add_node_nt(nt, ni);
|
||||
ni->ni_vap = vap;
|
||||
ni->ni_ic = ic;
|
||||
IEEE80211_NODE_UNLOCK(nt);
|
||||
@ -1815,10 +1843,8 @@ _ieee80211_free_node(struct ieee80211_node *ni)
|
||||
if (vap->iv_aid_bitmap != NULL)
|
||||
IEEE80211_AID_CLR(vap, ni->ni_associd);
|
||||
}
|
||||
if (nt != NULL) {
|
||||
TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
|
||||
LIST_REMOVE(ni, ni_hash);
|
||||
}
|
||||
if (nt != NULL)
|
||||
ieee80211_del_node_nt(nt, ni);
|
||||
ni->ni_ic->ic_node_free(ni);
|
||||
}
|
||||
|
||||
@ -1957,9 +1983,7 @@ node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
|
||||
* the references are dropped storage will be
|
||||
* reclaimed.
|
||||
*/
|
||||
TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
|
||||
LIST_REMOVE(ni, ni_hash);
|
||||
ni->ni_table = NULL; /* clear reference */
|
||||
ieee80211_del_node_nt(nt, ni);
|
||||
} else
|
||||
_ieee80211_free_node(ni);
|
||||
}
|
||||
@ -1977,6 +2001,7 @@ ieee80211_node_table_init(struct ieee80211com *ic,
|
||||
nt->nt_ic = ic;
|
||||
IEEE80211_NODE_LOCK_INIT(nt, ic->ic_name);
|
||||
TAILQ_INIT(&nt->nt_node);
|
||||
nt->nt_count = 0;
|
||||
nt->nt_name = name;
|
||||
nt->nt_inact_init = inact;
|
||||
nt->nt_keyixmax = keyixmax;
|
||||
@ -2261,108 +2286,46 @@ ieee80211_node_timeout(void *arg)
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over the node table and return an array of ref'ed nodes.
|
||||
*
|
||||
* This is separated out from calling the actual node function so that
|
||||
* no LORs will occur.
|
||||
*
|
||||
* If there are too many nodes (ie, the number of nodes doesn't fit
|
||||
* within 'max_aid' entries) then the node references will be freed
|
||||
* and an error will be returned.
|
||||
*
|
||||
* The responsibility of allocating and freeing "ni_arr" is up to
|
||||
* the caller.
|
||||
* The same as ieee80211_iterate_nodes(), but for one vap only.
|
||||
*/
|
||||
int
|
||||
ieee80211_iterate_nt(struct ieee80211_node_table *nt,
|
||||
struct ieee80211_node **ni_arr, uint16_t max_aid)
|
||||
ieee80211_iterate_nodes_vap(struct ieee80211_node_table *nt,
|
||||
struct ieee80211vap *vap, ieee80211_iter_func *f, void *arg)
|
||||
{
|
||||
int i, j, ret;
|
||||
struct ieee80211_node **ni_arr;
|
||||
struct ieee80211_node *ni;
|
||||
size_t size;
|
||||
int count, i;
|
||||
|
||||
/*
|
||||
* Iterate over the node table and save an array of ref'ed nodes.
|
||||
*
|
||||
* This is separated out from calling the actual node function so that
|
||||
* no LORs will occur.
|
||||
*/
|
||||
IEEE80211_NODE_LOCK(nt);
|
||||
count = nt->nt_count;
|
||||
size = count * sizeof(struct ieee80211_node *);
|
||||
ni_arr = (struct ieee80211_node **) IEEE80211_MALLOC(size, M_80211_NODE,
|
||||
IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
|
||||
if (ni_arr == NULL) {
|
||||
IEEE80211_NODE_UNLOCK(nt);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
i = ret = 0;
|
||||
i = 0;
|
||||
TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
|
||||
if (i >= max_aid) {
|
||||
ret = E2BIG;
|
||||
ic_printf(nt->nt_ic, "Node array overflow: max=%u",
|
||||
max_aid);
|
||||
break;
|
||||
}
|
||||
if (vap != NULL && ni->ni_vap != vap)
|
||||
continue;
|
||||
KASSERT(i < count,
|
||||
("node array overflow (vap %p, i %d, count %d)\n",
|
||||
vap, i, count));
|
||||
ni_arr[i] = ieee80211_ref_node(ni);
|
||||
i++;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's safe to unlock here.
|
||||
*
|
||||
* If we're successful, the list is returned.
|
||||
* If we're unsuccessful, the list is ignored
|
||||
* and we remove our references.
|
||||
*
|
||||
* This avoids any potential LOR with
|
||||
* ieee80211_free_node().
|
||||
*/
|
||||
IEEE80211_NODE_UNLOCK(nt);
|
||||
|
||||
/*
|
||||
* If ret is non-zero, we hit some kind of error.
|
||||
* Rather than walking some nodes, we'll walk none
|
||||
* of them.
|
||||
*/
|
||||
if (ret) {
|
||||
for (j = 0; j < i; j++) {
|
||||
/* ieee80211_free_node() locks by itself */
|
||||
ieee80211_free_node(ni_arr[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just a wrapper, so we don't have to change every ieee80211_iterate_nodes()
|
||||
* reference in the source.
|
||||
*
|
||||
* Note that this fetches 'max_aid' from the first VAP, rather than finding
|
||||
* the largest max_aid from all VAPs.
|
||||
*/
|
||||
void
|
||||
ieee80211_iterate_nodes(struct ieee80211_node_table *nt,
|
||||
ieee80211_iter_func *f, void *arg)
|
||||
{
|
||||
struct ieee80211_node **ni_arr;
|
||||
size_t size;
|
||||
int i;
|
||||
uint16_t max_aid;
|
||||
struct ieee80211vap *vap;
|
||||
|
||||
/* Overdoing it default */
|
||||
max_aid = IEEE80211_AID_MAX;
|
||||
|
||||
/* Handle the case of there being no vaps just yet */
|
||||
vap = TAILQ_FIRST(&nt->nt_ic->ic_vaps);
|
||||
if (vap != NULL)
|
||||
max_aid = vap->iv_max_aid;
|
||||
|
||||
size = max_aid * sizeof(struct ieee80211_node *);
|
||||
ni_arr = (struct ieee80211_node **) IEEE80211_MALLOC(size, M_80211_NODE,
|
||||
IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
|
||||
if (ni_arr == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If this fails, the node table won't have any
|
||||
* valid entries - ieee80211_iterate_nt() frees
|
||||
* the references to them. So don't try walking
|
||||
* the table; just skip to the end and free the
|
||||
* temporary memory.
|
||||
*/
|
||||
if (ieee80211_iterate_nt(nt, ni_arr, max_aid) != 0)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < max_aid; i++) {
|
||||
for (i = 0; i < count; i++) {
|
||||
if (ni_arr[i] == NULL) /* end of the list */
|
||||
break;
|
||||
(*f)(arg, ni_arr[i]);
|
||||
@ -2370,8 +2333,21 @@ ieee80211_iterate_nodes(struct ieee80211_node_table *nt,
|
||||
ieee80211_free_node(ni_arr[i]);
|
||||
}
|
||||
|
||||
done:
|
||||
IEEE80211_FREE(ni_arr, M_80211_NODE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just a wrapper, so we don't have to change every ieee80211_iterate_nodes()
|
||||
* reference in the source.
|
||||
*/
|
||||
void
|
||||
ieee80211_iterate_nodes(struct ieee80211_node_table *nt,
|
||||
ieee80211_iter_func *f, void *arg)
|
||||
{
|
||||
/* XXX no way to pass error to the caller. */
|
||||
(void) ieee80211_iterate_nodes_vap(nt, NULL, f, arg);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -359,6 +359,7 @@ struct ieee80211_node_table {
|
||||
ieee80211_node_lock_t nt_nodelock; /* on node table */
|
||||
TAILQ_HEAD(, ieee80211_node) nt_node; /* information of all nodes */
|
||||
LIST_HEAD(, ieee80211_node) nt_hash[IEEE80211_NODE_HASHSIZE];
|
||||
int nt_count; /* number of nodes */
|
||||
struct ieee80211_node **nt_keyixmap; /* key ix -> node map */
|
||||
int nt_keyixmax; /* keyixmap size */
|
||||
const char *nt_name; /* table name for debug msgs */
|
||||
@ -444,8 +445,8 @@ int ieee80211_node_delucastkey(struct ieee80211_node *);
|
||||
void ieee80211_node_timeout(void *arg);
|
||||
|
||||
typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
|
||||
int ieee80211_iterate_nt(struct ieee80211_node_table *,
|
||||
struct ieee80211_node **, uint16_t);
|
||||
int ieee80211_iterate_nodes_vap(struct ieee80211_node_table *,
|
||||
struct ieee80211vap *, ieee80211_iter_func *, void *);
|
||||
void ieee80211_iterate_nodes(struct ieee80211_node_table *,
|
||||
ieee80211_iter_func *, void *);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user