mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
wifi: cfg80211: Add support for dynamic addition/removal of links
Add support for requesting dynamic addition/removal of links to the current MLO association. Signed-off-by: Ilan Peer <ilan.peer@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20250102161730.cef23352f2a2.I79c849974c494cb1cbf9e1b22a5d2d37395ff5ac@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
720fa448f5
commit
65c1c04179
@ -4596,6 +4596,15 @@ struct mgmt_frame_regs {
|
||||
* @set_ttlm: set the TID to link mapping.
|
||||
* @get_radio_mask: get bitmask of radios in use.
|
||||
* (invoked with the wiphy mutex held)
|
||||
* @assoc_ml_reconf: Request a non-AP MLO connection to perform ML
|
||||
* reconfiguration, i.e., add and/or remove links to/from the
|
||||
* association using ML reconfiguration action frames. Successfully added
|
||||
* links will be added to the set of valid links. Successfully removed
|
||||
* links will be removed from the set of valid links. The driver must
|
||||
* indicate removed links by calling cfg80211_links_removed() and added
|
||||
* links by calling cfg80211_mlo_reconf_add_done(). When calling
|
||||
* cfg80211_mlo_reconf_add_done() the bss pointer must be given for each
|
||||
* link for which MLO reconfiguration 'add' operation was requested.
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
|
||||
@ -4959,6 +4968,9 @@ struct cfg80211_ops {
|
||||
int (*set_ttlm)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_ttlm_params *params);
|
||||
u32 (*get_radio_mask)(struct wiphy *wiphy, struct net_device *dev);
|
||||
int (*assoc_ml_reconf)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_assoc_link *add_links,
|
||||
u16 rem_links);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -9716,6 +9728,39 @@ static inline int cfg80211_color_change_notify(struct net_device *dev,
|
||||
*/
|
||||
void cfg80211_links_removed(struct net_device *dev, u16 link_mask);
|
||||
|
||||
/**
|
||||
* struct cfg80211_mlo_reconf_done_data - MLO reconfiguration data
|
||||
* @buf: MLO Reconfiguration Response frame (header + body)
|
||||
* @len: length of the frame data
|
||||
* @added_links: BIT mask of links successfully added to the association
|
||||
* @links: per-link information indexed by link ID
|
||||
* @links.bss: the BSS that MLO reconfiguration was requested for, ownership of
|
||||
* the pointer moves to cfg80211 in the call to
|
||||
* cfg80211_mlo_reconf_add_done().
|
||||
*
|
||||
* The BSS pointer must be set for each link for which 'add' operation was
|
||||
* requested in the assoc_ml_reconf callback.
|
||||
*/
|
||||
struct cfg80211_mlo_reconf_done_data {
|
||||
const u8 *buf;
|
||||
size_t len;
|
||||
u16 added_links;
|
||||
struct {
|
||||
struct cfg80211_bss *bss;
|
||||
} links[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||
};
|
||||
|
||||
/**
|
||||
* cfg80211_mlo_reconf_add_done - Notify about MLO reconfiguration result
|
||||
* @dev: network device.
|
||||
* @data: MLO reconfiguration done data, &struct cfg80211_mlo_reconf_done_data
|
||||
*
|
||||
* Inform cfg80211 and the userspace that processing of ML reconfiguration
|
||||
* request to add links to the association is done.
|
||||
*/
|
||||
void cfg80211_mlo_reconf_add_done(struct net_device *dev,
|
||||
struct cfg80211_mlo_reconf_done_data *data);
|
||||
|
||||
/**
|
||||
* cfg80211_schedule_channels_check - schedule regulatory check if needed
|
||||
* @wdev: the wireless device to check
|
||||
|
@ -1329,6 +1329,9 @@
|
||||
* %NL80211_ATTR_MLO_TTLM_ULINK attributes are used to specify the
|
||||
* TID to Link mapping for downlink/uplink traffic.
|
||||
*
|
||||
* @NL80211_CMD_ASSOC_MLO_RECONF: For a non-AP MLD station, request to
|
||||
* add/remove links to/from the association.
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -1586,6 +1589,8 @@ enum nl80211_commands {
|
||||
|
||||
NL80211_CMD_SET_TID_TO_LINK_MAPPING,
|
||||
|
||||
NL80211_CMD_ASSOC_MLO_RECONF,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@ -2877,6 +2882,9 @@ enum nl80211_commands {
|
||||
* This can be used to provide a list of selectors that are implemented
|
||||
* by the supplicant. If not given, support for SAE_H2E is assumed.
|
||||
*
|
||||
* @NL80211_ATTR_MLO_RECONF_REM_LINKS: (u16) A bitmask of the links requested
|
||||
* to be removed from the MLO association.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
@ -3429,6 +3437,8 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_SUPPORTED_SELECTORS,
|
||||
|
||||
NL80211_ATTR_MLO_RECONF_REM_LINKS,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -567,6 +567,10 @@ 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_assoc_ml_reconf(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_assoc_link *links,
|
||||
u16 rem_links);
|
||||
/**
|
||||
* struct cfg80211_colocated_ap - colocated AP information
|
||||
*
|
||||
|
@ -1294,3 +1294,80 @@ void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev)
|
||||
&rdev->background_radar_chandef,
|
||||
NL80211_RADAR_CAC_ABORTED);
|
||||
}
|
||||
|
||||
int cfg80211_assoc_ml_reconf(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_assoc_link *links,
|
||||
u16 rem_links)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
lockdep_assert_wiphy(wdev->wiphy);
|
||||
|
||||
err = rdev_assoc_ml_reconf(rdev, dev, links, rem_links);
|
||||
if (!err) {
|
||||
int link_id;
|
||||
|
||||
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS;
|
||||
link_id++) {
|
||||
if (!links[link_id].bss)
|
||||
continue;
|
||||
|
||||
cfg80211_ref_bss(&rdev->wiphy, links[link_id].bss);
|
||||
cfg80211_hold_bss(bss_from_pub(links[link_id].bss));
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void cfg80211_mlo_reconf_add_done(struct net_device *dev,
|
||||
struct cfg80211_mlo_reconf_done_data *data)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
int link_id;
|
||||
|
||||
lockdep_assert_wiphy(wiphy);
|
||||
|
||||
trace_cfg80211_mlo_reconf_add_done(dev, data->added_links,
|
||||
data->buf, data->len);
|
||||
|
||||
if (WARN_ON(!wdev->valid_links))
|
||||
return;
|
||||
|
||||
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
|
||||
return;
|
||||
|
||||
/* validate that a BSS is given for each added link */
|
||||
for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
|
||||
struct cfg80211_bss *bss = data->links[link_id].bss;
|
||||
|
||||
if (!(data->added_links & BIT(link_id)))
|
||||
continue;
|
||||
|
||||
if (WARN_ON(!bss))
|
||||
return;
|
||||
}
|
||||
|
||||
for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
|
||||
struct cfg80211_bss *bss = data->links[link_id].bss;
|
||||
|
||||
if (!bss)
|
||||
continue;
|
||||
|
||||
if (data->added_links & BIT(link_id)) {
|
||||
wdev->links[link_id].client.current_bss =
|
||||
bss_from_pub(bss);
|
||||
} else {
|
||||
cfg80211_unhold_bss(bss_from_pub(bss));
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
}
|
||||
}
|
||||
|
||||
wdev->valid_links |= data->added_links;
|
||||
nl80211_mlo_reconf_add_done(dev, data);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_mlo_reconf_add_done);
|
||||
|
@ -848,6 +848,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_SUPPORTED_SELECTORS] =
|
||||
NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_supported_selectors,
|
||||
NL80211_MAX_SUPP_SELECTORS),
|
||||
[NL80211_ATTR_MLO_RECONF_REM_LINKS] = { .type = NLA_U16 },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@ -16476,6 +16477,66 @@ nl80211_set_ttlm(struct sk_buff *skb, struct genl_info *info)
|
||||
return rdev_set_ttlm(rdev, dev, ¶ms);
|
||||
}
|
||||
|
||||
static int nl80211_assoc_ml_reconf(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_assoc_link links[IEEE80211_MLD_MAX_NUM_LINKS] = {};
|
||||
unsigned int link_id;
|
||||
u16 add_links, rem_links;
|
||||
int err;
|
||||
|
||||
if (!wdev->valid_links)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->ieee80211_ptr->conn_owner_nlportid &&
|
||||
dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
|
||||
return -EPERM;
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
add_links = 0;
|
||||
if (info->attrs[NL80211_ATTR_MLO_LINKS]) {
|
||||
err = nl80211_process_links(rdev, links, NULL, 0, info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS;
|
||||
link_id++) {
|
||||
if (!links[link_id].bss)
|
||||
continue;
|
||||
add_links |= BIT(link_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MLO_RECONF_REM_LINKS])
|
||||
rem_links =
|
||||
nla_get_u16(info->attrs[NL80211_ATTR_MLO_RECONF_REM_LINKS]);
|
||||
else
|
||||
rem_links = 0;
|
||||
|
||||
/* Validate that existing links are not added, removed links are valid
|
||||
* and don't allow adding and removing the same links
|
||||
*/
|
||||
if ((add_links & rem_links) || !(add_links | rem_links) ||
|
||||
(wdev->valid_links & add_links) ||
|
||||
((wdev->valid_links & rem_links) != rem_links)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = cfg80211_assoc_ml_reconf(rdev, dev, links, rem_links);
|
||||
|
||||
out:
|
||||
for (link_id = 0; link_id < ARRAY_SIZE(links); link_id++)
|
||||
cfg80211_put_bss(&rdev->wiphy, links[link_id].bss);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#define NL80211_FLAG_NEED_WIPHY 0x01
|
||||
#define NL80211_FLAG_NEED_NETDEV 0x02
|
||||
#define NL80211_FLAG_NEED_RTNL 0x04
|
||||
@ -17668,6 +17729,12 @@ static const struct genl_small_ops nl80211_small_ops[] = {
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_ASSOC_MLO_RECONF,
|
||||
.doit = nl80211_assoc_ml_reconf,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_family nl80211_fam __ro_after_init = {
|
||||
@ -18564,6 +18631,23 @@ void cfg80211_links_removed(struct net_device *dev, u16 link_mask)
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_links_removed);
|
||||
|
||||
void nl80211_mlo_reconf_add_done(struct net_device *dev,
|
||||
struct cfg80211_mlo_reconf_done_data *data)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
struct nl80211_mlme_event event = {
|
||||
.cmd = NL80211_CMD_ASSOC_MLO_RECONF,
|
||||
.buf = data->buf,
|
||||
.buf_len = data->len,
|
||||
.uapsd_queues = -1,
|
||||
};
|
||||
|
||||
nl80211_send_mlme_event(rdev, dev, &event, GFP_KERNEL);
|
||||
}
|
||||
EXPORT_SYMBOL(nl80211_mlo_reconf_add_done);
|
||||
|
||||
void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
gfp_t gfp)
|
||||
|
@ -124,4 +124,7 @@ void cfg80211_free_coalesce(struct cfg80211_coalesce *coalesce);
|
||||
/* peer measurement */
|
||||
int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
void nl80211_mlo_reconf_add_done(struct net_device *dev,
|
||||
struct cfg80211_mlo_reconf_done_data *data);
|
||||
|
||||
#endif /* __NET_WIRELESS_NL80211_H */
|
||||
|
@ -1547,4 +1547,23 @@ rdev_get_radio_mask(struct cfg80211_registered_device *rdev,
|
||||
|
||||
return rdev->ops->get_radio_mask(wiphy, dev);
|
||||
}
|
||||
|
||||
static inline int
|
||||
rdev_assoc_ml_reconf(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_assoc_link *add_links,
|
||||
u16 rem_links)
|
||||
{
|
||||
struct wiphy *wiphy = &rdev->wiphy;
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
trace_rdev_assoc_ml_reconf(wiphy, dev, add_links, rem_links);
|
||||
if (rdev->ops->assoc_ml_reconf)
|
||||
ret = rdev->ops->assoc_ml_reconf(wiphy, dev, add_links,
|
||||
rem_links);
|
||||
trace_rdev_return_int(wiphy, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __CFG80211_RDEV_OPS */
|
||||
|
@ -4104,6 +4104,50 @@ TRACE_EVENT(cfg80211_links_removed,
|
||||
__entry->link_mask)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_mlo_reconf_add_done,
|
||||
TP_PROTO(struct net_device *netdev, u16 link_mask,
|
||||
const u8 *buf, size_t len),
|
||||
TP_ARGS(netdev, link_mask, buf, len),
|
||||
TP_STRUCT__entry(
|
||||
NETDEV_ENTRY
|
||||
__field(u16, link_mask)
|
||||
__dynamic_array(u8, buf, len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
NETDEV_ASSIGN;
|
||||
__entry->link_mask = link_mask;
|
||||
memcpy(__get_dynamic_array(buf), buf, len);
|
||||
),
|
||||
TP_printk(NETDEV_PR_FMT ", link_mask:0x%x",
|
||||
NETDEV_PR_ARG, __entry->link_mask)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_assoc_ml_reconf,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
struct cfg80211_assoc_link *add_links,
|
||||
u16 rem_links),
|
||||
TP_ARGS(wiphy, netdev, add_links, rem_links),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
__field(u16, add_links)
|
||||
__field(u16, rem_links)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
u32 i;
|
||||
|
||||
__entry->add_links = 0;
|
||||
__entry->rem_links = rem_links;
|
||||
for (i = 0; add_links && i < IEEE80211_MLD_MAX_NUM_LINKS; i++)
|
||||
if (add_links[i].bss)
|
||||
__entry->add_links |= BIT(i);
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", add_links=0x%x, rem_links=0x%x",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG,
|
||||
__entry->add_links, __entry->rem_links)
|
||||
);
|
||||
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
|
Loading…
x
Reference in New Issue
Block a user