nl80211: Use valid_links bitmask for bss->links array

Most places in the codebase use a valid_links bitmask with an array.
Switch the bss->links array to use the same design with the Link ID
being used as the array index instead of having a link_id inside.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
This commit is contained in:
Benjamin Berg 2024-02-20 14:18:14 +01:00 committed by Jouni Malinen
parent 9ed51186e8
commit 0d4288a005
4 changed files with 112 additions and 142 deletions

View file

@ -2289,7 +2289,6 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
{
struct wpa_driver_nl80211_data *drv;
struct i802_bss *bss;
unsigned int i;
char path[128], buf[200], *pos;
ssize_t len;
int ret;
@ -2389,16 +2388,12 @@ skip_wifi_status:
}
/*
* Set the default link to be the first one, and set its address to that
* of the interface.
* Use link ID 0 for the single "link" of a non-MLD.
*/
bss->valid_links = 0;
bss->flink = &bss->links[0];
bss->n_links = 1;
os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
bss->links[i].link_id = NL80211_DRV_LINK_ID_NA;
return bss;
failed:
@ -3073,10 +3068,11 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss,
struct i802_link *link)
int link_id)
{
struct nl_msg *msg;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct i802_link *link = nl80211_get_link(bss, link_id);
if (!link->beacon_set)
return 0;
@ -3091,13 +3087,12 @@ static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss,
if (!msg)
return -ENOBUFS;
if (link->link_id != NL80211_DRV_LINK_ID_NA) {
if (link_id != NL80211_DRV_LINK_ID_NA) {
wpa_printf(MSG_DEBUG,
"nl80211: MLD: stop beaconing on link=%u",
link->link_id);
link_id);
if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
link->link_id)) {
if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
nlmsg_free(msg);
return -ENOBUFS;
}
@ -3109,10 +3104,10 @@ static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss,
static void wpa_driver_nl80211_del_beacon_all(struct i802_bss *bss)
{
unsigned int i;
int link_id;
for (i = 0; i < bss->n_links; i++)
wpa_driver_nl80211_del_beacon(bss, &bss->links[i]);
for_each_link_default(bss->valid_links, link_id, NL80211_DRV_LINK_ID_NA)
wpa_driver_nl80211_del_beacon(bss, link_id);
}
@ -4193,14 +4188,11 @@ int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id)
{
unsigned int i;
if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS)
return bss->flink;
for (i = 0; i < bss->n_links; i++) {
if (bss->links[i].link_id != link_id)
continue;
return &bss->links[i];
}
if (BIT(link_id) & bss->valid_links)
return &bss->links[link_id];
return bss->flink;
}
@ -4217,9 +4209,9 @@ static void nl80211_link_set_freq(struct i802_bss *bss, s8 link_id, int freq)
static int nl80211_get_link_freq(struct i802_bss *bss, const u8 *addr,
bool bss_freq_debug)
{
size_t i;
u8 i;
for (i = 0; i < bss->n_links; i++) {
for_each_link(bss->valid_links, i) {
if (ether_addr_equal(bss->links[i].addr, addr)) {
wpa_printf(MSG_DEBUG,
"nl80211: Use link freq=%d for address "
@ -5060,20 +5052,18 @@ static int wpa_driver_nl80211_set_ap(void *priv,
#endif /* CONFIG_MESH */
if (params->mld_ap) {
size_t i;
for (i = 0; i < bss->n_links; i++) {
if (bss->links[i].link_id == params->mld_link_id) {
link = &bss->links[i];
break;
}
}
if (i == bss->n_links) {
wpa_printf(MSG_DEBUG, "nl80211: Link ID=%u not found",
params->mld_link_id);
if (!nl80211_link_valid(bss->valid_links,
params->mld_link_id)) {
wpa_printf(MSG_DEBUG,
"nl80211: Link ID=%u invalid (valid: 0x%04x)",
params->mld_link_id, bss->valid_links);
return -EINVAL;
}
link = nl80211_get_link(bss, params->mld_link_id);
} else if (bss->valid_links) {
wpa_printf(MSG_DEBUG, "nl80211: MLD configuration expected");
return -EINVAL;
}
beacon_set = params->reenable ? 0 : link->beacon_set;
@ -5483,27 +5473,6 @@ fail:
}
static bool nl80211_link_valid(struct i802_bss *bss, s8 link_id)
{
unsigned int i;
if (link_id < 0)
return false;
for (i = 0; i < bss->n_links; i++) {
wpa_printf(MSG_DEBUG, "nl80211: %s - i=%u, link_id=%u",
__func__, i, bss->links[i].link_id);
if (bss->links[i].link_id == NL80211_DRV_LINK_ID_NA)
continue;
if (bss->links[i].link_id == link_id)
return true;
}
return false;
}
static int nl80211_set_channel(struct i802_bss *bss,
struct hostapd_freq_params *freq, int set_chan)
{
@ -5524,7 +5493,7 @@ static int nl80211_set_channel(struct i802_bss *bss,
return -1;
}
if (nl80211_link_valid(bss, freq->link_id)) {
if (nl80211_link_valid(bss->valid_links, freq->link_id)) {
wpa_printf(MSG_DEBUG, "nl80211: Set link_id=%u for freq",
freq->link_id);
@ -8886,7 +8855,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
if (type == WPA_IF_AP_BSS && setup_ap) {
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
unsigned int i;
if (new_bss == NULL) {
if (added)
@ -8894,10 +8862,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
return -1;
}
/* Initialize here before any failure path */
for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
new_bss->links[i].link_id = NL80211_DRV_LINK_ID_NA;
if (bridge &&
i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
@ -8922,7 +8886,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
new_bss->drv = drv;
new_bss->next = drv->first_bss->next;
new_bss->flink = &new_bss->links[0];
new_bss->n_links = 1;
new_bss->valid_links = 0;
os_memcpy(new_bss->flink->addr, new_bss->addr, ETH_ALEN);
new_bss->flink->freq = drv->first_bss->flink->freq;
@ -9464,33 +9428,35 @@ static void nl80211_remove_links(struct i802_bss *bss)
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
u8 link_id;
u8 link_id, i;
if (bss->n_links == 0)
return;
while (bss->links[0].link_id != NL80211_DRV_LINK_ID_NA) {
struct i802_link *link = &bss->links[0];
for_each_link(bss->valid_links, link_id) {
struct i802_link *link = &bss->links[link_id];
wpa_printf(MSG_DEBUG, "nl80211: MLD: remove link_id=%u",
link->link_id);
link_id);
wpa_driver_nl80211_del_beacon(bss, link);
link_id = link->link_id;
wpa_driver_nl80211_del_beacon(bss, link_id);
/* First remove the link locally */
if (bss->n_links == 1) {
bss->flink->link_id = NL80211_DRV_LINK_ID_NA;
bss->valid_links &= ~BIT(link_id);
os_memset(link->addr, 0, ETH_ALEN);
/* Choose new deflink if we are removing that link */
if (bss->flink == link) {
for_each_link_default(bss->valid_links, i, 0) {
bss->flink = &bss->links[i];
break;
}
}
/* If this was the last link, reset default link */
if (!bss->valid_links) {
/* TODO: Does keeping freq/bandwidth make sense? */
if (bss->flink != link)
os_memcpy(bss->flink, link, sizeof(*link));
os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
} else {
struct i802_link *other = &bss->links[bss->n_links - 1];
os_memcpy(link, other, sizeof(*link));
other->link_id = NL80211_DRV_LINK_ID_NA;
os_memset(other->addr, 0, ETH_ALEN);
bss->n_links--;
}
/* Remove the link from the kernel */
@ -9501,7 +9467,7 @@ static void nl80211_remove_links(struct i802_bss *bss)
wpa_printf(MSG_ERROR,
"nl80211: remove link (%d) failed",
link_id);
return;
continue;
}
ret = send_and_recv_cmd(drv, msg);
@ -9509,7 +9475,7 @@ static void nl80211_remove_links(struct i802_bss *bss)
wpa_printf(MSG_ERROR,
"nl80211: remove link (%d) failed. ret=%d (%s)",
link_id, ret, strerror(-ret));
return;
continue;
}
}
}
@ -9524,7 +9490,7 @@ static int wpa_driver_nl80211_deinit_ap(void *priv)
return -1;
/* Stop beaconing */
wpa_driver_nl80211_del_beacon(bss, bss->flink);
wpa_driver_nl80211_del_beacon(bss, NL80211_DRV_LINK_ID_NA);
nl80211_remove_links(bss);
@ -9543,7 +9509,6 @@ static int wpa_driver_nl80211_stop_ap(void *priv, int link_id)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
unsigned int i;
if (!is_ap_interface(drv->nlmode))
return -1;
@ -9553,13 +9518,9 @@ static int wpa_driver_nl80211_stop_ap(void *priv, int link_id)
return 0;
}
for (i = 0; i < bss->n_links; ++i) {
struct i802_link *link = &bss->links[i];
if (link->link_id == link_id) {
wpa_driver_nl80211_del_beacon(bss, link);
return 0;
}
if (nl80211_link_valid(bss->valid_links, link_id)) {
wpa_driver_nl80211_del_beacon(bss, link_id);
return 0;
}
return -1;
@ -13804,7 +13765,6 @@ static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr)
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
unsigned int idx, i;
int ret;
wpa_printf(MSG_DEBUG, "nl80211: MLD: add link_id=%u, addr=" MACSTR,
@ -13817,32 +13777,24 @@ static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr)
return -EINVAL;
}
if (bss->n_links >= MAX_NUM_MLD_LINKS) {
wpa_printf(MSG_DEBUG, "nl80211: MLD: already have n_links=%zu",
bss->n_links);
if (link_id >= MAX_NUM_MLD_LINKS) {
wpa_printf(MSG_DEBUG,
"nl80211: invalid link_id=%u", link_id);
return -EINVAL;
}
for (i = 0; i < bss->n_links; i++) {
if (bss->links[i].link_id == link_id &&
bss->links[i].beacon_set) {
wpa_printf(MSG_DEBUG,
"nl80211: MLD: link already set");
return -EINVAL;
}
if (bss->valid_links & BIT(link_id)) {
wpa_printf(MSG_DEBUG,
"nl80211: MLD: Link %u already set", link_id);
return -EINVAL;
}
/* try using the first link entry, assuming it is not beaconing yet */
if (bss->n_links == 1 &&
bss->flink->link_id == NL80211_DRV_LINK_ID_NA) {
if (!bss->valid_links) {
/* Becoming MLD, verify we were not beaconing */
if (bss->flink->beacon_set) {
wpa_printf(MSG_DEBUG, "nl80211: BSS already beaconing");
return -EINVAL;
}
idx = 0;
} else {
idx = bss->n_links;
}
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ADD_LINK);
@ -13860,12 +13812,16 @@ static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr)
return ret;
}
bss->links[idx].link_id = link_id;
os_memcpy(bss->links[idx].addr, addr, ETH_ALEN);
os_memcpy(bss->links[link_id].addr, addr, ETH_ALEN);
bss->n_links = idx + 1;
/* The new link is the first one, make it the default */
if (!bss->valid_links)
bss->flink = &bss->links[link_id];
wpa_printf(MSG_DEBUG, "nl80211: MLD: n_links=%zu", bss->n_links);
bss->valid_links |= BIT(link_id);
wpa_printf(MSG_DEBUG, "nl80211: MLD: valid_links=0x%04x",
bss->valid_links);
return 0;
}

View file

@ -55,7 +55,6 @@ struct nl80211_wiphy_data {
struct i802_link {
unsigned int beacon_set:1;
s8 link_id;
int freq;
int bandwidth;
u8 addr[ETH_ALEN];
@ -66,7 +65,7 @@ struct i802_bss {
struct wpa_driver_nl80211_data *drv;
struct i802_bss *next;
size_t n_links;
u16 valid_links;
struct i802_link links[MAX_NUM_MLD_LINKS];
struct i802_link *flink;
@ -354,6 +353,18 @@ const char * nl80211_iftype_str(enum nl80211_iftype mode);
void nl80211_restore_ap_mode(struct i802_bss *bss);
struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id);
static inline bool nl80211_link_valid(u16 links, s8 link_id)
{
if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS)
return false;
if (links & BIT(link_id))
return true;
return false;
}
static inline bool
nl80211_attr_supported(struct wpa_driver_nl80211_data *drv, unsigned int attr)
{

View file

@ -1610,18 +1610,17 @@ static void mlme_event_unprot_beacon(struct wpa_driver_nl80211_data *drv,
}
static struct i802_link *
nl80211_get_mld_link_by_freq(struct i802_bss *bss, unsigned int freq)
static s8
nl80211_get_link_id_by_freq(struct i802_bss *bss, unsigned int freq)
{
unsigned int i;
for (i = 0; i < bss->n_links; i++) {
if ((unsigned int) bss->links[i].freq == freq &&
bss->links[i].link_id != -1)
return &bss->links[i];
for_each_link(bss->valid_links, i) {
if ((unsigned int) bss->links[i].freq == freq)
return i;
}
return NULL;
return NL80211_DRV_LINK_ID_NA;
}
@ -1655,12 +1654,12 @@ static void mlme_event(struct i802_bss *bss,
/* Determine the MLD link either by an explicitly provided link id or
* finding a match based on the frequency. */
if (link)
mld_link = nl80211_get_link(bss, nla_get_u8(link));
link_id = nla_get_u8(link);
else if (freq)
mld_link = nl80211_get_mld_link_by_freq(bss, nla_get_u32(freq));
link_id = nl80211_get_link_id_by_freq(bss, nla_get_u32(freq));
if (mld_link)
link_id = mld_link->link_id;
if (nl80211_link_valid(bss->valid_links, link_id))
mld_link = nl80211_get_link(bss, link_id);
data = nla_data(frame);
len = nla_len(frame);
@ -1912,7 +1911,7 @@ static void mlme_event_dh_event(struct wpa_driver_nl80211_data *drv,
os_memset(&data, 0, sizeof(data));
addr = nla_data(tb[NL80211_ATTR_MAC]);
if (bss->links[0].link_id == NL80211_DRV_LINK_ID_NA &&
if (!bss->valid_links &&
(tb[NL80211_ATTR_MLO_LINK_ID] ||
tb[NL80211_ATTR_MLD_ADDR])) {
wpa_printf(MSG_ERROR,
@ -2176,7 +2175,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
u8 *req_ies = NULL, *resp_ies = NULL;
size_t req_ies_len = 0, resp_ies_len = 0;
if (bss->links[0].link_id == NL80211_DRV_LINK_ID_NA &&
if (!bss->valid_links &&
(tb[NL80211_ATTR_MLO_LINK_ID] ||
tb[NL80211_ATTR_MLD_ADDR])) {
wpa_printf(MSG_ERROR,
@ -2444,7 +2443,6 @@ static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
{
union wpa_event_data data;
enum nl80211_radar_event event_type;
struct i802_link *mld_link = NULL;
if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
return;
@ -2455,10 +2453,9 @@ static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
if (data.dfs_event.freq) {
mld_link = nl80211_get_mld_link_by_freq(drv->first_bss,
data.dfs_event.freq);
if (mld_link)
data.dfs_event.link_id = mld_link->link_id;
data.dfs_event.link_id =
nl80211_get_link_id_by_freq(drv->first_bss,
data.dfs_event.freq);
}
/* Check HT params */
@ -2824,7 +2821,6 @@ static void qca_nl80211_dfs_offload_radar_event(
{
union wpa_event_data data;
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct i802_link *mld_link = NULL;
wpa_printf(MSG_DEBUG,
"nl80211: DFS offload radar vendor event received");
@ -2844,10 +2840,9 @@ static void qca_nl80211_dfs_offload_radar_event(
data.dfs_event.link_id = NL80211_DRV_LINK_ID_NA;
if (data.dfs_event.freq) {
mld_link = nl80211_get_mld_link_by_freq(drv->first_bss,
data.dfs_event.freq);
if (mld_link)
data.dfs_event.link_id = mld_link->link_id;
data.dfs_event.link_id =
nl80211_get_link_id_by_freq(drv->first_bss,
data.dfs_event.freq);
}
wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, link=%d",

View file

@ -603,6 +603,14 @@ char * get_param(const char *cmd, const char *param);
for ((__i) = 0; (__i) < MAX_NUM_MLD_LINKS; (__i)++) \
if ((__links) & BIT(__i))
/* Iterate all links, or, if no link is defined, iterate given index */
#define for_each_link_default(_links, _i, _def_idx) \
for ((_i) = (_links) ? 0 : (_def_idx); \
(_i) < MAX_NUM_MLD_LINKS || \
(!(_links) && (_i) == (_def_idx)); \
(_i)++) \
if (!(_links) || (_links) & BIT(_i))
void forced_memzero(void *ptr, size_t len);
/*