wifi: mac80211: fix link manipulation
When we add non-deflink pointers, we need to remove the link[0] pointer to deflink in case link[0] is not valid afterwards. Also, we need to add that back when there are no more valid links. Reorg the code to fix that. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
939c4c7e82
commit
d3e2439b0f
1 changed files with 26 additions and 18 deletions
|
@ -463,6 +463,10 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
|
||||||
if (old_links == new_links)
|
if (old_links == new_links)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* if there were no old links, need to clear the pointers to deflink */
|
||||||
|
if (!old_links)
|
||||||
|
rem |= BIT(0);
|
||||||
|
|
||||||
/* allocate new link structures first */
|
/* allocate new link structures first */
|
||||||
for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
|
for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||||
link = kzalloc(sizeof(*link), GFP_KERNEL);
|
link = kzalloc(sizeof(*link), GFP_KERNEL);
|
||||||
|
@ -480,6 +484,22 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
|
||||||
BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link));
|
BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link));
|
||||||
memcpy(old_data, sdata->link, sizeof(old_data));
|
memcpy(old_data, sdata->link, sizeof(old_data));
|
||||||
|
|
||||||
|
/* grab old links to free later */
|
||||||
|
for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||||
|
RCU_INIT_POINTER(sdata->link[link_id], NULL);
|
||||||
|
RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
|
||||||
|
|
||||||
|
if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
|
* we must have allocated the data through this path so
|
||||||
|
* we know we can free both at the same time
|
||||||
|
*/
|
||||||
|
to_free[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
|
||||||
|
typeof(*links[link_id]),
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
/* link them into data structures */
|
/* link them into data structures */
|
||||||
for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
|
for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||||
WARN_ON(!use_deflink &&
|
WARN_ON(!use_deflink &&
|
||||||
|
@ -490,10 +510,9 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
|
||||||
ieee80211_link_setup(&link->data);
|
ieee80211_link_setup(&link->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
|
if (new_links == 0)
|
||||||
RCU_INIT_POINTER(sdata->link[link_id], NULL);
|
ieee80211_link_init(sdata, -1, &sdata->deflink,
|
||||||
RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
|
&sdata->vif.bss_conf);
|
||||||
}
|
|
||||||
|
|
||||||
sdata->vif.valid_links = new_links;
|
sdata->vif.valid_links = new_links;
|
||||||
|
|
||||||
|
@ -506,25 +525,14 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
|
||||||
memcpy(sdata->link, old_data, sizeof(old_data));
|
memcpy(sdata->link, old_data, sizeof(old_data));
|
||||||
memcpy(sdata->vif.link_conf, old, sizeof(old));
|
memcpy(sdata->vif.link_conf, old, sizeof(old));
|
||||||
sdata->vif.valid_links = old_links;
|
sdata->vif.valid_links = old_links;
|
||||||
/* and free the newly allocated links */
|
/* and free (only) the newly allocated links */
|
||||||
goto deinit;
|
memset(to_free, 0, sizeof(links));
|
||||||
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use deflink/bss_conf again if and only if there are no more links */
|
/* use deflink/bss_conf again if and only if there are no more links */
|
||||||
use_deflink = new_links == 0;
|
use_deflink = new_links == 0;
|
||||||
|
|
||||||
for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
|
|
||||||
if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
|
|
||||||
continue;
|
|
||||||
/*
|
|
||||||
* we must have allocated the data through this path so
|
|
||||||
* we know we can free both at the same time
|
|
||||||
*/
|
|
||||||
to_free[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
|
|
||||||
typeof(*links[link_id]),
|
|
||||||
data);
|
|
||||||
}
|
|
||||||
|
|
||||||
goto deinit;
|
goto deinit;
|
||||||
free:
|
free:
|
||||||
/* if we failed during allocation, only free all */
|
/* if we failed during allocation, only free all */
|
||||||
|
|
Loading…
Add table
Reference in a new issue