Introduce the capability to offload the countdown for MLO link reconfiguration IE if supported by the underlay driver/firmware. MLO link reconfiguration IE is added to beacons/probe replies sent by the MLD AP if the specified link is going to be removed. The driver is supposed to set the WIPHY_FLAG_MLO_RECONF_ADV_OFFLOAD flag to notify mac80211/hostapd it supports this capability in hw/fw. Moreover, the driver is supposed to generate an event to notify mac80211/hostapd when the countdown is completed calling ieee80211_mlo_reconf_complete_notify() utility routine. mac80211/cfg80211 will generate a NL80211_CMD_MLO_RECONF_ADV_OFFLOAD_EVENT event for hostapd. Signed-off-by: Lorenzo Bianconi --- include/net/cfg80211.h | 13 ++++++++++ include/net/mac80211.h | 13 ++++++++++ include/uapi/linux/nl80211.h | 12 +++++++++ net/mac80211/cfg.c | 16 ++++++++++++ net/mac80211/ieee80211_i.h | 5 ++++ net/mac80211/iface.c | 14 ++++++++++ net/wireless/nl80211.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 134 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fc01de19c7981a906a5303899e7000d8193c60a8..b3ce45674e3004b592b95c4dc08ba53929f27908 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5329,6 +5329,8 @@ struct cfg80211_ops { * @WIPHY_FLAG_SUPPORTS_NSTR_NONPRIMARY: support connection to non-primary link * of an NSTR mobile AP MLD. * @WIPHY_FLAG_DISABLE_WEXT: disable wireless extensions for this device + * @WIPHY_FLAG_MLO_RECONF_ADV_OFFLOAD: The underly driver supports link + * reconfiguration countdown in hw. */ enum wiphy_flags { WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK = BIT(0), @@ -5357,6 +5359,7 @@ enum wiphy_flags { WIPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23), WIPHY_FLAG_NOTIFY_REGDOM_BY_DRIVER = BIT(24), WIPHY_FLAG_CHANNEL_CHANGE_ON_BEACON = BIT(25), + WIPHY_FLAG_MLO_RECONF_ADV_OFFLOAD = BIT(26), }; /** @@ -10314,6 +10317,16 @@ struct cfg80211_mlo_reconf_done_data { void cfg80211_mlo_reconf_add_done(struct net_device *dev, struct cfg80211_mlo_reconf_done_data *data); +/** + * cfg80211_mlo_reconf_complete_notify - Notify about MLO reconfiguration + * countdown completion. + * @dev: network device. + * @link_bitmap: bitmap representing the links the driver was announcing in + * the Reconfiguration Multi-Link element. + */ +void cfg80211_mlo_reconf_complete_notify(struct net_device *dev, + u16 link_bitmap); + /** * cfg80211_schedule_channels_check - schedule regulatory check if needed * @wdev: the wireless device to check diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7f9d96939a4ea715eea288a83aeb9a0aa863c8df..ced70e42c4a4db65c86bd8a43c8b42428663adf0 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -7801,6 +7801,19 @@ void ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif, u64 color_bitmap, u8 link_id); + +/** + * ieee80211_mlo_reconf_complete_notify - notify userland about MLO + * link reconfiguration announcement completion. + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @link_bitmap: bitmap representing the links the driver was announcing in + * the Reconfiguration Multi-Link element. + * + */ +void ieee80211_mlo_reconf_complete_notify(struct ieee80211_vif *vif, + u16 link_bitmap); + /** * ieee80211_is_tx_data - check if frame is a data frame * diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index b63f718509060dd4b7b59e2d6cc2aad280acaa22..5c7c80d5f1e5addb78e40514db8b30bbf6041fd4 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1361,6 +1361,10 @@ * user space that the NAN new cluster has been joined. The cluster ID is * indicated by %NL80211_ATTR_MAC. * + * @NL80211_CMD_MLO_RECONF_ADV_OFFLOAD_EVENT: This command is used to notify + * user space the underlay driver has completed the MLO link + * reconfiguration announcement countdown. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1624,6 +1628,8 @@ enum nl80211_commands { NL80211_CMD_NAN_NEXT_DW_NOTIFICATION, NL80211_CMD_NAN_CLUSTER_JOINED, + NL80211_CMD_MLO_RECONF_ADV_OFFLOAD_EVENT, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2984,6 +2990,10 @@ enum nl80211_commands { * this feature during association. This is a flag attribute. * Currently only supported in mac80211 drivers. * + * @NL80211_ATTR_MLO_RECONF_ADV_OFFLOAD: Flag attribute to indicate user space + * the driver supports link reconfiguration countdown in hw when a link is + * removed. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3557,6 +3567,8 @@ enum nl80211_attrs { NL80211_ATTR_UHR_CAPABILITY, NL80211_ATTR_DISABLE_UHR, + NL80211_ATTR_MLO_RECONF_ADV_OFFLOAD, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5d04d7d550b0b0af2d84148317aa152ad5647986..b20086160fd8741450e0f863d93cc2cd6964470d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -5318,6 +5318,22 @@ ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(ieee80211_obss_color_collision_notify); +void ieee80211_mlo_reconf_complete_notify(struct ieee80211_vif *vif, + u16 link_bitmap) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + + if (vif->type != NL80211_IFTYPE_AP) + return; + + if (test_and_set_bit(IEEE80211_IF_AP_RECONF_LINKS, &sdata->u.ap.flags)) + return; + + sdata->u.ap.reconf_links = link_bitmap; + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); +} +EXPORT_SYMBOL_GPL(ieee80211_mlo_reconf_complete_notify); + static int ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_color_change_settings *params) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e60b814dd89e03a5b6dd7537375b49246e5b78a5..74bc6311e430a2374afe790a7aa5686f5a62c351 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -325,6 +325,8 @@ struct ps_data { int sb_count; /* num short beacons til next long beacon */ }; +#define IEEE80211_IF_AP_RECONF_LINKS BIT(0) + struct ieee80211_if_ap { struct list_head vlans; /* write-protected with RTNL and local->mtx */ @@ -333,6 +335,9 @@ struct ieee80211_if_ap { bool multicast_to_unicast; bool active; + + unsigned long flags; + u16 reconf_links; }; struct ieee80211_if_vlan { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 676b2a43c9f2f2de03f4dd3993bf5c0ba2de0d36..6cfee360b2e7bb08cf15be84a35a0825538725e3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1776,6 +1776,17 @@ static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata, } } +static void ieee80211_ap_work(struct ieee80211_sub_if_data *sdata) +{ + if (!test_bit(IEEE80211_IF_AP_RECONF_LINKS, &sdata->u.ap.flags)) + return; + + cfg80211_mlo_reconf_complete_notify(sdata->dev, + sdata->u.ap.reconf_links); + sdata->u.ap.reconf_links = 0; + clear_bit(IEEE80211_IF_AP_RECONF_LINKS, &sdata->u.ap.flags); +} + static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work) { struct ieee80211_sub_if_data *sdata = @@ -1817,6 +1828,9 @@ static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work) /* then other type-dependent work */ switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: + ieee80211_ap_work(sdata); + break; case NL80211_IFTYPE_STATION: ieee80211_sta_work(sdata); break; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6e58b238a1f89323585607b05b25a954abc44ffe..fd670bfd61034a99f0537b2a529984661fb505e7 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -946,6 +946,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_UHR_CAPABILITY] = NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_uhr_capa, 255), [NL80211_ATTR_DISABLE_UHR] = { .type = NLA_FLAG }, + [NL80211_ATTR_MLO_RECONF_ADV_OFFLOAD] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -3338,6 +3339,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, rdev->wiphy.hw_timestamp_max_peers)) goto nla_put_failure; + if (rdev->wiphy.flags & WIPHY_FLAG_MLO_RECONF_ADV_OFFLOAD) + nla_put_flag(msg, NL80211_ATTR_MLO_RECONF_ADV_OFFLOAD); + state->split_start++; break; case 17: @@ -20066,6 +20070,63 @@ void cfg80211_links_removed(struct net_device *dev, u16 link_mask) } EXPORT_SYMBOL(cfg80211_links_removed); +void cfg80211_mlo_reconf_complete_notify(struct net_device *dev, + u16 link_bitmap) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + struct nlattr *links; + struct sk_buff *msg; + void *hdr; + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP)) + return; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, + NL80211_CMD_MLO_RECONF_ADV_OFFLOAD_EVENT); + if (!hdr) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) + goto nla_put_failure; + + links = nla_nest_start(msg, NL80211_ATTR_MLO_LINKS); + if (!links) + goto nla_put_failure; + + while (link_bitmap) { + int link_id = __ffs(link_bitmap); + struct nlattr *link; + + link = nla_nest_start(msg, link_id + 1); + if (!link) + goto nla_put_failure; + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) + goto nla_put_failure; + + nla_nest_end(msg, link); + link_bitmap &= ~(1 << link_id); + } + + nla_nest_end(msg, links); + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, GFP_KERNEL); + return; + +nla_put_failure: + nlmsg_free(msg); +} +EXPORT_SYMBOL_GPL(cfg80211_mlo_reconf_complete_notify); + void nl80211_mlo_reconf_add_done(struct net_device *dev, struct cfg80211_mlo_reconf_done_data *data) { -- 2.53.0