Changeset View
Changeset View
Standalone View
Standalone View
head/sys/net80211/ieee80211_node.c
Show First 20 Lines • Show All 1,208 Lines • ▼ Show 20 Lines | for (i = 0; i < ni->ni_mimo_chains; i++) { | ||||
info->noise[i] = ni->ni_mimo_noise_ctl[i]; | info->noise[i] = ni->ni_mimo_noise_ctl[i]; | ||||
} | } | ||||
/* XXX ext radios? */ | /* XXX ext radios? */ | ||||
/* XXX EVM? */ | /* 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 * | struct ieee80211_node * | ||||
ieee80211_alloc_node(struct ieee80211_node_table *nt, | ieee80211_alloc_node(struct ieee80211_node_table *nt, | ||||
struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN]) | struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN]) | ||||
{ | { | ||||
struct ieee80211com *ic = nt->nt_ic; | struct ieee80211com *ic = nt->nt_ic; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
int hash; | |||||
ni = ic->ic_node_alloc(vap, macaddr); | ni = ic->ic_node_alloc(vap, macaddr); | ||||
if (ni == NULL) { | if (ni == NULL) { | ||||
vap->iv_stats.is_rx_nodealloc++; | vap->iv_stats.is_rx_nodealloc++; | ||||
return NULL; | return NULL; | ||||
} | } | ||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, | IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, | ||||
"%s %p<%s> in %s table\n", __func__, ni, | "%s %p<%s> in %s table\n", __func__, ni, | ||||
ether_sprintf(macaddr), nt->nt_name); | ether_sprintf(macaddr), nt->nt_name); | ||||
IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); | IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); | ||||
hash = IEEE80211_NODE_HASH(ic, macaddr); | |||||
ieee80211_node_initref(ni); /* mark referenced */ | ieee80211_node_initref(ni); /* mark referenced */ | ||||
ni->ni_chan = IEEE80211_CHAN_ANYC; | ni->ni_chan = IEEE80211_CHAN_ANYC; | ||||
ni->ni_authmode = IEEE80211_AUTH_OPEN; | ni->ni_authmode = IEEE80211_AUTH_OPEN; | ||||
ni->ni_txpower = ic->ic_txpowlimit; /* max power */ | ni->ni_txpower = ic->ic_txpowlimit; /* max power */ | ||||
ni->ni_txparms = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; | ni->ni_txparms = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; | ||||
ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); | ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); | ||||
ni->ni_avgrssi = IEEE80211_RSSI_DUMMY_MARKER; | ni->ni_avgrssi = IEEE80211_RSSI_DUMMY_MARKER; | ||||
ni->ni_inact_reload = nt->nt_inact_init; | ni->ni_inact_reload = nt->nt_inact_init; | ||||
ni->ni_inact = ni->ni_inact_reload; | ni->ni_inact = ni->ni_inact_reload; | ||||
ni->ni_ath_defkeyix = 0x7fff; | ni->ni_ath_defkeyix = 0x7fff; | ||||
ieee80211_psq_init(&ni->ni_psq, "unknown"); | ieee80211_psq_init(&ni->ni_psq, "unknown"); | ||||
#ifdef IEEE80211_SUPPORT_MESH | #ifdef IEEE80211_SUPPORT_MESH | ||||
if (vap->iv_opmode == IEEE80211_M_MBSS) | if (vap->iv_opmode == IEEE80211_M_MBSS) | ||||
ieee80211_mesh_node_init(vap, ni); | ieee80211_mesh_node_init(vap, ni); | ||||
#endif | #endif | ||||
IEEE80211_NODE_LOCK(nt); | IEEE80211_NODE_LOCK(nt); | ||||
TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); | ieee80211_add_node_nt(nt, ni); | ||||
LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); | |||||
ni->ni_table = nt; | |||||
ni->ni_vap = vap; | ni->ni_vap = vap; | ||||
ni->ni_ic = ic; | ni->ni_ic = ic; | ||||
IEEE80211_NODE_UNLOCK(nt); | IEEE80211_NODE_UNLOCK(nt); | ||||
IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, | IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, | ||||
"%s: inact_reload %u", __func__, ni->ni_inact_reload); | "%s: inact_reload %u", __func__, ni->ni_inact_reload); | ||||
ieee80211_ratectl_node_init(ni); | ieee80211_ratectl_node_init(ni); | ||||
▲ Show 20 Lines • Show All 546 Lines • ▼ Show 20 Lines | IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, | ||||
ether_sprintf(ni->ni_macaddr), | ether_sprintf(ni->ni_macaddr), | ||||
nt != NULL ? nt->nt_name : "<gone>"); | nt != NULL ? nt->nt_name : "<gone>"); | ||||
#endif | #endif | ||||
if (ni->ni_associd != 0) { | if (ni->ni_associd != 0) { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
if (vap->iv_aid_bitmap != NULL) | if (vap->iv_aid_bitmap != NULL) | ||||
IEEE80211_AID_CLR(vap, ni->ni_associd); | IEEE80211_AID_CLR(vap, ni->ni_associd); | ||||
} | } | ||||
if (nt != NULL) { | if (nt != NULL) | ||||
TAILQ_REMOVE(&nt->nt_node, ni, ni_list); | ieee80211_del_node_nt(nt, ni); | ||||
LIST_REMOVE(ni, ni_hash); | |||||
} | |||||
ni->ni_ic->ic_node_free(ni); | ni->ni_ic->ic_node_free(ni); | ||||
} | } | ||||
/* | /* | ||||
* Clear any entry in the unicast key mapping table. | * Clear any entry in the unicast key mapping table. | ||||
*/ | */ | ||||
static int | static int | ||||
node_clear_keyixmap(struct ieee80211_node_table *nt, struct ieee80211_node *ni) | node_clear_keyixmap(struct ieee80211_node_table *nt, struct ieee80211_node *ni) | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) | ||||
(void)node_clear_keyixmap(nt, ni); | (void)node_clear_keyixmap(nt, ni); | ||||
if (!ieee80211_node_dectestref(ni)) { | if (!ieee80211_node_dectestref(ni)) { | ||||
/* | /* | ||||
* Other references are present, just remove the | * Other references are present, just remove the | ||||
* node from the table so it cannot be found. When | * node from the table so it cannot be found. When | ||||
* the references are dropped storage will be | * the references are dropped storage will be | ||||
* reclaimed. | * reclaimed. | ||||
*/ | */ | ||||
TAILQ_REMOVE(&nt->nt_node, ni, ni_list); | ieee80211_del_node_nt(nt, ni); | ||||
LIST_REMOVE(ni, ni_hash); | |||||
ni->ni_table = NULL; /* clear reference */ | |||||
} else | } else | ||||
_ieee80211_free_node(ni); | _ieee80211_free_node(ni); | ||||
} | } | ||||
/* | /* | ||||
* Node table support. | * Node table support. | ||||
*/ | */ | ||||
static void | static void | ||||
ieee80211_node_table_init(struct ieee80211com *ic, | ieee80211_node_table_init(struct ieee80211com *ic, | ||||
struct ieee80211_node_table *nt, | struct ieee80211_node_table *nt, | ||||
const char *name, int inact, int keyixmax) | const char *name, int inact, int keyixmax) | ||||
{ | { | ||||
nt->nt_ic = ic; | nt->nt_ic = ic; | ||||
IEEE80211_NODE_LOCK_INIT(nt, ic->ic_name); | IEEE80211_NODE_LOCK_INIT(nt, ic->ic_name); | ||||
TAILQ_INIT(&nt->nt_node); | TAILQ_INIT(&nt->nt_node); | ||||
nt->nt_count = 0; | |||||
nt->nt_name = name; | nt->nt_name = name; | ||||
nt->nt_inact_init = inact; | nt->nt_inact_init = inact; | ||||
nt->nt_keyixmax = keyixmax; | nt->nt_keyixmax = keyixmax; | ||||
if (nt->nt_keyixmax > 0) { | if (nt->nt_keyixmax > 0) { | ||||
nt->nt_keyixmap = (struct ieee80211_node **) IEEE80211_MALLOC( | nt->nt_keyixmap = (struct ieee80211_node **) IEEE80211_MALLOC( | ||||
keyixmax * sizeof(struct ieee80211_node *), | keyixmax * sizeof(struct ieee80211_node *), | ||||
M_80211_NODE, | M_80211_NODE, | ||||
IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); | IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); | ||||
▲ Show 20 Lines • Show All 268 Lines • ▼ Show 20 Lines | if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) { | ||||
ieee80211_ht_timeout(ic); | ieee80211_ht_timeout(ic); | ||||
IEEE80211_UNLOCK(ic); | IEEE80211_UNLOCK(ic); | ||||
} | } | ||||
callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, | callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, | ||||
ieee80211_node_timeout, ic); | ieee80211_node_timeout, ic); | ||||
} | } | ||||
/* | /* | ||||
* Iterate over the node table and return an array of ref'ed nodes. | * The same as ieee80211_iterate_nodes(), but for one vap only. | ||||
* | |||||
* 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. | |||||
*/ | */ | ||||
int | int | ||||
ieee80211_iterate_nt(struct ieee80211_node_table *nt, | ieee80211_iterate_nodes_vap(struct ieee80211_node_table *nt, | ||||
struct ieee80211_node **ni_arr, uint16_t max_aid) | struct ieee80211vap *vap, ieee80211_iter_func *f, void *arg) | ||||
{ | { | ||||
int i, j, ret; | struct ieee80211_node **ni_arr; | ||||
struct ieee80211_node *ni; | 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); | 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) { | TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { | ||||
if (i >= max_aid) { | if (vap != NULL && ni->ni_vap != vap) | ||||
ret = E2BIG; | continue; | ||||
ic_printf(nt->nt_ic, "Node array overflow: max=%u", | KASSERT(i < count, | ||||
max_aid); | ("node array overflow (vap %p, i %d, count %d)\n", | ||||
break; | vap, i, count)); | ||||
} | |||||
ni_arr[i] = ieee80211_ref_node(ni); | ni_arr[i] = ieee80211_ref_node(ni); | ||||
i++; | 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); | IEEE80211_NODE_UNLOCK(nt); | ||||
/* | for (i = 0; i < count; i++) { | ||||
* If ret is non-zero, we hit some kind of error. | if (ni_arr[i] == NULL) /* end of the list */ | ||||
* Rather than walking some nodes, we'll walk none | break; | ||||
* of them. | (*f)(arg, ni_arr[i]); | ||||
*/ | |||||
if (ret) { | |||||
for (j = 0; j < i; j++) { | |||||
/* ieee80211_free_node() locks by itself */ | /* ieee80211_free_node() locks by itself */ | ||||
ieee80211_free_node(ni_arr[j]); | 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() | * Just a wrapper, so we don't have to change every ieee80211_iterate_nodes() | ||||
* reference in the source. | * 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 | void | ||||
ieee80211_iterate_nodes(struct ieee80211_node_table *nt, | ieee80211_iterate_nodes(struct ieee80211_node_table *nt, | ||||
ieee80211_iter_func *f, void *arg) | ieee80211_iter_func *f, void *arg) | ||||
{ | { | ||||
struct ieee80211_node **ni_arr; | /* XXX no way to pass error to the caller. */ | ||||
size_t size; | (void) ieee80211_iterate_nodes_vap(nt, NULL, f, arg); | ||||
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); | |||||
} | } | ||||
void | void | ||||
ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) | ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) | ||||
{ | { | ||||
printf("0x%p: mac %s refcnt %d\n", ni, | printf("0x%p: mac %s refcnt %d\n", ni, | ||||
ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); | ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); | ||||
printf("\tauthmode %u flags 0x%x\n", | printf("\tauthmode %u flags 0x%x\n", | ||||
▲ Show 20 Lines • Show All 472 Lines • Show Last 20 Lines |