@@ -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 IE will be sent.
+ * @ie: ML reconfigure IE to be updated in beacon in the link going to be
+ * removed and in all affiliated links.
+ * @ie_len: ML reconfigure IE length
+ * @link_id: Link id of the link to be removed.
+ */
+struct cfg80211_link_reconfig_removal_params {
+ u16 link_removal_cntdown;
+ const u8 *ie;
+ size_t ie_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 IE built for that particular
+ * link along with the TBTT count until which the beacon with ML
+ * reconfigure IE 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,42 @@ ssize_t wiphy_locked_debugfs_write(struct wiphy *wiphy, struct file *file,
void *data);
#endif
+enum ieee80211_link_reconfig_remove_state {
+ IEEE80211_LINK_RECONFIG_START,
+ IEEE80211_LINK_RECONFIG_COMPLETE,
+};
+
+/**
+ * cfg80211_update_link_reconfig_remove_status - 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
+ * @status: Inform started or completed action to userspace based on the value
+ * received,
+ * i) 0 (IEEE80211_LINK_RECONFIG_START) - Send
+ * NL80211_CMD_LINK_REMOVAL_STARTED
+ * ii) 1 (IEEE80211_LINK_RECONFIG_COMPLETE) - Send
+ * NL80211_CMD_LINK_REMOVAL_COMPLETED
+ *
+ *
+ * This function is used to inform userspace about the ongoing link removal
+ * status. 'IEEE80211_LINK_RECONFIG_START' is issued when the first beacon with
+ * ML reconfigure IE is sent out. This event can be used by userspace to start
+ * the BTM in case of AP mode. And, IEEE80211_LINK_RECONFIG_COMPLETE is issued
+ * when the last beacon is sent with ML reconfigure IE. 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_status(struct net_device *dev,
+ unsigned int link_id,
+ u8 tbtt_count, u64 tsf,
+ enum ieee80211_link_reconfig_remove_state action);
+
#endif /* __NET_CFG80211_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 & IE(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,
@@ -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
@@ -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,9 @@ 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 = {};
+ bool is_ml_reconfig = false;
+ int ret = 0;
/* cannot remove if there's no link */
if (!info->attrs[NL80211_ATTR_MLO_LINK_ID])
@@ -16115,9 +16120,35 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
- cfg80211_remove_link(wdev, link_id);
+ 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;
- return 0;
+ /* 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;
+
+ is_ml_reconfig = true;
+ params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ params.ie_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;
+ }
+
+ if (is_ml_reconfig)
+ ret = cfg80211_link_reconfig_remove(wdev, ¶ms);
+ else
+ cfg80211_remove_link(wdev, link_id);
+
+ return ret;
}
static int
@@ -20214,6 +20245,72 @@ void cfg80211_schedule_channels_check(struct wireless_dev *wdev)
}
EXPORT_SYMBOL(cfg80211_schedule_channels_check);
+int
+cfg80211_update_link_reconfig_remove_status(struct net_device *netdev,
+ unsigned int link_id,
+ u8 tbtt_count, u64 tsf,
+ enum ieee80211_link_reconfig_remove_state action)
+{
+ struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+ struct sk_buff *msg;
+ void *hdr = NULL;
+ int ret = 0;
+
+ /* 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;
+
+ trace_cfg80211_update_link_reconfig_remove_status(wiphy, netdev,
+ link_id, tbtt_count,
+ tsf, action);
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ if (!msg)
+ return -ENOMEM;
+
+ if (action == IEEE80211_LINK_RECONFIG_START)
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_LINK_REMOVAL_STARTED);
+ else if (action == IEEE80211_LINK_RECONFIG_COMPLETE)
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_LINK_REMOVAL_COMPLETED);
+
+ if (!hdr) {
+ ret = -ENOBUFS;
+ goto nla_put_failure;
+ }
+
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) {
+ ret = -EINVAL;
+ 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)) {
+ ret = -EINVAL;
+ goto nla_put_failure;
+ }
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+ NL80211_MCGRP_MLME, GFP_ATOMIC);
+
+ return ret;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+
+ return ret;
+}
+EXPORT_SYMBOL(cfg80211_update_link_reconfig_remove_status);
+
/* initialisation/exit functions */
int __init nl80211_init(void)
@@ -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,
@@ -4005,6 +4005,62 @@ 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->ie_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->ie,
+ params->ie_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_status,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ unsigned int link_id, u8 tbtt_count, u64 tsf,
+ enum ieee80211_link_reconfig_remove_state action),
+
+ TP_ARGS(wiphy, netdev, link_id, tbtt_count, tsf, action),
+
+ TP_STRUCT__entry(WIPHY_ENTRY
+ NETDEV_ENTRY
+ __field(u32, link_id)
+ __field(u8, tbtt_count)
+ __field(u64, tsf)
+ __field(enum ieee80211_link_reconfig_remove_state, action)
+ ),
+
+ TP_fast_assign(WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ __entry->link_id = link_id;
+ __entry->tbtt_count = tbtt_count;
+ __entry->tsf = tsf;
+ __entry->action = action;
+ ),
+
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %u tbtt:%u tsf: %lld, action: %d",
+ WIPHY_PR_ARG, NETDEV_PR_ARG,
+ __entry->link_id, __entry->tbtt_count,
+ __entry->tsf, __entry->action)
+);
+
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
@@ -2799,6 +2799,24 @@ 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);
+ int ret = -EINVAL;
+
+ 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)
+ ret = rdev_link_reconfig_remove(rdev, wdev->netdev, params);
+
+ return ret;
+}
+
void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);