Skip to content

Commit 65c1c04

Browse files
ilanpeer2jmberg-intel
authored andcommitted
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 <[email protected]> Signed-off-by: Miri Korenblit <[email protected]> Link: https://patch.msgid.link/20250102161730.cef23352f2a2.I79c849974c494cb1cbf9e1b22a5d2d37395ff5ac@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent 720fa44 commit 65c1c04

File tree

8 files changed

+286
-0
lines changed

8 files changed

+286
-0
lines changed

include/net/cfg80211.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4596,6 +4596,15 @@ struct mgmt_frame_regs {
45964596
* @set_ttlm: set the TID to link mapping.
45974597
* @get_radio_mask: get bitmask of radios in use.
45984598
* (invoked with the wiphy mutex held)
4599+
* @assoc_ml_reconf: Request a non-AP MLO connection to perform ML
4600+
* reconfiguration, i.e., add and/or remove links to/from the
4601+
* association using ML reconfiguration action frames. Successfully added
4602+
* links will be added to the set of valid links. Successfully removed
4603+
* links will be removed from the set of valid links. The driver must
4604+
* indicate removed links by calling cfg80211_links_removed() and added
4605+
* links by calling cfg80211_mlo_reconf_add_done(). When calling
4606+
* cfg80211_mlo_reconf_add_done() the bss pointer must be given for each
4607+
* link for which MLO reconfiguration 'add' operation was requested.
45994608
*/
46004609
struct cfg80211_ops {
46014610
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4959,6 +4968,9 @@ struct cfg80211_ops {
49594968
int (*set_ttlm)(struct wiphy *wiphy, struct net_device *dev,
49604969
struct cfg80211_ttlm_params *params);
49614970
u32 (*get_radio_mask)(struct wiphy *wiphy, struct net_device *dev);
4971+
int (*assoc_ml_reconf)(struct wiphy *wiphy, struct net_device *dev,
4972+
struct cfg80211_assoc_link *add_links,
4973+
u16 rem_links);
49624974
};
49634975

49644976
/*
@@ -9716,6 +9728,39 @@ static inline int cfg80211_color_change_notify(struct net_device *dev,
97169728
*/
97179729
void cfg80211_links_removed(struct net_device *dev, u16 link_mask);
97189730

9731+
/**
9732+
* struct cfg80211_mlo_reconf_done_data - MLO reconfiguration data
9733+
* @buf: MLO Reconfiguration Response frame (header + body)
9734+
* @len: length of the frame data
9735+
* @added_links: BIT mask of links successfully added to the association
9736+
* @links: per-link information indexed by link ID
9737+
* @links.bss: the BSS that MLO reconfiguration was requested for, ownership of
9738+
* the pointer moves to cfg80211 in the call to
9739+
* cfg80211_mlo_reconf_add_done().
9740+
*
9741+
* The BSS pointer must be set for each link for which 'add' operation was
9742+
* requested in the assoc_ml_reconf callback.
9743+
*/
9744+
struct cfg80211_mlo_reconf_done_data {
9745+
const u8 *buf;
9746+
size_t len;
9747+
u16 added_links;
9748+
struct {
9749+
struct cfg80211_bss *bss;
9750+
} links[IEEE80211_MLD_MAX_NUM_LINKS];
9751+
};
9752+
9753+
/**
9754+
* cfg80211_mlo_reconf_add_done - Notify about MLO reconfiguration result
9755+
* @dev: network device.
9756+
* @data: MLO reconfiguration done data, &struct cfg80211_mlo_reconf_done_data
9757+
*
9758+
* Inform cfg80211 and the userspace that processing of ML reconfiguration
9759+
* request to add links to the association is done.
9760+
*/
9761+
void cfg80211_mlo_reconf_add_done(struct net_device *dev,
9762+
struct cfg80211_mlo_reconf_done_data *data);
9763+
97199764
/**
97209765
* cfg80211_schedule_channels_check - schedule regulatory check if needed
97219766
* @wdev: the wireless device to check

include/uapi/linux/nl80211.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,9 @@
13291329
* %NL80211_ATTR_MLO_TTLM_ULINK attributes are used to specify the
13301330
* TID to Link mapping for downlink/uplink traffic.
13311331
*
1332+
* @NL80211_CMD_ASSOC_MLO_RECONF: For a non-AP MLD station, request to
1333+
* add/remove links to/from the association.
1334+
*
13321335
* @NL80211_CMD_MAX: highest used command number
13331336
* @__NL80211_CMD_AFTER_LAST: internal use
13341337
*/
@@ -1586,6 +1589,8 @@ enum nl80211_commands {
15861589

15871590
NL80211_CMD_SET_TID_TO_LINK_MAPPING,
15881591

1592+
NL80211_CMD_ASSOC_MLO_RECONF,
1593+
15891594
/* add new commands above here */
15901595

15911596
/* used to define NL80211_CMD_MAX below */
@@ -2877,6 +2882,9 @@ enum nl80211_commands {
28772882
* This can be used to provide a list of selectors that are implemented
28782883
* by the supplicant. If not given, support for SAE_H2E is assumed.
28792884
*
2885+
* @NL80211_ATTR_MLO_RECONF_REM_LINKS: (u16) A bitmask of the links requested
2886+
* to be removed from the MLO association.
2887+
*
28802888
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
28812889
* @NL80211_ATTR_MAX: highest attribute number currently defined
28822890
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3429,6 +3437,8 @@ enum nl80211_attrs {
34293437

34303438
NL80211_ATTR_SUPPORTED_SELECTORS,
34313439

3440+
NL80211_ATTR_MLO_RECONF_REM_LINKS,
3441+
34323442
/* add attributes here, update the policy in nl80211.c */
34333443

34343444
__NL80211_ATTR_AFTER_LAST,

net/wireless/core.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,10 @@ int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev,
567567
struct wireless_dev *wdev);
568568
void cfg80211_wdev_release_link_bsses(struct wireless_dev *wdev, u16 link_mask);
569569

570+
int cfg80211_assoc_ml_reconf(struct cfg80211_registered_device *rdev,
571+
struct net_device *dev,
572+
struct cfg80211_assoc_link *links,
573+
u16 rem_links);
570574
/**
571575
* struct cfg80211_colocated_ap - colocated AP information
572576
*

net/wireless/mlme.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,3 +1294,80 @@ void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev)
12941294
&rdev->background_radar_chandef,
12951295
NL80211_RADAR_CAC_ABORTED);
12961296
}
1297+
1298+
int cfg80211_assoc_ml_reconf(struct cfg80211_registered_device *rdev,
1299+
struct net_device *dev,
1300+
struct cfg80211_assoc_link *links,
1301+
u16 rem_links)
1302+
{
1303+
struct wireless_dev *wdev = dev->ieee80211_ptr;
1304+
int err;
1305+
1306+
lockdep_assert_wiphy(wdev->wiphy);
1307+
1308+
err = rdev_assoc_ml_reconf(rdev, dev, links, rem_links);
1309+
if (!err) {
1310+
int link_id;
1311+
1312+
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS;
1313+
link_id++) {
1314+
if (!links[link_id].bss)
1315+
continue;
1316+
1317+
cfg80211_ref_bss(&rdev->wiphy, links[link_id].bss);
1318+
cfg80211_hold_bss(bss_from_pub(links[link_id].bss));
1319+
}
1320+
}
1321+
1322+
return err;
1323+
}
1324+
1325+
void cfg80211_mlo_reconf_add_done(struct net_device *dev,
1326+
struct cfg80211_mlo_reconf_done_data *data)
1327+
{
1328+
struct wireless_dev *wdev = dev->ieee80211_ptr;
1329+
struct wiphy *wiphy = wdev->wiphy;
1330+
int link_id;
1331+
1332+
lockdep_assert_wiphy(wiphy);
1333+
1334+
trace_cfg80211_mlo_reconf_add_done(dev, data->added_links,
1335+
data->buf, data->len);
1336+
1337+
if (WARN_ON(!wdev->valid_links))
1338+
return;
1339+
1340+
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
1341+
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
1342+
return;
1343+
1344+
/* validate that a BSS is given for each added link */
1345+
for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
1346+
struct cfg80211_bss *bss = data->links[link_id].bss;
1347+
1348+
if (!(data->added_links & BIT(link_id)))
1349+
continue;
1350+
1351+
if (WARN_ON(!bss))
1352+
return;
1353+
}
1354+
1355+
for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
1356+
struct cfg80211_bss *bss = data->links[link_id].bss;
1357+
1358+
if (!bss)
1359+
continue;
1360+
1361+
if (data->added_links & BIT(link_id)) {
1362+
wdev->links[link_id].client.current_bss =
1363+
bss_from_pub(bss);
1364+
} else {
1365+
cfg80211_unhold_bss(bss_from_pub(bss));
1366+
cfg80211_put_bss(wiphy, bss);
1367+
}
1368+
}
1369+
1370+
wdev->valid_links |= data->added_links;
1371+
nl80211_mlo_reconf_add_done(dev, data);
1372+
}
1373+
EXPORT_SYMBOL(cfg80211_mlo_reconf_add_done);

net/wireless/nl80211.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
848848
[NL80211_ATTR_SUPPORTED_SELECTORS] =
849849
NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_supported_selectors,
850850
NL80211_MAX_SUPP_SELECTORS),
851+
[NL80211_ATTR_MLO_RECONF_REM_LINKS] = { .type = NLA_U16 },
851852
};
852853

853854
/* policy for the key attributes */
@@ -16476,6 +16477,66 @@ nl80211_set_ttlm(struct sk_buff *skb, struct genl_info *info)
1647616477
return rdev_set_ttlm(rdev, dev, &params);
1647716478
}
1647816479

16480+
static int nl80211_assoc_ml_reconf(struct sk_buff *skb, struct genl_info *info)
16481+
{
16482+
struct cfg80211_registered_device *rdev = info->user_ptr[0];
16483+
struct net_device *dev = info->user_ptr[1];
16484+
struct wireless_dev *wdev = dev->ieee80211_ptr;
16485+
struct cfg80211_assoc_link links[IEEE80211_MLD_MAX_NUM_LINKS] = {};
16486+
unsigned int link_id;
16487+
u16 add_links, rem_links;
16488+
int err;
16489+
16490+
if (!wdev->valid_links)
16491+
return -EINVAL;
16492+
16493+
if (dev->ieee80211_ptr->conn_owner_nlportid &&
16494+
dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
16495+
return -EPERM;
16496+
16497+
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
16498+
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
16499+
return -EOPNOTSUPP;
16500+
16501+
add_links = 0;
16502+
if (info->attrs[NL80211_ATTR_MLO_LINKS]) {
16503+
err = nl80211_process_links(rdev, links, NULL, 0, info);
16504+
if (err)
16505+
return err;
16506+
16507+
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS;
16508+
link_id++) {
16509+
if (!links[link_id].bss)
16510+
continue;
16511+
add_links |= BIT(link_id);
16512+
}
16513+
}
16514+
16515+
if (info->attrs[NL80211_ATTR_MLO_RECONF_REM_LINKS])
16516+
rem_links =
16517+
nla_get_u16(info->attrs[NL80211_ATTR_MLO_RECONF_REM_LINKS]);
16518+
else
16519+
rem_links = 0;
16520+
16521+
/* Validate that existing links are not added, removed links are valid
16522+
* and don't allow adding and removing the same links
16523+
*/
16524+
if ((add_links & rem_links) || !(add_links | rem_links) ||
16525+
(wdev->valid_links & add_links) ||
16526+
((wdev->valid_links & rem_links) != rem_links)) {
16527+
err = -EINVAL;
16528+
goto out;
16529+
}
16530+
16531+
err = cfg80211_assoc_ml_reconf(rdev, dev, links, rem_links);
16532+
16533+
out:
16534+
for (link_id = 0; link_id < ARRAY_SIZE(links); link_id++)
16535+
cfg80211_put_bss(&rdev->wiphy, links[link_id].bss);
16536+
16537+
return err;
16538+
}
16539+
1647916540
#define NL80211_FLAG_NEED_WIPHY 0x01
1648016541
#define NL80211_FLAG_NEED_NETDEV 0x02
1648116542
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -17668,6 +17729,12 @@ static const struct genl_small_ops nl80211_small_ops[] = {
1766817729
.flags = GENL_UNS_ADMIN_PERM,
1766917730
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
1767017731
},
17732+
{
17733+
.cmd = NL80211_CMD_ASSOC_MLO_RECONF,
17734+
.doit = nl80211_assoc_ml_reconf,
17735+
.flags = GENL_UNS_ADMIN_PERM,
17736+
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
17737+
},
1767117738
};
1767217739

1767317740
static struct genl_family nl80211_fam __ro_after_init = {
@@ -18564,6 +18631,23 @@ void cfg80211_links_removed(struct net_device *dev, u16 link_mask)
1856418631
}
1856518632
EXPORT_SYMBOL(cfg80211_links_removed);
1856618633

18634+
void nl80211_mlo_reconf_add_done(struct net_device *dev,
18635+
struct cfg80211_mlo_reconf_done_data *data)
18636+
{
18637+
struct wireless_dev *wdev = dev->ieee80211_ptr;
18638+
struct wiphy *wiphy = wdev->wiphy;
18639+
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
18640+
struct nl80211_mlme_event event = {
18641+
.cmd = NL80211_CMD_ASSOC_MLO_RECONF,
18642+
.buf = data->buf,
18643+
.buf_len = data->len,
18644+
.uapsd_queues = -1,
18645+
};
18646+
18647+
nl80211_send_mlme_event(rdev, dev, &event, GFP_KERNEL);
18648+
}
18649+
EXPORT_SYMBOL(nl80211_mlo_reconf_add_done);
18650+
1856718651
void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
1856818652
struct net_device *netdev, const u8 *bssid,
1856918653
gfp_t gfp)

net/wireless/nl80211.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,7 @@ void cfg80211_free_coalesce(struct cfg80211_coalesce *coalesce);
124124
/* peer measurement */
125125
int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info);
126126

127+
void nl80211_mlo_reconf_add_done(struct net_device *dev,
128+
struct cfg80211_mlo_reconf_done_data *data);
129+
127130
#endif /* __NET_WIRELESS_NL80211_H */

net/wireless/rdev-ops.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,4 +1547,23 @@ rdev_get_radio_mask(struct cfg80211_registered_device *rdev,
15471547

15481548
return rdev->ops->get_radio_mask(wiphy, dev);
15491549
}
1550+
1551+
static inline int
1552+
rdev_assoc_ml_reconf(struct cfg80211_registered_device *rdev,
1553+
struct net_device *dev,
1554+
struct cfg80211_assoc_link *add_links,
1555+
u16 rem_links)
1556+
{
1557+
struct wiphy *wiphy = &rdev->wiphy;
1558+
int ret = -EOPNOTSUPP;
1559+
1560+
trace_rdev_assoc_ml_reconf(wiphy, dev, add_links, rem_links);
1561+
if (rdev->ops->assoc_ml_reconf)
1562+
ret = rdev->ops->assoc_ml_reconf(wiphy, dev, add_links,
1563+
rem_links);
1564+
trace_rdev_return_int(wiphy, ret);
1565+
1566+
return ret;
1567+
}
1568+
15501569
#endif /* __CFG80211_RDEV_OPS */

net/wireless/trace.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4104,6 +4104,50 @@ TRACE_EVENT(cfg80211_links_removed,
41044104
__entry->link_mask)
41054105
);
41064106

4107+
TRACE_EVENT(cfg80211_mlo_reconf_add_done,
4108+
TP_PROTO(struct net_device *netdev, u16 link_mask,
4109+
const u8 *buf, size_t len),
4110+
TP_ARGS(netdev, link_mask, buf, len),
4111+
TP_STRUCT__entry(
4112+
NETDEV_ENTRY
4113+
__field(u16, link_mask)
4114+
__dynamic_array(u8, buf, len)
4115+
),
4116+
TP_fast_assign(
4117+
NETDEV_ASSIGN;
4118+
__entry->link_mask = link_mask;
4119+
memcpy(__get_dynamic_array(buf), buf, len);
4120+
),
4121+
TP_printk(NETDEV_PR_FMT ", link_mask:0x%x",
4122+
NETDEV_PR_ARG, __entry->link_mask)
4123+
);
4124+
4125+
TRACE_EVENT(rdev_assoc_ml_reconf,
4126+
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
4127+
struct cfg80211_assoc_link *add_links,
4128+
u16 rem_links),
4129+
TP_ARGS(wiphy, netdev, add_links, rem_links),
4130+
TP_STRUCT__entry(
4131+
WIPHY_ENTRY
4132+
NETDEV_ENTRY
4133+
__field(u16, add_links)
4134+
__field(u16, rem_links)
4135+
),
4136+
TP_fast_assign(
4137+
WIPHY_ASSIGN;
4138+
NETDEV_ASSIGN;
4139+
u32 i;
4140+
4141+
__entry->add_links = 0;
4142+
__entry->rem_links = rem_links;
4143+
for (i = 0; add_links && i < IEEE80211_MLD_MAX_NUM_LINKS; i++)
4144+
if (add_links[i].bss)
4145+
__entry->add_links |= BIT(i);
4146+
),
4147+
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", add_links=0x%x, rem_links=0x%x",
4148+
WIPHY_PR_ARG, NETDEV_PR_ARG,
4149+
__entry->add_links, __entry->rem_links)
4150+
);
41074151
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
41084152

41094153
#undef TRACE_INCLUDE_PATH

0 commit comments

Comments
 (0)