@@ -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
931951static void
@@ -973,15 +993,19 @@ ieee80211_mle_defrag_epcs(struct ieee80211_elems_parse *elems_parse)
973993struct ieee802_11_elems *
974994ieee802_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