Index: sys/net80211/ieee80211_node.h =================================================================== --- sys/net80211/ieee80211_node.h +++ sys/net80211/ieee80211_node.h @@ -356,6 +356,7 @@ 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 */ @@ -441,8 +442,8 @@ 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 *); Index: sys/net80211/ieee80211_node.c =================================================================== --- sys/net80211/ieee80211_node.c +++ sys/net80211/ieee80211_node.c @@ -1158,13 +1158,44 @@ /* 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) { @@ -1177,7 +1208,6 @@ 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; @@ -1194,9 +1224,7 @@ 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); @@ -1759,10 +1787,8 @@ 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); } @@ -1901,9 +1927,7 @@ * 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); } @@ -1921,6 +1945,7 @@ 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; @@ -2205,117 +2230,68 @@ } /* - * 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]); - } + for (i = 0; i < count; i++) { + if (ni_arr[i] == NULL) /* end of the list */ + break; + (*f)(arg, ni_arr[i]); + /* ieee80211_free_node() locks by itself */ + ieee80211_free_node(ni_arr[i]); } - return (ret); + 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. - * - * 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++) { - if (ni_arr[i] == NULL) /* end of the list */ - break; - (*f)(arg, ni_arr[i]); - /* ieee80211_free_node() locks by itself */ - ieee80211_free_node(ni_arr[i]); - } - -done: - IEEE80211_FREE(ni_arr, M_80211_NODE); + /* XXX no way to pass error to the caller. */ + (void) ieee80211_iterate_nodes_vap(nt, NULL, f, arg); } void