@@ -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+
61646256static 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-
70877112static 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