Skip to content

Commit 99ca2c2

Browse files
committed
wifi: mac80211: fix MLE non-inheritance parsing
The code is erroneously applying the non-inheritance element to the inner elements rather than the outer, which is clearly completely wrong. Fix it by finding the MLE basic element at the beginning, and then applying the non-inheritance for the outer parsing. While at it, do some general cleanups such as not allowing callers to try looking for a specific non-transmitted BSS and link at the same time. Fixes: 45ebac4 ("wifi: mac80211: Parse station profile from association response") Reviewed-by: Ilan Peer <[email protected]> Reviewed-by: Miriam Rachel Korenblit <[email protected]> Link: https://patch.msgid.link/20250221112451.b46d42f45b66.If5b95dc3c80208e0c62d8895fb6152aa54b6620b@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent 3640dbc commit 99ca2c2

File tree

2 files changed

+83
-45
lines changed

2 files changed

+83
-45
lines changed

net/mac80211/mlme.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4959,6 +4959,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
49594959
parse_params.start = bss_ies->data;
49604960
parse_params.len = bss_ies->len;
49614961
parse_params.bss = cbss;
4962+
parse_params.link_id = -1;
49624963
bss_elems = ieee802_11_parse_elems_full(&parse_params);
49634964
if (!bss_elems) {
49644965
ret = false;

net/mac80211/parse.c

Lines changed: 82 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ struct ieee80211_elems_parse {
4747
/* The EPCS Multi-Link element in the original elements */
4848
const struct element *ml_epcs_elem;
4949

50+
bool multi_link_inner;
51+
5052
/*
5153
* scratch buffer that can be used for various element parsing related
5254
* tasks, e.g., element de-fragmentation etc.
@@ -152,12 +154,11 @@ ieee80211_parse_extension_element(u32 *crc,
152154
switch (le16_get_bits(mle->control,
153155
IEEE80211_ML_CONTROL_TYPE)) {
154156
case IEEE80211_ML_CONTROL_TYPE_BASIC:
155-
if (elems_parse->ml_basic_elem) {
157+
if (elems_parse->multi_link_inner) {
156158
elems->parse_error |=
157159
IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC;
158160
break;
159161
}
160-
elems_parse->ml_basic_elem = elem;
161162
break;
162163
case IEEE80211_ML_CONTROL_TYPE_RECONF:
163164
elems_parse->ml_reconf_elem = elem;
@@ -866,21 +867,36 @@ ieee80211_mle_get_sta_prof(struct ieee80211_elems_parse *elems_parse,
866867
}
867868
}
868869

869-
static void ieee80211_mle_parse_link(struct ieee80211_elems_parse *elems_parse,
870-
struct ieee80211_elems_parse_params *params)
870+
static const struct element *
871+
ieee80211_prep_mle_link_parse(struct ieee80211_elems_parse *elems_parse,
872+
struct ieee80211_elems_parse_params *params,
873+
struct ieee80211_elems_parse_params *sub)
871874
{
872875
struct ieee802_11_elems *elems = &elems_parse->elems;
873876
struct ieee80211_mle_per_sta_profile *prof;
874-
struct ieee80211_elems_parse_params sub = {
875-
.mode = params->mode,
876-
.action = params->action,
877-
.from_ap = params->from_ap,
878-
.link_id = -1,
879-
};
880-
ssize_t ml_len = elems->ml_basic_len;
881-
const struct element *non_inherit = NULL;
877+
const struct element *tmp;
878+
ssize_t ml_len;
882879
const u8 *end;
883880

881+
if (params->mode < IEEE80211_CONN_MODE_EHT)
882+
return NULL;
883+
884+
for_each_element_extid(tmp, WLAN_EID_EXT_EHT_MULTI_LINK,
885+
elems->ie_start, elems->total_len) {
886+
const struct ieee80211_multi_link_elem *mle =
887+
(void *)tmp->data + 1;
888+
889+
if (!ieee80211_mle_size_ok(tmp->data + 1, tmp->datalen - 1))
890+
continue;
891+
892+
if (le16_get_bits(mle->control, IEEE80211_ML_CONTROL_TYPE) !=
893+
IEEE80211_ML_CONTROL_TYPE_BASIC)
894+
continue;
895+
896+
elems_parse->ml_basic_elem = tmp;
897+
break;
898+
}
899+
884900
ml_len = cfg80211_defragment_element(elems_parse->ml_basic_elem,
885901
elems->ie_start,
886902
elems->total_len,
@@ -891,26 +907,26 @@ static void ieee80211_mle_parse_link(struct ieee80211_elems_parse *elems_parse,
891907
WLAN_EID_FRAGMENT);
892908

893909
if (ml_len < 0)
894-
return;
910+
return NULL;
895911

896912
elems->ml_basic = (const void *)elems_parse->scratch_pos;
897913
elems->ml_basic_len = ml_len;
898914
elems_parse->scratch_pos += ml_len;
899915

900916
if (params->link_id == -1)
901-
return;
917+
return NULL;
902918

903919
ieee80211_mle_get_sta_prof(elems_parse, params->link_id);
904920
prof = elems->prof;
905921

906922
if (!prof)
907-
return;
923+
return NULL;
908924

909925
/* check if we have the 4 bytes for the fixed part in assoc response */
910926
if (elems->sta_prof_len < sizeof(*prof) + prof->sta_info_len - 1 + 4) {
911927
elems->prof = NULL;
912928
elems->sta_prof_len = 0;
913-
return;
929+
return NULL;
914930
}
915931

916932
/*
@@ -919,13 +935,17 @@ static void ieee80211_mle_parse_link(struct ieee80211_elems_parse *elems_parse,
919935
* the -1 is because the 'sta_info_len' is accounted to as part of the
920936
* per-STA profile, but not part of the 'u8 variable[]' portion.
921937
*/
922-
sub.start = prof->variable + prof->sta_info_len - 1 + 4;
938+
sub->start = prof->variable + prof->sta_info_len - 1 + 4;
923939
end = (const u8 *)prof + elems->sta_prof_len;
924-
sub.len = end - sub.start;
940+
sub->len = end - sub->start;
925941

926-
non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
927-
sub.start, sub.len);
928-
_ieee802_11_parse_elems_full(&sub, elems_parse, non_inherit);
942+
sub->mode = params->mode;
943+
sub->action = params->action;
944+
sub->from_ap = params->from_ap;
945+
sub->link_id = -1;
946+
947+
return cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
948+
sub->start, sub->len);
929949
}
930950

931951
static void
@@ -973,15 +993,19 @@ ieee80211_mle_defrag_epcs(struct ieee80211_elems_parse *elems_parse)
973993
struct ieee802_11_elems *
974994
ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
975995
{
996+
struct ieee80211_elems_parse_params sub = {};
976997
struct ieee80211_elems_parse *elems_parse;
977-
struct ieee802_11_elems *elems;
978998
const struct element *non_inherit = NULL;
979-
u8 *nontransmitted_profile;
980-
int nontransmitted_profile_len = 0;
999+
struct ieee802_11_elems *elems;
9811000
size_t scratch_len = 3 * params->len;
1001+
bool multi_link_inner = false;
9821002

9831003
BUILD_BUG_ON(offsetof(typeof(*elems_parse), elems) != 0);
9841004

1005+
/* cannot parse for both a specific link and non-transmitted BSS */
1006+
if (WARN_ON(params->link_id >= 0 && params->bss))
1007+
return NULL;
1008+
9851009
elems_parse = kzalloc(struct_size(elems_parse, scratch, scratch_len),
9861010
GFP_ATOMIC);
9871011
if (!elems_parse)
@@ -998,34 +1022,47 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
9981022
ieee80211_clear_tpe(&elems->tpe);
9991023
ieee80211_clear_tpe(&elems->csa_tpe);
10001024

1001-
nontransmitted_profile = elems_parse->scratch_pos;
1002-
nontransmitted_profile_len =
1003-
ieee802_11_find_bssid_profile(params->start, params->len,
1004-
elems, params->bss,
1005-
nontransmitted_profile);
1006-
elems_parse->scratch_pos += nontransmitted_profile_len;
1007-
non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
1008-
nontransmitted_profile,
1009-
nontransmitted_profile_len);
1025+
/*
1026+
* If we're looking for a non-transmitted BSS then we cannot at
1027+
* the same time be looking for a second link as the two can only
1028+
* appear in the same frame carrying info for different BSSes.
1029+
*
1030+
* In any case, we only look for one at a time, as encoded by
1031+
* the WARN_ON above.
1032+
*/
1033+
if (params->bss) {
1034+
int nontx_len =
1035+
ieee802_11_find_bssid_profile(params->start,
1036+
params->len,
1037+
elems, params->bss,
1038+
elems_parse->scratch_pos);
1039+
sub.start = elems_parse->scratch_pos;
1040+
sub.mode = params->mode;
1041+
sub.len = nontx_len;
1042+
sub.action = params->action;
1043+
sub.link_id = params->link_id;
1044+
1045+
/* consume the space used for non-transmitted profile */
1046+
elems_parse->scratch_pos += nontx_len;
1047+
1048+
non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
1049+
sub.start, nontx_len);
1050+
} else {
1051+
/* must always parse to get elems_parse->ml_basic_elem */
1052+
non_inherit = ieee80211_prep_mle_link_parse(elems_parse, params,
1053+
&sub);
1054+
multi_link_inner = true;
1055+
}
10101056

10111057
elems->crc = _ieee802_11_parse_elems_full(params, elems_parse,
10121058
non_inherit);
10131059

1014-
/* Override with nontransmitted profile, if found */
1015-
if (nontransmitted_profile_len) {
1016-
struct ieee80211_elems_parse_params sub = {
1017-
.mode = params->mode,
1018-
.start = nontransmitted_profile,
1019-
.len = nontransmitted_profile_len,
1020-
.action = params->action,
1021-
.link_id = params->link_id,
1022-
};
1023-
1060+
/* Override with nontransmitted/per-STA profile if found */
1061+
if (sub.len) {
1062+
elems_parse->multi_link_inner = multi_link_inner;
10241063
_ieee802_11_parse_elems_full(&sub, elems_parse, NULL);
10251064
}
10261065

1027-
ieee80211_mle_parse_link(elems_parse, params);
1028-
10291066
ieee80211_mle_defrag_reconf(elems_parse);
10301067

10311068
ieee80211_mle_defrag_epcs(elems_parse);

0 commit comments

Comments
 (0)