@@ -47,6 +47,8 @@ struct ieee80211_elems_parse {
47
47
/* The EPCS Multi-Link element in the original elements */
48
48
const struct element * ml_epcs_elem ;
49
49
50
+ bool multi_link_inner ;
51
+
50
52
/*
51
53
* scratch buffer that can be used for various element parsing related
52
54
* tasks, e.g., element de-fragmentation etc.
@@ -152,12 +154,11 @@ ieee80211_parse_extension_element(u32 *crc,
152
154
switch (le16_get_bits (mle -> control ,
153
155
IEEE80211_ML_CONTROL_TYPE )) {
154
156
case IEEE80211_ML_CONTROL_TYPE_BASIC :
155
- if (elems_parse -> ml_basic_elem ) {
157
+ if (elems_parse -> multi_link_inner ) {
156
158
elems -> parse_error |=
157
159
IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC ;
158
160
break ;
159
161
}
160
- elems_parse -> ml_basic_elem = elem ;
161
162
break ;
162
163
case IEEE80211_ML_CONTROL_TYPE_RECONF :
163
164
elems_parse -> ml_reconf_elem = elem ;
@@ -866,21 +867,36 @@ ieee80211_mle_get_sta_prof(struct ieee80211_elems_parse *elems_parse,
866
867
}
867
868
}
868
869
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 )
871
874
{
872
875
struct ieee802_11_elems * elems = & elems_parse -> elems ;
873
876
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 ;
882
879
const u8 * end ;
883
880
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
+
884
900
ml_len = cfg80211_defragment_element (elems_parse -> ml_basic_elem ,
885
901
elems -> ie_start ,
886
902
elems -> total_len ,
@@ -891,26 +907,26 @@ static void ieee80211_mle_parse_link(struct ieee80211_elems_parse *elems_parse,
891
907
WLAN_EID_FRAGMENT );
892
908
893
909
if (ml_len < 0 )
894
- return ;
910
+ return NULL ;
895
911
896
912
elems -> ml_basic = (const void * )elems_parse -> scratch_pos ;
897
913
elems -> ml_basic_len = ml_len ;
898
914
elems_parse -> scratch_pos += ml_len ;
899
915
900
916
if (params -> link_id == -1 )
901
- return ;
917
+ return NULL ;
902
918
903
919
ieee80211_mle_get_sta_prof (elems_parse , params -> link_id );
904
920
prof = elems -> prof ;
905
921
906
922
if (!prof )
907
- return ;
923
+ return NULL ;
908
924
909
925
/* check if we have the 4 bytes for the fixed part in assoc response */
910
926
if (elems -> sta_prof_len < sizeof (* prof ) + prof -> sta_info_len - 1 + 4 ) {
911
927
elems -> prof = NULL ;
912
928
elems -> sta_prof_len = 0 ;
913
- return ;
929
+ return NULL ;
914
930
}
915
931
916
932
/*
@@ -919,13 +935,17 @@ static void ieee80211_mle_parse_link(struct ieee80211_elems_parse *elems_parse,
919
935
* the -1 is because the 'sta_info_len' is accounted to as part of the
920
936
* per-STA profile, but not part of the 'u8 variable[]' portion.
921
937
*/
922
- sub . start = prof -> variable + prof -> sta_info_len - 1 + 4 ;
938
+ sub -> start = prof -> variable + prof -> sta_info_len - 1 + 4 ;
923
939
end = (const u8 * )prof + elems -> sta_prof_len ;
924
- sub . len = end - sub . start ;
940
+ sub -> len = end - sub -> start ;
925
941
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 );
929
949
}
930
950
931
951
static void
@@ -973,15 +993,19 @@ ieee80211_mle_defrag_epcs(struct ieee80211_elems_parse *elems_parse)
973
993
struct ieee802_11_elems *
974
994
ieee802_11_parse_elems_full (struct ieee80211_elems_parse_params * params )
975
995
{
996
+ struct ieee80211_elems_parse_params sub = {};
976
997
struct ieee80211_elems_parse * elems_parse ;
977
- struct ieee802_11_elems * elems ;
978
998
const struct element * non_inherit = NULL ;
979
- u8 * nontransmitted_profile ;
980
- int nontransmitted_profile_len = 0 ;
999
+ struct ieee802_11_elems * elems ;
981
1000
size_t scratch_len = 3 * params -> len ;
1001
+ bool multi_link_inner = false;
982
1002
983
1003
BUILD_BUG_ON (offsetof (typeof (* elems_parse ), elems ) != 0 );
984
1004
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
+
985
1009
elems_parse = kzalloc (struct_size (elems_parse , scratch , scratch_len ),
986
1010
GFP_ATOMIC );
987
1011
if (!elems_parse )
@@ -998,34 +1022,47 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
998
1022
ieee80211_clear_tpe (& elems -> tpe );
999
1023
ieee80211_clear_tpe (& elems -> csa_tpe );
1000
1024
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
+ }
1010
1056
1011
1057
elems -> crc = _ieee802_11_parse_elems_full (params , elems_parse ,
1012
1058
non_inherit );
1013
1059
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 ;
1024
1063
_ieee802_11_parse_elems_full (& sub , elems_parse , NULL );
1025
1064
}
1026
1065
1027
- ieee80211_mle_parse_link (elems_parse , params );
1028
-
1029
1066
ieee80211_mle_defrag_reconf (elems_parse );
1030
1067
1031
1068
ieee80211_mle_defrag_epcs (elems_parse );
0 commit comments