[PATCH] AP: send TTLM if a link is indicated as disabled

Benjamin Berg benjamin at sipsolutions.net
Tue Jan 20 01:45:04 PST 2026


Hi,

note that the relevant patches got merged into wireless, so the test is
currently failing.

For reference:
 https://patch.msgid.link/20260118093904.754e057896a5.Ifd06f5ef839a93bfd54d0593dc932870f95f3242@changeid

Benjamin

On Thu, 2025-10-30 at 13:29 +0100, Benjamin Berg wrote:
> From: Benjamin Berg <benjamin.berg at intel.com>
> 
> When a link is indicated as disabled, then a corresponding TTLM
> should
> be sent. Add the appropriate code to generate the TTLM.
> 
> Co-authored-by: Ilan Peer <ilan.peer at intel.com>
> Signed-off-by: Benjamin Berg <benjamin.berg at intel.com>
> Signed-off-by: Ilan Peer <ilan.peer at intel.com>
> 
> ---
> 
> Hi,
> 
> we are going to queue some mac80211 fixes for TTLM handling during
> association. Without this fix, the eht_mld_owe_two_links_one_disabled
> hwsim test will start failing as mac80211 does not know that the
> second
> link is disabled.
> 
> Benjamin
> ---
>  src/ap/beacon.c              | 12 ++++++++
>  src/ap/ieee802_11.c          |  4 +++
>  src/ap/ieee802_11.h          |  3 ++
>  src/ap/ieee802_11_eht.c      | 57
> ++++++++++++++++++++++++++++++++++++
>  src/common/ieee802_11_defs.h | 10 +++++++
>  5 files changed, 86 insertions(+)
> 
> diff --git a/src/ap/beacon.c b/src/ap/beacon.c
> index 5a99611197..9ffff4f7d2 100644
> --- a/src/ap/beacon.c
> +++ b/src/ap/beacon.c
> @@ -797,6 +797,10 @@ static size_t
> hostapd_probe_resp_elems_len(struct hostapd_data *hapd,
>  			 * switch */
>  			buflen += 6;
>  		}
> +
> +		if (hapd->conf->mld_ap)
> +			buflen +=
> hostapd_eid_eht_ml_tid_to_link_map_len(
> +				hapd);
>  	}
>  #endif /* CONFIG_IEEE80211BE */
>  
> @@ -966,6 +970,9 @@ static u8 * hostapd_probe_resp_fill_elems(struct
> hostapd_data *hapd,
>  
>  		pos = hostapd_eid_eht_capab(hapd, pos,
> IEEE80211_MODE_AP);
>  		pos = hostapd_eid_eht_operation(hapd, pos);
> +
> +		if (hapd->conf->mld_ap)
> +			pos =
> hostapd_eid_eht_ml_tid_to_link_map(hapd, pos);
>  	}
>  #endif /* CONFIG_IEEE80211BE */
>  
> @@ -2256,6 +2263,8 @@ int ieee802_11_build_ap_params(struct
> hostapd_data *hapd,
>  		 */
>  		if (hapd->conf->mld_ap) {
>  			tail_len += 256;
> +			tail_len +=
> +				hostapd_eid_eht_ml_tid_to_link_map_l
> en(hapd);
>  
>  			/* for Max Channel Switch Time element
> during channel
>  			 * switch */
> @@ -2444,6 +2453,9 @@ int ieee802_11_build_ap_params(struct
> hostapd_data *hapd,
>  		tailpos = hostapd_eid_eht_capab(hapd, tailpos,
>  						IEEE80211_MODE_AP);
>  		tailpos = hostapd_eid_eht_operation(hapd, tailpos);
> +		if (hapd->conf->mld_ap)
> +			tailpos =
> hostapd_eid_eht_ml_tid_to_link_map(hapd,
> +								    
> tailpos);
>  	}
>  #endif /* CONFIG_IEEE80211BE */
>  
> diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
> index dc3b397c5f..49731cc965 100644
> --- a/src/ap/ieee802_11.c
> +++ b/src/ap/ieee802_11.c
> @@ -5411,6 +5411,8 @@ static u16 send_assoc_resp(struct hostapd_data
> *hapd, struct sta_info *sta,
>  		buflen += 3 + sizeof(struct
> ieee80211_eht_operation);
>  		if (hapd->iconf->punct_bitmap)
>  			buflen +=
> EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
> +		if (ap_sta_is_mld(hapd, sta))
> +			buflen +=
> hostapd_eid_eht_ml_tid_to_link_map_len(hapd);
>  	}
>  #endif /* CONFIG_IEEE80211BE */
>  
> @@ -5572,6 +5574,8 @@ rsnxe_done:
>  			p = hostapd_eid_eht_ml_assoc(hapd, sta, p);
>  		p = hostapd_eid_eht_capab(hapd, p,
> IEEE80211_MODE_AP);
>  		p = hostapd_eid_eht_operation(hapd, p);
> +		if (ap_sta_is_mld(hapd, sta))
> +			p = hostapd_eid_eht_ml_tid_to_link_map(hapd,
> p);
>  	}
>  #endif /* CONFIG_IEEE80211BE */
>  
> diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
> index 77704faaec..4764dc8ab8 100644
> --- a/src/ap/ieee802_11.h
> +++ b/src/ap/ieee802_11.h
> @@ -323,4 +323,7 @@ void hostapd_link_reconf_resp_tx_status(struct
> hostapd_data *hapd,
>  					const struct ieee80211_mgmt
> *mgmt,
>  					size_t len, int ok);
>  
> +size_t hostapd_eid_eht_ml_tid_to_link_map_len(struct hostapd_data
> *hapd);
> +u8 *hostapd_eid_eht_ml_tid_to_link_map(struct hostapd_data *hapd, u8
> *eid);
> +
>  #endif /* IEEE802_11_H */
> diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
> index ac36c9c48c..9a88dace4c 100644
> --- a/src/ap/ieee802_11_eht.c
> +++ b/src/ap/ieee802_11_eht.c
> @@ -2748,3 +2748,60 @@ void ieee802_11_rx_protected_eht_action(struct
> hostapd_data *hapd,
>  		   "MLD: Unsupported Protected EHT Action %u from "
> MACSTR
>  		   " discarded", action, MAC2STR(mgmt->sa));
>  }
> +
> +
> +size_t hostapd_eid_eht_ml_tid_to_link_map_len(struct hostapd_data
> *hapd)
> +{
> +	if (!hapd->conf->mld_ap)
> +		return 0;
> +
> +#ifdef CONFIG_TESTING_OPTIONS
> +	/*
> +	 * Allocate enough space for mld_indicate_disabled. i.e.:
> +	 *  EID, Length and extended EID (3) +
> +	 *  control including presence bitmap (2) + 8 * 2 byte link
> mappings
> +	 */
> +	return 3 + 2 + 8 * 2;
> +#else
> +	return 0;
> +#endif /* CONFIG_TESTING_OPTIONS */
> +}
> +
> +
> +u8 *hostapd_eid_eht_ml_tid_to_link_map(struct hostapd_data *hapd, u8
> *eid)
> +{
> +#ifdef CONFIG_TESTING_OPTIONS
> +	struct hostapd_data *other_hapd;
> +	bool need_ttlm = false;
> +	u16 ttlm = 0;
> +#endif
> +	u8 *pos = eid;
> +
> +	if (!hapd->conf->mld_ap)
> +		return eid;
> +
> +#ifdef CONFIG_TESTING_OPTIONS
> +	for_each_mld_link(other_hapd, hapd) {
> +		if (other_hapd->conf->mld_indicate_disabled)
> +			need_ttlm = true;
> +		else
> +			ttlm |= BIT(other_hapd->mld_link_id);
> +	}
> +
> +	if (need_ttlm) {
> +		*pos++ = WLAN_EID_EXTENSION;
> +		/* ext EID + 2 bytes control + 8 * link mappings */
> +		*pos++ = 1 + 2 + 8 * 2;
> +		*pos++ = WLAN_EID_EXT_TID_TO_LINK_MAPPING;
> +		*pos++ = EHT_TID_TO_LINK_MAP_DIRECTION_BOTH;
> +		*pos++ = 0xff; /* link mapping presence bitmap */
> +
> +		for (int i = 0; i < 8; i++) {
> +			WPA_PUT_LE16(pos, ttlm);
> +			pos += 2;
> +		}
> +	}
> +#endif /* CONFIG_TESTING_OPTIONS */
> +
> +	return pos;
> +}
> diff --git a/src/common/ieee802_11_defs.h
> b/src/common/ieee802_11_defs.h
> index 1d803660ca..9d8d0c2c56 100644
> --- a/src/common/ieee802_11_defs.h
> +++ b/src/common/ieee802_11_defs.h
> @@ -3103,6 +3103,16 @@ enum scs_direction {
>  #define EHT_QOS_CONTROL_INFO_PRESENCE_MASK_OFFSET	9
>  #define EHT_QOS_CONTROL_INFO_LINK_ID_OFFSET		25
>  
> +/* IEEE P802.11REVmf/D1.0, 9.4.2.325 (TID-To-Link Mapping element)
> */
> +#define EHT_TID_TO_LINK_MAP_DIRECTION_DOWN	0
> +#define EHT_TID_TO_LINK_MAP_DIRECTION_UP	1
> +#define EHT_TID_TO_LINK_MAP_DIRECTION_BOTH	2
> +#define EHT_TID_TO_LINK_MAP_DIRECTION_MSK	0x03
> +#define EHT_TID_TO_LINK_MAP_DEFAULT		0x04
> +#define EHT_TID_TO_LINK_MAP_SWITCH_TIME_PRESENT	0x08
> +#define EHT_TID_TO_LINK_MAP_EXPECT_DUR_PRESENT	0x10
> +#define EHT_TID_TO_LINK_MAP_LINK_MAPPING_SIZE	0x20
> +
>  /*
>   * IEEE P802.11be/D4.0, 9.4.2.316 QoS Characteristics element,
>   * Presence Bitmap Of Additional Parameters



More information about the Hostap mailing list