@@ -3053,6 +3053,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
30533053 memset (sdata -> vif .bss_conf .tx_pwr_env , 0 ,
30543054 sizeof (sdata -> vif .bss_conf .tx_pwr_env ));
30553055
3056+ memset (& sdata -> u .mgd .ttlm_info , 0 ,
3057+ sizeof (sdata -> u .mgd .ttlm_info ));
3058+ wiphy_delayed_work_cancel (sdata -> local -> hw .wiphy , & ifmgd -> ttlm_work );
30563059 ieee80211_vif_set_links (sdata , 0 , 0 );
30573060}
30583061
@@ -5821,6 +5824,194 @@ static void ieee80211_ml_reconfiguration(struct ieee80211_sub_if_data *sdata,
58215824 TU_TO_JIFFIES (delay ));
58225825}
58235826
5827+ static void ieee80211_tid_to_link_map_work (struct wiphy * wiphy ,
5828+ struct wiphy_work * work )
5829+ {
5830+ u16 new_active_links , new_dormant_links ;
5831+ struct ieee80211_sub_if_data * sdata =
5832+ container_of (work , struct ieee80211_sub_if_data ,
5833+ u .mgd .ttlm_work .work );
5834+ int ret ;
5835+
5836+ new_active_links = sdata -> u .mgd .ttlm_info .map &
5837+ sdata -> vif .valid_links ;
5838+ new_dormant_links = ~sdata -> u .mgd .ttlm_info .map &
5839+ sdata -> vif .valid_links ;
5840+ if (!new_active_links ) {
5841+ ieee80211_disconnect (& sdata -> vif , false);
5842+ return ;
5843+ }
5844+
5845+ ieee80211_vif_set_links (sdata , sdata -> vif .valid_links , 0 );
5846+ new_active_links = BIT (ffs (new_active_links ) - 1 );
5847+ ieee80211_set_active_links (& sdata -> vif , new_active_links );
5848+
5849+ ret = ieee80211_vif_set_links (sdata , sdata -> vif .valid_links ,
5850+ new_dormant_links );
5851+
5852+ sdata -> u .mgd .ttlm_info .active = true;
5853+ sdata -> u .mgd .ttlm_info .switch_time = 0 ;
5854+
5855+ if (!ret )
5856+ ieee80211_vif_cfg_change_notify (sdata ,
5857+ BSS_CHANGED_MLD_VALID_LINKS );
5858+ }
5859+
5860+ static u16 ieee80211_get_ttlm (u8 bm_size , u8 * data )
5861+ {
5862+ if (bm_size == 1 )
5863+ return * data ;
5864+ else
5865+ return get_unaligned_le16 (data );
5866+ }
5867+
5868+ static int
5869+ ieee80211_parse_adv_t2l (struct ieee80211_sub_if_data * sdata ,
5870+ const struct ieee80211_ttlm_elem * ttlm ,
5871+ struct ieee80211_adv_ttlm_info * ttlm_info )
5872+ {
5873+ /* The element size was already validated in
5874+ * ieee80211_tid_to_link_map_size_ok()
5875+ */
5876+ u8 control , link_map_presence , map_size , tid ;
5877+ u8 * pos ;
5878+
5879+ memset (ttlm_info , 0 , sizeof (* ttlm_info ));
5880+ pos = (void * )ttlm -> optional ;
5881+ control = ttlm -> control ;
5882+
5883+ if ((control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP ) ||
5884+ !(control & IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT ))
5885+ return 0 ;
5886+
5887+ if ((control & IEEE80211_TTLM_CONTROL_DIRECTION ) !=
5888+ IEEE80211_TTLM_DIRECTION_BOTH ) {
5889+ sdata_info (sdata , "Invalid advertised T2L map direction\n" );
5890+ return - EINVAL ;
5891+ }
5892+
5893+ link_map_presence = * pos ;
5894+ pos ++ ;
5895+
5896+ ttlm_info -> switch_time = get_unaligned_le16 (pos );
5897+ pos += 2 ;
5898+
5899+ if (control & IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT ) {
5900+ ttlm_info -> duration = pos [0 ] | pos [1 ] << 8 | pos [2 ] << 16 ;
5901+ pos += 3 ;
5902+ }
5903+
5904+ if (control & IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE )
5905+ map_size = 1 ;
5906+ else
5907+ map_size = 2 ;
5908+
5909+ /* According to Draft P802.11be_D3.0 clause 35.3.7.1.7, an AP MLD shall
5910+ * not advertise a TID-to-link mapping that does not map all TIDs to the
5911+ * same link set, reject frame if not all links have mapping
5912+ */
5913+ if (link_map_presence != 0xff ) {
5914+ sdata_info (sdata ,
5915+ "Invalid advertised T2L mapping presence indicator\n" );
5916+ return - EINVAL ;
5917+ }
5918+
5919+ ttlm_info -> map = ieee80211_get_ttlm (map_size , pos );
5920+ if (!ttlm_info -> map ) {
5921+ sdata_info (sdata ,
5922+ "Invalid advertised T2L map for TID 0\n" );
5923+ return - EINVAL ;
5924+ }
5925+
5926+ pos += map_size ;
5927+
5928+ for (tid = 1 ; tid < 8 ; tid ++ ) {
5929+ u16 map = ieee80211_get_ttlm (map_size , pos );
5930+
5931+ if (map != ttlm_info -> map ) {
5932+ sdata_info (sdata , "Invalid advertised T2L map for tid %d\n" ,
5933+ tid );
5934+ return - EINVAL ;
5935+ }
5936+
5937+ pos += map_size ;
5938+ }
5939+ return 0 ;
5940+ }
5941+
5942+ static void ieee80211_process_adv_ttlm (struct ieee80211_sub_if_data * sdata ,
5943+ struct ieee802_11_elems * elems ,
5944+ u64 beacon_ts )
5945+ {
5946+ u8 i ;
5947+ int ret ;
5948+
5949+ if (!ieee80211_vif_is_mld (& sdata -> vif ))
5950+ return ;
5951+
5952+ if (!elems -> ttlm_num ) {
5953+ if (sdata -> u .mgd .ttlm_info .switch_time ) {
5954+ /* if a planned TID-to-link mapping was cancelled -
5955+ * abort it
5956+ */
5957+ wiphy_delayed_work_cancel (sdata -> local -> hw .wiphy ,
5958+ & sdata -> u .mgd .ttlm_work );
5959+ } else if (sdata -> u .mgd .ttlm_info .active ) {
5960+ /* if no TID-to-link element, set to default mapping in
5961+ * which all TIDs are mapped to all setup links
5962+ */
5963+ ret = ieee80211_vif_set_links (sdata ,
5964+ sdata -> vif .valid_links ,
5965+ 0 );
5966+ if (ret ) {
5967+ sdata_info (sdata , "Failed setting valid/dormant links\n" );
5968+ return ;
5969+ }
5970+ ieee80211_vif_cfg_change_notify (sdata ,
5971+ BSS_CHANGED_MLD_VALID_LINKS );
5972+ }
5973+ memset (& sdata -> u .mgd .ttlm_info , 0 ,
5974+ sizeof (sdata -> u .mgd .ttlm_info ));
5975+ return ;
5976+ }
5977+
5978+ for (i = 0 ; i < elems -> ttlm_num ; i ++ ) {
5979+ struct ieee80211_adv_ttlm_info ttlm_info ;
5980+ u32 res ;
5981+
5982+ res = ieee80211_parse_adv_t2l (sdata , elems -> ttlm [i ],
5983+ & ttlm_info );
5984+
5985+ if (res ) {
5986+ __ieee80211_disconnect (sdata );
5987+ return ;
5988+ }
5989+
5990+ if (ttlm_info .switch_time ) {
5991+ u32 st_us , delay = 0 ;
5992+ u32 ts_l26 = beacon_ts & GENMASK (25 , 0 );
5993+
5994+ /* The t2l map switch time is indicated with a partial
5995+ * TSF value, convert it to TSF and calc the delay
5996+ * to the start time.
5997+ */
5998+ st_us = ieee80211_tu_to_usec (ttlm_info .switch_time );
5999+ if (st_us > ts_l26 )
6000+ delay = st_us - ts_l26 ;
6001+ else
6002+ continue ;
6003+
6004+ sdata -> u .mgd .ttlm_info = ttlm_info ;
6005+ wiphy_delayed_work_cancel (sdata -> local -> hw .wiphy ,
6006+ & sdata -> u .mgd .ttlm_work );
6007+ wiphy_delayed_work_queue (sdata -> local -> hw .wiphy ,
6008+ & sdata -> u .mgd .ttlm_work ,
6009+ usecs_to_jiffies (delay ));
6010+ return ;
6011+ }
6012+ }
6013+ }
6014+
58246015static void ieee80211_rx_mgmt_beacon (struct ieee80211_link_data * link ,
58256016 struct ieee80211_hdr * hdr , size_t len ,
58266017 struct ieee80211_rx_status * rx_status )
@@ -6144,6 +6335,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
61446335 }
61456336
61466337 ieee80211_ml_reconfiguration (sdata , elems );
6338+ ieee80211_process_adv_ttlm (sdata , elems ,
6339+ le64_to_cpu (mgmt -> u .beacon .timestamp ));
61476340
61486341 ieee80211_link_info_change_notify (sdata , link , changed );
61496342free :
@@ -6766,6 +6959,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
67666959 timer_setup (& ifmgd -> conn_mon_timer , ieee80211_sta_conn_mon_timer , 0 );
67676960 wiphy_delayed_work_init (& ifmgd -> tx_tspec_wk ,
67686961 ieee80211_sta_handle_tspec_ac_params_wk );
6962+ wiphy_delayed_work_init (& ifmgd -> ttlm_work ,
6963+ ieee80211_tid_to_link_map_work );
67696964
67706965 ifmgd -> flags = 0 ;
67716966 ifmgd -> powersave = sdata -> wdev .ps ;
@@ -7840,6 +8035,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
78408035 & ifmgd -> tdls_peer_del_work );
78418036 wiphy_delayed_work_cancel (sdata -> local -> hw .wiphy ,
78428037 & ifmgd -> ml_reconf_work );
8038+ wiphy_delayed_work_cancel (sdata -> local -> hw .wiphy , & ifmgd -> ttlm_work );
78438039
78448040 if (ifmgd -> assoc_data )
78458041 ieee80211_destroy_assoc_data (sdata , ASSOC_TIMEOUT );
0 commit comments