Skip to content

Commit 8eb8dd2

Browse files
ilanpeer2jmberg-intel
authored andcommitted
wifi: mac80211: Support link removal using Reconfiguration ML element
Add support for handling link removal indicated by the Reconfiguration Multi-Link element. Signed-off-by: Ilan Peer <[email protected]> Signed-off-by: Gregory Greenman <[email protected]> Link: https://lore.kernel.org/r/20230618214436.d8a046dc0c1a.I4dcf794da2a2d9f4e5f63a4b32158075d27c0660@changeid [use cfg80211_links_removed() API instead] Signed-off-by: Johannes Berg <[email protected]>
1 parent 79973d5 commit 8eb8dd2

File tree

3 files changed

+205
-0
lines changed

3 files changed

+205
-0
lines changed

include/linux/ieee80211.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4891,6 +4891,39 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data,
48914891
fixed + prof->sta_info_len <= len;
48924892
}
48934893

4894+
#define IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID 0x000f
4895+
#define IEEE80211_MLE_STA_RECONF_CONTROL_COMPLETE_PROFILE 0x0010
4896+
#define IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT 0x0020
4897+
#define IEEE80211_MLE_STA_RECONF_CONTROL_DELETE_TIMER_PRESENT 0x0040
4898+
4899+
/**
4900+
* ieee80211_mle_reconf_sta_prof_size_ok - validate reconfiguration multi-link
4901+
* element sta profile size.
4902+
* @data: pointer to the sub element data
4903+
* @len: length of the containing sub element
4904+
*/
4905+
static inline bool ieee80211_mle_reconf_sta_prof_size_ok(const u8 *data,
4906+
size_t len)
4907+
{
4908+
const struct ieee80211_mle_per_sta_profile *prof = (const void *)data;
4909+
u16 control;
4910+
u8 fixed = sizeof(*prof);
4911+
u8 info_len = 1;
4912+
4913+
if (len < fixed)
4914+
return false;
4915+
4916+
control = le16_to_cpu(prof->control);
4917+
4918+
if (control & IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT)
4919+
info_len += ETH_ALEN;
4920+
if (control & IEEE80211_MLE_STA_RECONF_CONTROL_DELETE_TIMER_PRESENT)
4921+
info_len += 2;
4922+
4923+
return prof->sta_info_len >= info_len &&
4924+
fixed + prof->sta_info_len - 1 <= len;
4925+
}
4926+
48944927
#define for_each_mle_subelement(_elem, _data, _len) \
48954928
if (ieee80211_mle_size_ok(_data, _len)) \
48964929
for_each_element(_elem, \

net/mac80211/ieee80211_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,9 @@ struct ieee80211_if_managed {
551551
*/
552552
u8 *assoc_req_ies;
553553
size_t assoc_req_ies_len;
554+
555+
struct wiphy_delayed_work ml_reconf_work;
556+
u16 removed_links;
554557
};
555558

556559
struct ieee80211_if_ibss {

net/mac80211/mlme.c

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5608,6 +5608,169 @@ static bool ieee80211_config_puncturing(struct ieee80211_link_data *link,
56085608
return true;
56095609
}
56105610

5611+
static void ieee80211_ml_reconf_work(struct wiphy *wiphy,
5612+
struct wiphy_work *work)
5613+
{
5614+
struct ieee80211_sub_if_data *sdata =
5615+
container_of(work, struct ieee80211_sub_if_data,
5616+
u.mgd.ml_reconf_work.work);
5617+
u16 new_valid_links, new_active_links, new_dormant_links;
5618+
int ret;
5619+
5620+
sdata_lock(sdata);
5621+
if (!sdata->u.mgd.removed_links) {
5622+
sdata_unlock(sdata);
5623+
return;
5624+
}
5625+
5626+
sdata_info(sdata,
5627+
"MLO Reconfiguration: work: valid=0x%x, removed=0x%x\n",
5628+
sdata->vif.valid_links, sdata->u.mgd.removed_links);
5629+
5630+
new_valid_links = sdata->vif.valid_links & ~sdata->u.mgd.removed_links;
5631+
if (new_valid_links == sdata->vif.valid_links) {
5632+
sdata_unlock(sdata);
5633+
return;
5634+
}
5635+
5636+
if (!new_valid_links ||
5637+
!(new_valid_links & ~sdata->vif.dormant_links)) {
5638+
sdata_info(sdata, "No valid links after reconfiguration\n");
5639+
ret = -EINVAL;
5640+
goto out;
5641+
}
5642+
5643+
new_active_links = sdata->vif.active_links & ~sdata->u.mgd.removed_links;
5644+
if (new_active_links != sdata->vif.active_links) {
5645+
if (!new_active_links)
5646+
new_active_links =
5647+
BIT(ffs(new_valid_links &
5648+
~sdata->vif.dormant_links) - 1);
5649+
5650+
ret = __ieee80211_set_active_links(&sdata->vif,
5651+
new_active_links);
5652+
if (ret) {
5653+
sdata_info(sdata,
5654+
"Failed setting active links\n");
5655+
goto out;
5656+
}
5657+
}
5658+
5659+
new_dormant_links = sdata->vif.dormant_links & ~sdata->u.mgd.removed_links;
5660+
5661+
ret = ieee80211_vif_set_links(sdata, new_valid_links,
5662+
new_dormant_links);
5663+
if (ret)
5664+
sdata_info(sdata, "Failed setting valid links\n");
5665+
5666+
out:
5667+
if (!ret)
5668+
cfg80211_links_removed(sdata->dev, sdata->u.mgd.removed_links);
5669+
else
5670+
___ieee80211_disconnect(sdata);
5671+
5672+
sdata->u.mgd.removed_links = 0;
5673+
5674+
sdata_unlock(sdata);
5675+
}
5676+
5677+
static void ieee80211_ml_reconfiguration(struct ieee80211_sub_if_data *sdata,
5678+
struct ieee802_11_elems *elems)
5679+
{
5680+
const struct ieee80211_multi_link_elem *ml;
5681+
const struct element *sub;
5682+
size_t ml_len;
5683+
unsigned long removed_links = 0;
5684+
u16 link_removal_timeout[IEEE80211_MLD_MAX_NUM_LINKS] = {};
5685+
u8 link_id;
5686+
u32 delay;
5687+
5688+
if (!ieee80211_vif_is_mld(&sdata->vif) || !elems->ml_reconf)
5689+
return;
5690+
5691+
ml_len = cfg80211_defragment_element(elems->ml_reconf_elem,
5692+
elems->ie_start,
5693+
elems->total_len,
5694+
elems->scratch_pos,
5695+
elems->scratch + elems->scratch_len -
5696+
elems->scratch_pos,
5697+
WLAN_EID_FRAGMENT);
5698+
5699+
elems->ml_reconf = (const void *)elems->scratch_pos;
5700+
elems->ml_reconf_len = ml_len;
5701+
ml = elems->ml_reconf;
5702+
5703+
/* Directly parse the sub elements as the common information doesn't
5704+
* hold any useful information.
5705+
*/
5706+
for_each_mle_subelement(sub, (u8 *)ml, ml_len) {
5707+
struct ieee80211_mle_per_sta_profile *prof = (void *)sub->data;
5708+
u8 *pos = prof->variable;
5709+
u16 control;
5710+
5711+
if (sub->id != IEEE80211_MLE_SUBELEM_PER_STA_PROFILE)
5712+
continue;
5713+
5714+
if (!ieee80211_mle_reconf_sta_prof_size_ok(sub->data,
5715+
sub->datalen))
5716+
return;
5717+
5718+
control = le16_to_cpu(prof->control);
5719+
link_id = control & IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID;
5720+
5721+
removed_links |= BIT(link_id);
5722+
5723+
/* the MAC address should not be included, but handle it */
5724+
if (control &
5725+
IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT)
5726+
pos += 6;
5727+
5728+
/* According to Draft P802.11be_D3.0, the control should
5729+
* include the AP Removal Timer present. If the AP Removal Timer
5730+
* is not present assume immediate removal.
5731+
*/
5732+
if (control &
5733+
IEEE80211_MLE_STA_RECONF_CONTROL_DELETE_TIMER_PRESENT)
5734+
link_removal_timeout[link_id] = le16_to_cpu(*(__le16 *)pos);
5735+
}
5736+
5737+
removed_links &= sdata->vif.valid_links;
5738+
if (!removed_links) {
5739+
/* In case the removal was cancelled, abort it */
5740+
if (sdata->u.mgd.removed_links) {
5741+
sdata->u.mgd.removed_links = 0;
5742+
wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
5743+
&sdata->u.mgd.ml_reconf_work);
5744+
}
5745+
return;
5746+
}
5747+
5748+
delay = 0;
5749+
for_each_set_bit(link_id, &removed_links, IEEE80211_MLD_MAX_NUM_LINKS) {
5750+
struct ieee80211_bss_conf *link_conf =
5751+
sdata_dereference(sdata->vif.link_conf[link_id], sdata);
5752+
u32 link_delay;
5753+
5754+
if (!link_conf) {
5755+
removed_links &= ~BIT(link_id);
5756+
continue;
5757+
}
5758+
5759+
link_delay = link_conf->beacon_int *
5760+
link_removal_timeout[link_id];
5761+
5762+
if (!delay)
5763+
delay = link_delay;
5764+
else
5765+
delay = min(delay, link_delay);
5766+
}
5767+
5768+
sdata->u.mgd.removed_links = removed_links;
5769+
wiphy_delayed_work_queue(sdata->local->hw.wiphy,
5770+
&sdata->u.mgd.ml_reconf_work,
5771+
TU_TO_JIFFIES(delay));
5772+
}
5773+
56115774
static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
56125775
struct ieee80211_hdr *hdr, size_t len,
56135776
struct ieee80211_rx_status *rx_status)
@@ -5937,6 +6100,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
59376100
}
59386101
}
59396102

6103+
ieee80211_ml_reconfiguration(sdata, elems);
6104+
59406105
ieee80211_link_info_change_notify(sdata, link, changed);
59416106
free:
59426107
kfree(elems);
@@ -6563,6 +6728,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
65636728
ieee80211_csa_connection_drop_work);
65646729
INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work,
65656730
ieee80211_tdls_peer_del_work);
6731+
wiphy_delayed_work_init(&ifmgd->ml_reconf_work,
6732+
ieee80211_ml_reconf_work);
65666733
timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0);
65676734
timer_setup(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, 0);
65686735
timer_setup(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer, 0);
@@ -7575,6 +7742,8 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
75757742
wiphy_work_cancel(sdata->local->hw.wiphy,
75767743
&ifmgd->csa_connection_drop_work);
75777744
cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work);
7745+
wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
7746+
&ifmgd->ml_reconf_work);
75787747

75797748
sdata_lock(sdata);
75807749
if (ifmgd->assoc_data)

0 commit comments

Comments
 (0)