diff mbox series

[RFC,v2,1/2] wifi: cfg80211/mac80211: Introduce nl80211 commands to support MLD link removal offload

Message ID 20240404185950.776062-2-quic_mdharane@quicinc.com
State Superseded
Headers show
Series Add Multi-Link Reconfigure link removal support | expand

Commit Message

Manish Dharanenthiran April 4, 2024, 6:59 p.m. UTC
This is a preparation for supporting Multi-Link reconfigure link removal
procedure[IEEE P802.11be/D5.0 - 35.3.6.3 Removing affiliated APs] for
driver which supports offloaded Multi-Link reconfigure link removal.

Multi-Link reconfigure link removal offloaded drivers will take care of
updating the reconfiguration MLE in self and partner beacons. It also
updates the AP removal timer automatically and notifies once the counter
is expired.

For such drivers AP link removal count(TBTT) and reconfiguration MLE
needs to be passed from userspace. AP link removal count indicates the
number of beacons the reconfiguration MLE will be present, after which
the link will be removed. To support this, NL80211_ATTR_AP_REMOVAL_COUNT
and NL80211_ATTR_IE are used.

In beacon offloaded drivers, to indicate status of ongoing link removal,
add two new commands NL80211_CMD_LINK_REMOVAL_STARTED,
NL80211_CMD_LINK_REMOVAL_COMPLETED. NL80211_CMD_LINK_REMOVAL_STARTED
will update timestamp of first beacon sent with reconfiguration MLE
using NL80211_ATTR_TSF attribute.

Co-developed-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Manish Dharanenthiran <quic_mdharane@quicinc.com>
---
 include/net/cfg80211.h       | 52 +++++++++++++++++++++
 include/uapi/linux/nl80211.h | 30 +++++++++++++
 net/wireless/core.h          |  2 +
 net/wireless/nl80211.c       | 87 ++++++++++++++++++++++++++++++++++++
 net/wireless/rdev-ops.h      | 17 +++++++
 net/wireless/trace.h         | 58 ++++++++++++++++++++++++
 net/wireless/util.c          | 17 +++++++
 7 files changed, 263 insertions(+)

Comments

Johannes Berg June 26, 2024, 9:28 a.m. UTC | #1
On Fri, 2024-04-05 at 00:29 +0530, Manish Dharanenthiran wrote:
> This is a preparation for supporting Multi-Link reconfigure link removal
> procedure[IEEE P802.11be/D5.0 - 35.3.6.3 Removing affiliated APs] for
> driver which supports offloaded Multi-Link reconfigure link removal.
> 
> Multi-Link reconfigure link removal offloaded drivers will take care of
> updating the reconfiguration MLE in self and partner beacons. It also
> updates the AP removal timer automatically and notifies once the counter
> is expired.

How do we distinguish those drivers from others that won't (be able to)
do this as we had discussed also for the CSA flows?

> +/**
> + * struct cfg80211_link_reconfig_removal_params - Contains params needed for
> + * link reconfig removal

nit: maybe indent the second line with a tab? is that possible? it's a
bit confusing to go into the parameters right away without any visual
separation, IMHO.

> + * @link_removal_cntdown: TBTT countdown value until which the beacon with ML
> + *	reconfigure element will be sent.
> + * @reconfigure_elem: ML reconfigure element to be updated in beacon in the link going to be
> + *	removed and in all affiliated links.
> + * @elem_len: ML reconfigure element length
> + * @link_id: Link id of the link to be removed.
> + */
> +struct cfg80211_link_reconfig_removal_params {
> +	u16 link_removal_cntdown;
> +	const u8 *reconfigure_elem;
> +	size_t elem_len;
> +	unsigned int link_id;

nit: I guess the size of this doesn't really matter, but putting a
pointer after a u16 always feels wrong because it adds 6 bytes of
padding on 64-bit :)

> +/**
> + * cfg80211_update_link_reconfig_remove_update - Inform userspace about
> + *	the removal status of link which is scheduled for removal

here you did a tab btw :)

> + * This function is used to inform userspace about the ongoing link removal
> + * status. 'NL80211_CMD_LINK_REMOVAL_STARTED' is issued when the first beacon with

Please use %NL80211_CMD_LINK_REMOVAL_STARTED which would print it as a
constant, instead of '...'.

> + * ML reconfigure element is sent out. This event can be used by userspace to start
> + * the BTM in case of AP mode. And, NL80211_CMD_LINK_REMOVAL_COMPLETED is issued

same here

> + * when the last beacon is sent with ML reconfigure element. This is used to
> + * initiate the deletion of that link, also to trigger deauth/disassoc for the
> + * associated peer(s).
> + *
> + * Note: This API is currently used by drivers which supports offloaded
> + * Multi-Link reconfigure link removal. Returns failure if FEATURE FLAG is not

"FEATURE FLAG" was ... some kind of placeholder?

Should this even return a value? What are you going to do with it?

You should also document the context this can be called in.


> + * @NL80211_ATTR_TSF: (u64) TSF value when the first beacon with reconfiguration
> + *	MLE is sent.

What's that needed for, btw?

> +++ b/net/wireless/nl80211.c
> @@ -826,6 +826,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
>  	[NL80211_ATTR_MLO_TTLM_DLINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
>  	[NL80211_ATTR_MLO_TTLM_ULINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
>  	[NL80211_ATTR_ASSOC_SPP_AMSDU] = { .type = NLA_FLAG },
> +	[NL80211_ATTR_AP_REMOVAL_COUNT] = { .type = NLA_U8 },

No range? I guess 0 might be an issue?

> +	[NL80211_ATTR_TSF] = { .type = NLA_U64 },

If the TSF is output only maybe it should not have a policy for input?

> @@ -16103,6 +16105,7 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
>  	unsigned int link_id = nl80211_link_id(info->attrs);
>  	struct net_device *dev = info->user_ptr[1];
>  	struct wireless_dev *wdev = dev->ieee80211_ptr;
> +	struct cfg80211_link_reconfig_removal_params params = {};

that can move into the if

> @@ -16115,6 +16118,30 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
>  		return -EINVAL;
>  	}
>  
> +	if (info->attrs[NL80211_ATTR_AP_REMOVAL_COUNT]) {
> +		/* Parsing and sending information to driver about ML
> +		 * reconfiguration is supported only when
> +		 * NL80211_EXT_FEATURE_MLD_LINK_REMOVAL_OFFLOAD is set
> +		 */
> +		if (!wiphy_ext_feature_isset(wdev->wiphy,
> +					     NL80211_EXT_FEATURE_MLD_LINK_REMOVAL_OFFLOAD))
> +			return -EOPNOTSUPP;
> +
> +		/* If AP removal count is present, it is mandatory to have IE
> +		 * attribute as well, return error if not present
> +		 */
> +		if (!info->attrs[NL80211_ATTR_IE])
> +			return -EINVAL;
> +
> +		params.reconfigure_elem = nla_data(info->attrs[NL80211_ATTR_IE]);
> +		params.elem_len = nla_len(info->attrs[NL80211_ATTR_IE]);
> +		params.link_removal_cntdown =
> +			nla_get_u16(info->attrs[NL80211_ATTR_AP_REMOVAL_COUNT]);

doesn't match the policy ... but policy also doesn't match
documentation, so I think policy is wrong?

> +int
> +cfg80211_update_link_reconfig_remove_update(struct net_device *netdev,
> +					    unsigned int link_id,
> +					    u8 tbtt_count, u64 tsf,
> +					    enum nl80211_commands cmd)
> +{

[...]

> + nla_put_failure:
> +	genlmsg_cancel(msg, hdr);
> +	nlmsg_free(msg);

nit: no need to cancel before free

> +TRACE_EVENT(rdev_link_reconfig_remove,
> +	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
> +		 const struct cfg80211_link_reconfig_removal_params *params),
> +
> +	TP_ARGS(wiphy, netdev, params),
> +
> +	TP_STRUCT__entry(
> +		WIPHY_ENTRY
> +		NETDEV_ENTRY
> +		__field(u32, link_id)
> +		__field(u16, count)
> +		__dynamic_array(u8, frame, params->elem_len)
> +	),
> +
> +	TP_fast_assign(
> +		WIPHY_ASSIGN;
> +		NETDEV_ASSIGN;
> +		__entry->link_id = params->link_id;
> +		__entry->count = params->link_removal_cntdown;
> +		memcpy(__get_dynamic_array(frame), params->reconfigure_elem,
> +		       params->elem_len);
> +	),
> +
> +	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %u frame:0x%.2x count:%d",
> +		  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id,
> +		  le16_to_cpup((__le16 *)__get_dynamic_array(frame)), __entry->count)

What's that frame argument?! Need to check it's long enough? But ... is
that worth it at all to try to print it here in this way? Maybe with
%*pH but then you don't get all of it either? Or just leave it, and
write a small plugin if needed?

> +int cfg80211_link_reconfig_remove(struct wireless_dev *wdev,
> +				  const struct cfg80211_link_reconfig_removal_params *params)
> +{
> +	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
> +
> +	lockdep_assert_wiphy(wdev->wiphy);
> +
> +	/* Currently, removal of link from MLD is supported for AP BSS only, it
> +	 * can be extended for non-AP/STA MLD as well but that shall use
> +	 * action frame to update about its link reconfiguration.
> +	 */
> +	if (wdev->iftype == NL80211_IFTYPE_AP)
> +		return rdev_link_reconfig_remove(rdev, wdev->netdev, params);
> +
> +	return -EINVAL;


Would kind of feel to better be

 if (iftype != ...) return -EINVAL;

 ... normal flow

johannes
Manish Dharanenthiran July 3, 2024, 10:06 a.m. UTC | #2
On 6/26/2024 2:58 PM, Johannes Berg wrote:
> On Fri, 2024-04-05 at 00:29 +0530, Manish Dharanenthiran wrote:
>> This is a preparation for supporting Multi-Link reconfigure link removal
>> procedure[IEEE P802.11be/D5.0 - 35.3.6.3 Removing affiliated APs] for
>> driver which supports offloaded Multi-Link reconfigure link removal.
>>
>> Multi-Link reconfigure link removal offloaded drivers will take care of
>> updating the reconfiguration MLE in self and partner beacons. It also
>> updates the AP removal timer automatically and notifies once the counter
>> is expired.
> 
> How do we distinguish those drivers from others that won't (be able to)
> do this as we had discussed also for the CSA flows?

Similar to CSA, where the beacon synchronization between partner links 
will be handled in the respective firmware, updating the reconfiguration 
element in the partner link gets handled by the firmware as well, so the 
driver needs to send only the reconfiguration element to the affected 
link. To do this, in the other discussion we were leaning on introducing 
a new feature flag like "FW_HANDLES_PARTNER_LINK_CSA" or 
"BEACON_OFFLOADED_DRIVER" which indicates that beacon synchronization 
will be handled in the respective firmware itself. To achieve that in 
this RFC, we have added a feature flag named 
[%NL80211_EXT_FEATURE_MLD_LINK_REMOVAL_OFFLOAD] in wiphy level. If its 
set, reconfiguration element will be sent to driver and only when the 
driver sends the signal back to userspace to start BTM or the actual 
link termination, hostapd will take actions. Whereas, in other drivers, 
hostapd would ideally run a decrementing timer based on the count given 
and once it reaches zero, that particular link will be terminated.

Also, probe response and assoc response gets handled in the userspace 
even in the offloaded drivers. To update the latest AP removal 
timer(TBTT) firmware will send the latest count and the tsf value of the 
beacon to driver which will eventually pass to hostapd, so the hostapd 
can take care of adding the reconfiguration element while sending the 
response.

> 
>> +/**
>> + * struct cfg80211_link_reconfig_removal_params - Contains params needed for
>> + * link reconfig removal
> 
> nit: maybe indent the second line with a tab? is that possible? it's a
> bit confusing to go into the parameters right away without any visual
> separation, IMHO.
> 
Sure, will address this. Thought aligning with the other API(s) in this 
file.

>> + * @link_removal_cntdown: TBTT countdown value until which the beacon with ML
>> + *	reconfigure element will be sent.
>> + * @reconfigure_elem: ML reconfigure element to be updated in beacon in the link going to be
>> + *	removed and in all affiliated links.
>> + * @elem_len: ML reconfigure element length
>> + * @link_id: Link id of the link to be removed.
>> + */
>> +struct cfg80211_link_reconfig_removal_params {
>> +	u16 link_removal_cntdown;
>> +	const u8 *reconfigure_elem;
>> +	size_t elem_len;
>> +	unsigned int link_id;
> 
> nit: I guess the size of this doesn't really matter, but putting a
> pointer after a u16 always feels wrong because it adds 6 bytes of
> padding on 64-bit :)
> 
size of this is to send the reconfigure_elem length. Will check, if it 
can be removed or modified accordingly without affecting much on the 
padding.

>> +/**
>> + * cfg80211_update_link_reconfig_remove_update - Inform userspace about
>> + *	the removal status of link which is scheduled for removal
> 
> here you did a tab btw :)
Will change in the above line as well :)
> 
>> + * This function is used to inform userspace about the ongoing link removal
>> + * status. 'NL80211_CMD_LINK_REMOVAL_STARTED' is issued when the first beacon with
> 
> Please use %NL80211_CMD_LINK_REMOVAL_STARTED which would print it as a
> constant, instead of '...'.
> 
>> + * ML reconfigure element is sent out. This event can be used by userspace to start
>> + * the BTM in case of AP mode. And, NL80211_CMD_LINK_REMOVAL_COMPLETED is issued
> 
> same here
> 
Sure, will address in both the places.

>> + * when the last beacon is sent with ML reconfigure element. This is used to
>> + * initiate the deletion of that link, also to trigger deauth/disassoc for the
>> + * associated peer(s).
>> + *
>> + * Note: This API is currently used by drivers which supports offloaded
>> + * Multi-Link reconfigure link removal. Returns failure if FEATURE FLAG is not
> 
> "FEATURE FLAG" was ... some kind of placeholder?
> 
> Should this even return a value? What are you going to do with it?
> 
Yes, initially thought that if we have a return driver using this will 
take necessary action with this. Kindly let me know, if you prefer a 
void API and do those validation prior calling this API.

> You should also document the context this can be called in.
> 
Yeah initially it was put as a placeholder but I should have updated 
after introducing the actual flag. Missed to do that. Will update in 
next version, also document the context.
> 
>> + * @NL80211_ATTR_TSF: (u64) TSF value when the first beacon with reconfiguration
>> + *	MLE is sent.
> 
> What's that needed for, btw?
>
This TSF will be used to calculate the BTM message. When the first 
beacon with reconfiguration element is sent out, we will receive this 
from firmware with the timestamp of the first beacon, once that is sent 
to userspace, hostapd will then calculate the BSS termination timestamp 
from this.

>> +++ b/net/wireless/nl80211.c
>> @@ -826,6 +826,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
>>   	[NL80211_ATTR_MLO_TTLM_DLINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
>>   	[NL80211_ATTR_MLO_TTLM_ULINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
>>   	[NL80211_ATTR_ASSOC_SPP_AMSDU] = { .type = NLA_FLAG },
>> +	[NL80211_ATTR_AP_REMOVAL_COUNT] = { .type = NLA_U8 },
> 
> No range? I guess 0 might be an issue?
0 will not be actually used, but it won't harm as well. Hence, didn't 
add any range for this.
> 
>> +	[NL80211_ATTR_TSF] = { .type = NLA_U64 },
> 
> If the TSF is output only maybe it should not have a policy for input?

> 
>> @@ -16103,6 +16105,7 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
>>   	unsigned int link_id = nl80211_link_id(info->attrs);
>>   	struct net_device *dev = info->user_ptr[1];
>>   	struct wireless_dev *wdev = dev->ieee80211_ptr;
>> +	struct cfg80211_link_reconfig_removal_params params = {};
> 
> that can move into the if
Sure. will address in next version.
> 
>> @@ -16115,6 +16118,30 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
>>   		return -EINVAL;
>>   	}
>>   
>> +	if (info->attrs[NL80211_ATTR_AP_REMOVAL_COUNT]) {
>> +		/* Parsing and sending information to driver about ML
>> +		 * reconfiguration is supported only when
>> +		 * NL80211_EXT_FEATURE_MLD_LINK_REMOVAL_OFFLOAD is set
>> +		 */
>> +		if (!wiphy_ext_feature_isset(wdev->wiphy,
>> +					     NL80211_EXT_FEATURE_MLD_LINK_REMOVAL_OFFLOAD))
>> +			return -EOPNOTSUPP;
>> +
>> +		/* If AP removal count is present, it is mandatory to have IE
>> +		 * attribute as well, return error if not present
>> +		 */
>> +		if (!info->attrs[NL80211_ATTR_IE])
>> +			return -EINVAL;
>> +
>> +		params.reconfigure_elem = nla_data(info->attrs[NL80211_ATTR_IE]);
>> +		params.elem_len = nla_len(info->attrs[NL80211_ATTR_IE]);
>> +		params.link_removal_cntdown =
>> +			nla_get_u16(info->attrs[NL80211_ATTR_AP_REMOVAL_COUNT]);
> 
> doesn't match the policy ... but policy also doesn't match
> documentation, so I think policy is wrong?
> 
oh sorry! Should have updated the policy accordingly. Missed while 
updating the patch. Will address this in next version.
>> +int
>> +cfg80211_update_link_reconfig_remove_update(struct net_device *netdev,
>> +					    unsigned int link_id,
>> +					    u8 tbtt_count, u64 tsf,
>> +					    enum nl80211_commands cmd)
>> +{
> 
> [...]
> 
>> + nla_put_failure:
>> +	genlmsg_cancel(msg, hdr);
>> +	nlmsg_free(msg);
> 
> nit: no need to cancel before free
> 
Sure, will address.

>> +TRACE_EVENT(rdev_link_reconfig_remove,
>> +	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
>> +		 const struct cfg80211_link_reconfig_removal_params *params),
>> +
>> +	TP_ARGS(wiphy, netdev, params),
>> +
>> +	TP_STRUCT__entry(
>> +		WIPHY_ENTRY
>> +		NETDEV_ENTRY
>> +		__field(u32, link_id)
>> +		__field(u16, count)
>> +		__dynamic_array(u8, frame, params->elem_len)
>> +	),
>> +
>> +	TP_fast_assign(
>> +		WIPHY_ASSIGN;
>> +		NETDEV_ASSIGN;
>> +		__entry->link_id = params->link_id;
>> +		__entry->count = params->link_removal_cntdown;
>> +		memcpy(__get_dynamic_array(frame), params->reconfigure_elem,
>> +		       params->elem_len);
>> +	),
>> +
>> +	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %u frame:0x%.2x count:%d",
>> +		  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id,
>> +		  le16_to_cpup((__le16 *)__get_dynamic_array(frame)), __entry->count)
> 
> What's that frame argument?! Need to check it's long enough? But ... is
> that worth it at all to try to print it here in this way? Maybe with
> %*pH but then you don't get all of it either? Or just leave it, and
> write a small plugin if needed?
> 
I didn't had much insight while writing the trace API. But, once i gone 
through the code, the dynamic array was used in places where there is a 
need to print IE(s) and few other similar things.

>> +int cfg80211_link_reconfig_remove(struct wireless_dev *wdev,
>> +				  const struct cfg80211_link_reconfig_removal_params *params)
>> +{
>> +	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
>> +
>> +	lockdep_assert_wiphy(wdev->wiphy);
>> +
>> +	/* Currently, removal of link from MLD is supported for AP BSS only, it
>> +	 * can be extended for non-AP/STA MLD as well but that shall use
>> +	 * action frame to update about its link reconfiguration.
>> +	 */
>> +	if (wdev->iftype == NL80211_IFTYPE_AP)
>> +		return rdev_link_reconfig_remove(rdev, wdev->netdev, params);
>> +
>> +	return -EINVAL;
> 
> 
> Would kind of feel to better be
> 
>   if (iftype != ...) return -EINVAL;
> 
>   ... normal flow
> 
Sure, will correct this.
> johannes

Thanks Johannes for the review, will address the comments and update the 
next version.

Regards
Manish Dharanenthiran.
diff mbox series

Patch

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2e2be4fd2bb6..e016fd096373 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4169,6 +4169,23 @@  struct mgmt_frame_regs {
 	u32 global_mcast_stypes, interface_mcast_stypes;
 };
 
+/**
+ * struct cfg80211_link_reconfig_removal_params - Contains params needed for
+ * link reconfig removal
+ * @link_removal_cntdown: TBTT countdown value until which the beacon with ML
+ *	reconfigure element will be sent.
+ * @reconfigure_elem: ML reconfigure element to be updated in beacon in the link going to be
+ *	removed and in all affiliated links.
+ * @elem_len: ML reconfigure element length
+ * @link_id: Link id of the link to be removed.
+ */
+struct cfg80211_link_reconfig_removal_params {
+	u16 link_removal_cntdown;
+	const u8 *reconfigure_elem;
+	size_t elem_len;
+	unsigned int link_id;
+};
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -4570,6 +4587,11 @@  struct mgmt_frame_regs {
  *
  * @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames.
  * @set_ttlm: set the TID to link mapping.
+ *
+ * @link_reconfig_remove: Notifies the driver about the link to be
+ *	scheduled for removal with ML reconfigure element built for that particular
+ *	link along with the TBTT count until which the beacon with ML
+ *	reconfigure element should be sent.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4931,6 +4953,9 @@  struct cfg80211_ops {
 				    struct cfg80211_set_hw_timestamp *hwts);
 	int	(*set_ttlm)(struct wiphy *wiphy, struct net_device *dev,
 			    struct cfg80211_ttlm_params *params);
+	int	(*link_reconfig_remove)(struct wiphy *wiphy,
+					struct net_device *dev,
+					const struct cfg80211_link_reconfig_removal_params *params);
 };
 
 /*
@@ -9509,4 +9534,31 @@  ssize_t wiphy_locked_debugfs_write(struct wiphy *wiphy, struct file *file,
 				   void *data);
 #endif
 
+/**
+ * cfg80211_update_link_reconfig_remove_update - Inform userspace about
+ *	the removal status of link which is scheduled for removal
+ * @dev: the device on which the operation is requested
+ * @link_id: Link which is undergoing removal
+ * @tbtt_count: Current tbtt_count to be updated.
+ * @tsf: Beacon's timestamp value
+ * @cmd: Inform started or completed action to userspace based on the value
+ *
+ * This function is used to inform userspace about the ongoing link removal
+ * status. 'NL80211_CMD_LINK_REMOVAL_STARTED' is issued when the first beacon with
+ * ML reconfigure element is sent out. This event can be used by userspace to start
+ * the BTM in case of AP mode. And, NL80211_CMD_LINK_REMOVAL_COMPLETED is issued
+ * when the last beacon is sent with ML reconfigure element. This is used to
+ * initiate the deletion of that link, also to trigger deauth/disassoc for the
+ * associated peer(s).
+ *
+ * Note: This API is currently used by drivers which supports offloaded
+ * Multi-Link reconfigure link removal. Returns failure if FEATURE FLAG is not
+ * set or success if NL message is sent.
+ */
+int
+cfg80211_update_link_reconfig_remove_update(struct net_device *dev,
+					    unsigned int link_id,
+					    u8 tbtt_count, u64 tsf,
+					    enum nl80211_commands cmd);
+
 #endif /* __NET_CFG80211_H */
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f917bc6c9b6f..5d09140fd070 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1304,6 +1304,10 @@ 
  * @NL80211_CMD_REMOVE_LINK: Remove a link from an interface. This may come
  *	without %NL80211_ATTR_MLO_LINK_ID as an easy way to remove all links
  *	in preparation for e.g. roaming to a regular (non-MLO) AP.
+ *	To initiate link removal procedure, set below attributes,
+ *	%NL80211_ATTR_AP_REMOVAL_COUNT - AP removal timer count(TBTT)
+ *	%NL80211_ATTR_IE - ML reconfigure Information element
+ *	Can be extended to update multiple TBTT & element(s).
  *
  * @NL80211_CMD_ADD_LINK_STA: Add a link to an MLD station
  * @NL80211_CMD_MODIFY_LINK_STA: Modify a link of an MLD station
@@ -1329,6 +1333,14 @@ 
  *      %NL80211_ATTR_MLO_TTLM_ULINK attributes are used to specify the
  *      TID to Link mapping for downlink/uplink traffic.
  *
+ * @NL80211_CMD_LINK_REMOVAL_STARTED: Once first beacon with reconfiguration MLE
+ *	is sent, userspace is notified with the TBTT and TSF value to indicate
+ *	timestamp of that beacon using %NL80211_ATTR_AP_REMOVAL_COUNT and
+ *	%NL80211_ATTR_TSF respectively.
+ *
+ * @NL80211_CMD_LINK_REMOVAL_COMPLETED: Once last beacon with reconfiguration
+ *	MLE is sent, userspace is notified with completion.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1586,6 +1598,10 @@  enum nl80211_commands {
 
 	NL80211_CMD_SET_TID_TO_LINK_MAPPING,
 
+	NL80211_CMD_LINK_REMOVAL_STARTED,
+
+	NL80211_CMD_LINK_REMOVAL_COMPLETED,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -2856,6 +2872,13 @@  enum nl80211_commands {
  *	%NL80211_CMD_ASSOCIATE indicating the SPP A-MSDUs
  *	are used on this connection
  *
+ * @NL80211_ATTR_AP_REMOVAL_COUNT: (u16) TBTT count up-to which reconfiguration
+ *	MLE is sent. Also, userspace will be notified with this count once the
+ *	first beacon with reconfiguration MLE is sent.
+ *
+ * @NL80211_ATTR_TSF: (u64) TSF value when the first beacon with reconfiguration
+ *	MLE is sent.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3401,6 +3424,9 @@  enum nl80211_attrs {
 
 	NL80211_ATTR_ASSOC_SPP_AMSDU,
 
+	NL80211_ATTR_AP_REMOVAL_COUNT,
+	NL80211_ATTR_TSF,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -6545,6 +6571,9 @@  enum nl80211_feature_flags {
  *	(signaling and payload protected) A-MSDUs and this shall be advertised
  *	in the RSNXE.
  *
+ * @NL80211_EXT_FEATURE_MLD_LINK_REMOVAL_OFFLOAD: Driver/device which supports
+ *	ML reconfig link removal offload.
+ *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
  */
@@ -6620,6 +6649,7 @@  enum nl80211_ext_feature_index {
 	NL80211_EXT_FEATURE_OWE_OFFLOAD_AP,
 	NL80211_EXT_FEATURE_DFS_CONCURRENT,
 	NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT,
+	NL80211_EXT_FEATURE_MLD_LINK_REMOVAL_OFFLOAD,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 118f2f619828..ce1a1aa048e2 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -552,6 +552,8 @@  void cfg80211_remove_links(struct wireless_dev *wdev);
 int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev,
 				 struct wireless_dev *wdev);
 void cfg80211_wdev_release_link_bsses(struct wireless_dev *wdev, u16 link_mask);
+int cfg80211_link_reconfig_remove(struct wireless_dev *wdev,
+				  const struct cfg80211_link_reconfig_removal_params *params);
 
 /**
  * struct cfg80211_colocated_ap - colocated AP information
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b4edba6b0b7b..6a1a9e370cde 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -826,6 +826,8 @@  static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 	[NL80211_ATTR_MLO_TTLM_DLINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
 	[NL80211_ATTR_MLO_TTLM_ULINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
 	[NL80211_ATTR_ASSOC_SPP_AMSDU] = { .type = NLA_FLAG },
+	[NL80211_ATTR_AP_REMOVAL_COUNT] = { .type = NLA_U8 },
+	[NL80211_ATTR_TSF] = { .type = NLA_U64 },
 };
 
 /* policy for the key attributes */
@@ -16103,6 +16105,7 @@  static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
 	unsigned int link_id = nl80211_link_id(info->attrs);
 	struct net_device *dev = info->user_ptr[1];
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_link_reconfig_removal_params params = {};
 
 	/* cannot remove if there's no link */
 	if (!info->attrs[NL80211_ATTR_MLO_LINK_ID])
@@ -16115,6 +16118,30 @@  static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 	}
 
+	if (info->attrs[NL80211_ATTR_AP_REMOVAL_COUNT]) {
+		/* Parsing and sending information to driver about ML
+		 * reconfiguration is supported only when
+		 * NL80211_EXT_FEATURE_MLD_LINK_REMOVAL_OFFLOAD is set
+		 */
+		if (!wiphy_ext_feature_isset(wdev->wiphy,
+					     NL80211_EXT_FEATURE_MLD_LINK_REMOVAL_OFFLOAD))
+			return -EOPNOTSUPP;
+
+		/* If AP removal count is present, it is mandatory to have IE
+		 * attribute as well, return error if not present
+		 */
+		if (!info->attrs[NL80211_ATTR_IE])
+			return -EINVAL;
+
+		params.reconfigure_elem = nla_data(info->attrs[NL80211_ATTR_IE]);
+		params.elem_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+		params.link_removal_cntdown =
+			nla_get_u16(info->attrs[NL80211_ATTR_AP_REMOVAL_COUNT]);
+		params.link_id = link_id;
+
+		return cfg80211_link_reconfig_remove(wdev, &params);
+	}
+
 	cfg80211_remove_link(wdev, link_id);
 
 	return 0;
@@ -20214,6 +20241,66 @@  void cfg80211_schedule_channels_check(struct wireless_dev *wdev)
 }
 EXPORT_SYMBOL(cfg80211_schedule_channels_check);
 
+int
+cfg80211_update_link_reconfig_remove_update(struct net_device *netdev,
+					    unsigned int link_id,
+					    u8 tbtt_count, u64 tsf,
+					    enum nl80211_commands cmd)
+{
+	struct wireless_dev *wdev = netdev->ieee80211_ptr;
+	struct wiphy *wiphy = wdev->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+	struct sk_buff *msg;
+	void *hdr;
+
+	/* Only for ML reconfigure link removal offloaded driver, need to
+	 * update the status about the ongoing link removal to userspace.
+	 */
+	if (!wiphy_ext_feature_isset(wiphy,
+				     NL80211_EXT_FEATURE_MLD_LINK_REMOVAL_OFFLOAD))
+		return -EOPNOTSUPP;
+
+	if (link_id >= 0 || !(wdev->valid_links & BIT(link_id)))
+		return -EINVAL;
+
+	trace_cfg80211_update_link_reconfig_remove_update(wiphy, netdev,
+							  link_id, tbtt_count,
+							  tsf, cmd);
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
+
+	if (!hdr)
+		goto nla_put_failure;
+
+	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
+		goto nla_put_failure;
+
+	if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id) ||
+	    nla_put_u8(msg, NL80211_ATTR_AP_REMOVAL_COUNT, tbtt_count) ||
+	    nla_put_u64_64bit(msg, NL80211_ATTR_TSF, tsf,
+			      NL80211_ATTR_PAD))
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
+				NL80211_MCGRP_MLME, GFP_ATOMIC);
+
+	return 0;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cfg80211_update_link_reconfig_remove_update);
+
 /* initialisation/exit functions */
 
 int __init nl80211_init(void)
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 43897a5269b6..cbf5da73fbb0 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1459,6 +1459,23 @@  rdev_del_intf_link(struct cfg80211_registered_device *rdev,
 	trace_rdev_return_void(&rdev->wiphy);
 }
 
+static inline int
+rdev_link_reconfig_remove(struct cfg80211_registered_device *rdev,
+			  struct net_device *dev,
+			  const struct cfg80211_link_reconfig_removal_params *params)
+{
+	int ret = -EOPNOTSUPP;
+
+	trace_rdev_link_reconfig_remove(&rdev->wiphy, dev, params);
+
+	if (rdev->ops->link_reconfig_remove)
+		ret = rdev->ops->link_reconfig_remove(&rdev->wiphy, dev,
+						      params);
+
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
 static inline int
 rdev_add_link_station(struct cfg80211_registered_device *rdev,
 		      struct net_device *dev,
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index e039e66ab377..383b07601275 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -4005,6 +4005,64 @@  TRACE_EVENT(rdev_set_ttlm,
 		  WIPHY_PR_ARG, NETDEV_PR_ARG)
 );
 
+TRACE_EVENT(rdev_link_reconfig_remove,
+	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+		 const struct cfg80211_link_reconfig_removal_params *params),
+
+	TP_ARGS(wiphy, netdev, params),
+
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		__field(u32, link_id)
+		__field(u16, count)
+		__dynamic_array(u8, frame, params->elem_len)
+	),
+
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		__entry->link_id = params->link_id;
+		__entry->count = params->link_removal_cntdown;
+		memcpy(__get_dynamic_array(frame), params->reconfigure_elem,
+		       params->elem_len);
+	),
+
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %u frame:0x%.2x count:%d",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id,
+		  le16_to_cpup((__le16 *)__get_dynamic_array(frame)), __entry->count)
+);
+
+TRACE_EVENT(cfg80211_update_link_reconfig_remove_update,
+	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+		 unsigned int link_id, u8 tbtt_count, u64 tsf,
+		 enum nl80211_commands cmd),
+
+	TP_ARGS(wiphy, netdev, link_id, tbtt_count, tsf, cmd),
+
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		__field(u32, link_id)
+		__field(u8, tbtt_count)
+		__field(u64, tsf)
+		__field(enum nl80211_commands, cmd)
+	),
+
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		__entry->link_id = link_id;
+		__entry->tbtt_count = tbtt_count;
+		__entry->tsf = tsf;
+		__entry->cmd = cmd;
+	),
+
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %u tbtt:%u tsf: %lld, cmd: %d",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG,
+		  __entry->link_id, __entry->tbtt_count, __entry->tsf, __entry->cmd)
+);
+
 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 2bde8a354631..a7ba0d1850b5 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -2799,6 +2799,23 @@  bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
 }
 EXPORT_SYMBOL(cfg80211_iftype_allowed);
 
+int cfg80211_link_reconfig_remove(struct wireless_dev *wdev,
+				  const struct cfg80211_link_reconfig_removal_params *params)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+
+	lockdep_assert_wiphy(wdev->wiphy);
+
+	/* Currently, removal of link from MLD is supported for AP BSS only, it
+	 * can be extended for non-AP/STA MLD as well but that shall use
+	 * action frame to update about its link reconfiguration.
+	 */
+	if (wdev->iftype == NL80211_IFTYPE_AP)
+		return rdev_link_reconfig_remove(rdev, wdev->netdev, params);
+
+	return -EINVAL;
+}
+
 void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id)
 {
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);