Skip to content

Commit aebc29d

Browse files
benzeajmberg-intel
authored andcommitted
wifi: mac80211: apply advertised TTLM from association response
When the AP has a disabled link that the station can include in the association, the fact that the link is dormant needs to be advertised in the TID to Link Mapping (TTLM). Section 35.3.7.2.3 ("Negotiation of TTLM") of Draft P802.11REVmf_D1.0 also states that the mapping needs to be included in the association response frame. As such, we can simply rely on the TTLM from the association response. Before this change mac80211 would not properly track that an advertised TTLM was effectively active, resulting in it not enabling the link once it became available again. For the link reconfiguration case, the data was not used at all. This behaviour is actually correct because Draft P802.11REVmf_D1.0 states in section 35.3.6.4 that we "shall operate with all the TIDs mapped to the newly added links ..." Fixes: 6d543b3 ("wifi: mac80211: Support disabled links during association") Signed-off-by: Benjamin Berg <benjamin.berg@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20260118093904.43c861424543.I067f702ac46b84ac3f8b4ea16fb0db9cbbfae7e2@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent 3fa2886 commit aebc29d

2 files changed

Lines changed: 119 additions & 99 deletions

File tree

net/mac80211/ieee80211_i.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,6 @@ struct ieee80211_mgd_assoc_data {
451451
struct ieee80211_conn_settings conn;
452452

453453
u16 status;
454-
455-
bool disabled;
456454
} link[IEEE80211_MLD_MAX_NUM_LINKS];
457455

458456
u8 ap_addr[ETH_ALEN] __aligned(2);

net/mac80211/mlme.c

Lines changed: 119 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -6161,6 +6161,98 @@ static bool ieee80211_get_dtim(const struct cfg80211_bss_ies *ies,
61616161
return true;
61626162
}
61636163

6164+
static u16 ieee80211_get_ttlm(u8 bm_size, u8 *data)
6165+
{
6166+
if (bm_size == 1)
6167+
return *data;
6168+
6169+
return get_unaligned_le16(data);
6170+
}
6171+
6172+
static int
6173+
ieee80211_parse_adv_t2l(struct ieee80211_sub_if_data *sdata,
6174+
const struct ieee80211_ttlm_elem *ttlm,
6175+
struct ieee80211_adv_ttlm_info *ttlm_info)
6176+
{
6177+
/* The element size was already validated in
6178+
* ieee80211_tid_to_link_map_size_ok()
6179+
*/
6180+
u8 control, link_map_presence, map_size, tid;
6181+
u8 *pos;
6182+
6183+
memset(ttlm_info, 0, sizeof(*ttlm_info));
6184+
pos = (void *)ttlm->optional;
6185+
control = ttlm->control;
6186+
6187+
if ((control & IEEE80211_TTLM_CONTROL_DIRECTION) !=
6188+
IEEE80211_TTLM_DIRECTION_BOTH) {
6189+
sdata_info(sdata, "Invalid advertised T2L map direction\n");
6190+
return -EINVAL;
6191+
}
6192+
6193+
link_map_presence = *pos;
6194+
pos++;
6195+
6196+
if (control & IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT) {
6197+
ttlm_info->switch_time = get_unaligned_le16(pos);
6198+
6199+
/* Since ttlm_info->switch_time == 0 means no switch time, bump
6200+
* it by 1.
6201+
*/
6202+
if (!ttlm_info->switch_time)
6203+
ttlm_info->switch_time = 1;
6204+
6205+
pos += 2;
6206+
}
6207+
6208+
if (control & IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT) {
6209+
ttlm_info->duration = pos[0] | pos[1] << 8 | pos[2] << 16;
6210+
pos += 3;
6211+
}
6212+
6213+
if (control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP) {
6214+
ttlm_info->map = 0xffff;
6215+
return 0;
6216+
}
6217+
6218+
if (control & IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE)
6219+
map_size = 1;
6220+
else
6221+
map_size = 2;
6222+
6223+
/* According to Draft P802.11be_D3.0 clause 35.3.7.1.7, an AP MLD shall
6224+
* not advertise a TID-to-link mapping that does not map all TIDs to the
6225+
* same link set, reject frame if not all links have mapping
6226+
*/
6227+
if (link_map_presence != 0xff) {
6228+
sdata_info(sdata,
6229+
"Invalid advertised T2L mapping presence indicator\n");
6230+
return -EINVAL;
6231+
}
6232+
6233+
ttlm_info->map = ieee80211_get_ttlm(map_size, pos);
6234+
if (!ttlm_info->map) {
6235+
sdata_info(sdata,
6236+
"Invalid advertised T2L map for TID 0\n");
6237+
return -EINVAL;
6238+
}
6239+
6240+
pos += map_size;
6241+
6242+
for (tid = 1; tid < 8; tid++) {
6243+
u16 map = ieee80211_get_ttlm(map_size, pos);
6244+
6245+
if (map != ttlm_info->map) {
6246+
sdata_info(sdata, "Invalid advertised T2L map for tid %d\n",
6247+
tid);
6248+
return -EINVAL;
6249+
}
6250+
6251+
pos += map_size;
6252+
}
6253+
return 0;
6254+
}
6255+
61646256
static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
61656257
struct ieee80211_mgmt *mgmt,
61666258
struct ieee802_11_elems *elems,
@@ -6192,8 +6284,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
61926284
continue;
61936285

61946286
valid_links |= BIT(link_id);
6195-
if (assoc_data->link[link_id].disabled)
6196-
dormant_links |= BIT(link_id);
61976287

61986288
if (link_id != assoc_data->assoc_link_id) {
61996289
err = ieee80211_sta_allocate_link(sta, link_id);
@@ -6202,6 +6292,33 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
62026292
}
62036293
}
62046294

6295+
/*
6296+
* We do not support setting a negotiated TTLM during
6297+
* association. As such, we can assume that if there is a TTLM,
6298+
* then it is the currently active advertised TTLM.
6299+
* In that case, there must be exactly one TTLM that does not
6300+
* have a switch time set. This mapping should also leave us
6301+
* with at least one usable link.
6302+
*/
6303+
if (elems->ttlm_num > 1) {
6304+
sdata_info(sdata,
6305+
"More than one advertised TTLM in association response\n");
6306+
goto out_err;
6307+
} else if (elems->ttlm_num == 1) {
6308+
if (ieee80211_parse_adv_t2l(sdata, elems->ttlm[0],
6309+
&sdata->u.mgd.ttlm_info) ||
6310+
sdata->u.mgd.ttlm_info.switch_time != 0 ||
6311+
!(valid_links & sdata->u.mgd.ttlm_info.map)) {
6312+
sdata_info(sdata,
6313+
"Invalid advertised TTLM in association response\n");
6314+
goto out_err;
6315+
}
6316+
6317+
sdata->u.mgd.ttlm_info.active = true;
6318+
dormant_links =
6319+
valid_links & ~sdata->u.mgd.ttlm_info.map;
6320+
}
6321+
62056322
ieee80211_vif_set_links(sdata, valid_links, dormant_links);
62066323
}
62076324

@@ -6992,98 +7109,6 @@ static void ieee80211_tid_to_link_map_work(struct wiphy *wiphy,
69927109
sdata->u.mgd.ttlm_info.switch_time = 0;
69937110
}
69947111

6995-
static u16 ieee80211_get_ttlm(u8 bm_size, u8 *data)
6996-
{
6997-
if (bm_size == 1)
6998-
return *data;
6999-
else
7000-
return get_unaligned_le16(data);
7001-
}
7002-
7003-
static int
7004-
ieee80211_parse_adv_t2l(struct ieee80211_sub_if_data *sdata,
7005-
const struct ieee80211_ttlm_elem *ttlm,
7006-
struct ieee80211_adv_ttlm_info *ttlm_info)
7007-
{
7008-
/* The element size was already validated in
7009-
* ieee80211_tid_to_link_map_size_ok()
7010-
*/
7011-
u8 control, link_map_presence, map_size, tid;
7012-
u8 *pos;
7013-
7014-
memset(ttlm_info, 0, sizeof(*ttlm_info));
7015-
pos = (void *)ttlm->optional;
7016-
control = ttlm->control;
7017-
7018-
if ((control & IEEE80211_TTLM_CONTROL_DIRECTION) !=
7019-
IEEE80211_TTLM_DIRECTION_BOTH) {
7020-
sdata_info(sdata, "Invalid advertised T2L map direction\n");
7021-
return -EINVAL;
7022-
}
7023-
7024-
link_map_presence = *pos;
7025-
pos++;
7026-
7027-
if (control & IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT) {
7028-
ttlm_info->switch_time = get_unaligned_le16(pos);
7029-
7030-
/* Since ttlm_info->switch_time == 0 means no switch time, bump
7031-
* it by 1.
7032-
*/
7033-
if (!ttlm_info->switch_time)
7034-
ttlm_info->switch_time = 1;
7035-
7036-
pos += 2;
7037-
}
7038-
7039-
if (control & IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT) {
7040-
ttlm_info->duration = pos[0] | pos[1] << 8 | pos[2] << 16;
7041-
pos += 3;
7042-
}
7043-
7044-
if (control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP) {
7045-
ttlm_info->map = 0xffff;
7046-
return 0;
7047-
}
7048-
7049-
if (control & IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE)
7050-
map_size = 1;
7051-
else
7052-
map_size = 2;
7053-
7054-
/* According to Draft P802.11be_D3.0 clause 35.3.7.1.7, an AP MLD shall
7055-
* not advertise a TID-to-link mapping that does not map all TIDs to the
7056-
* same link set, reject frame if not all links have mapping
7057-
*/
7058-
if (link_map_presence != 0xff) {
7059-
sdata_info(sdata,
7060-
"Invalid advertised T2L mapping presence indicator\n");
7061-
return -EINVAL;
7062-
}
7063-
7064-
ttlm_info->map = ieee80211_get_ttlm(map_size, pos);
7065-
if (!ttlm_info->map) {
7066-
sdata_info(sdata,
7067-
"Invalid advertised T2L map for TID 0\n");
7068-
return -EINVAL;
7069-
}
7070-
7071-
pos += map_size;
7072-
7073-
for (tid = 1; tid < 8; tid++) {
7074-
u16 map = ieee80211_get_ttlm(map_size, pos);
7075-
7076-
if (map != ttlm_info->map) {
7077-
sdata_info(sdata, "Invalid advertised T2L map for tid %d\n",
7078-
tid);
7079-
return -EINVAL;
7080-
}
7081-
7082-
pos += map_size;
7083-
}
7084-
return 0;
7085-
}
7086-
70877112
static void ieee80211_process_adv_ttlm(struct ieee80211_sub_if_data *sdata,
70887113
struct ieee802_11_elems *elems,
70897114
u64 beacon_ts)
@@ -9740,7 +9765,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
97409765
req, true, i,
97419766
&assoc_data->link[i].conn);
97429767
assoc_data->link[i].bss = link_cbss;
9743-
assoc_data->link[i].disabled = req->links[i].disabled;
97449768

97459769
if (!bss->uapsd_supported)
97469770
uapsd_supported = false;
@@ -10722,8 +10746,6 @@ int ieee80211_mgd_assoc_ml_reconf(struct ieee80211_sub_if_data *sdata,
1072210746
&data->link[link_id].conn);
1072310747

1072410748
data->link[link_id].bss = link_cbss;
10725-
data->link[link_id].disabled =
10726-
req->add_links[link_id].disabled;
1072710749
data->link[link_id].elems =
1072810750
(u8 *)req->add_links[link_id].elems;
1072910751
data->link[link_id].elems_len =

0 commit comments

Comments
 (0)