summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/wireless/mlme.c30
-rw-r--r--net/wireless/nl80211.c91
-rw-r--r--net/wireless/sme.c2
3 files changed, 117 insertions, 6 deletions
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 532113937469..d92eed0e52cd 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -241,6 +241,10 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
if (!req->bss)
return -ENOENT;
+ if (req->link_id >= 0 &&
+ !(wdev->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO))
+ return -EINVAL;
+
if (req->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
if (!req->key || !req->key_len ||
req->key_idx < 0 || req->key_idx > 3)
@@ -294,10 +298,19 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct cfg80211_assoc_request *req)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- int err;
+ int err, i, j;
ASSERT_WDEV_LOCK(wdev);
+ for (i = 1; i < ARRAY_SIZE(req->links); i++) {
+ if (!req->links[i].bss)
+ continue;
+ for (j = 0; j < i; j++) {
+ if (req->links[i].bss == req->links[j].bss)
+ return -EINVAL;
+ }
+ }
+
if (wdev->connected &&
(!req->prev_bssid ||
!ether_addr_equal(wdev->u.client.connected_addr, req->prev_bssid)))
@@ -310,8 +323,19 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
err = rdev_assoc(rdev, dev, req);
if (!err) {
- cfg80211_ref_bss(&rdev->wiphy, req->bss);
- cfg80211_hold_bss(bss_from_pub(req->bss));
+ int link_id;
+
+ if (req->bss) {
+ cfg80211_ref_bss(&rdev->wiphy, req->bss);
+ cfg80211_hold_bss(bss_from_pub(req->bss));
+ }
+
+ for (link_id = 0; link_id < ARRAY_SIZE(req->links); link_id++) {
+ if (!req->links[link_id].bss)
+ continue;
+ cfg80211_ref_bss(&rdev->wiphy, req->links[link_id].bss);
+ cfg80211_hold_bss(bss_from_pub(req->links[link_id].bss));
+ }
}
return err;
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5a4d3ddcdf80..9bc66a21ac3a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -796,6 +796,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
NLA_POLICY_NESTED_ARRAY(nl80211_policy),
[NL80211_ATTR_MLO_LINK_ID] =
NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS),
+ [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN),
};
/* policy for the key attributes */
@@ -10282,6 +10283,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
req.key = key.p.key;
req.key_len = key.p.key_len;
req.key_idx = key.idx;
+ req.link_id = nl80211_link_id_or_invalid(info->attrs);
+ if (req.link_id >= 0) {
+ if (!info->attrs[NL80211_ATTR_MLD_ADDR])
+ return -EINVAL;
+ req.ap_mld_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]);
+ }
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
IEEE80211_BSS_TYPE_ESS,
@@ -10475,7 +10482,9 @@ static int nl80211_associate(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 cfg80211_assoc_request req = {};
+ struct nlattr **attrs = NULL;
const u8 *bssid, *ssid;
+ unsigned int link_id;
int err, ssid_len;
if (dev->ieee80211_ptr->conn_owner_nlportid &&
@@ -10585,9 +10594,81 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
sizeof(req.s1g_capa));
}
- req.bss = nl80211_assoc_bss(rdev, ssid, ssid_len, info->attrs, &bssid);
- if (IS_ERR(req.bss))
- return PTR_ERR(req.bss);
+ req.link_id = nl80211_link_id_or_invalid(info->attrs);
+
+ if (info->attrs[NL80211_ATTR_MLO_LINKS]) {
+ unsigned int attrsize = NUM_NL80211_ATTR * sizeof(*attrs);
+ struct nlattr *link;
+ int rem = 0;
+
+ if (req.link_id < 0)
+ return -EINVAL;
+
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_MLO))
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_MAC] ||
+ info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
+ !info->attrs[NL80211_ATTR_MLD_ADDR])
+ return -EINVAL;
+
+ req.ap_mld_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]);
+
+ attrs = kzalloc(attrsize, GFP_KERNEL);
+ if (!attrs)
+ return -ENOMEM;
+
+ nla_for_each_nested(link,
+ info->attrs[NL80211_ATTR_MLO_LINKS],
+ rem) {
+ memset(attrs, 0, attrsize);
+
+ nla_parse_nested(attrs, NL80211_ATTR_MAX,
+ link, NULL, NULL);
+
+ if (!attrs[NL80211_ATTR_MLO_LINK_ID]) {
+ err = -EINVAL;
+ goto free;
+ }
+
+ link_id = nla_get_u8(attrs[NL80211_ATTR_MLO_LINK_ID]);
+ /* cannot use the same link ID again */
+ if (req.links[link_id].bss) {
+ err = -EINVAL;
+ goto free;
+ }
+ req.links[link_id].bss =
+ nl80211_assoc_bss(rdev, ssid, ssid_len, attrs,
+ &bssid);
+ if (IS_ERR(req.links[link_id].bss)) {
+ err = PTR_ERR(req.links[link_id].bss);
+ goto free;
+ }
+
+ if (attrs[NL80211_ATTR_IE]) {
+ req.links[link_id].elems =
+ nla_data(attrs[NL80211_ATTR_IE]);
+ req.links[link_id].elems_len =
+ nla_len(attrs[NL80211_ATTR_IE]);
+ }
+ }
+
+ if (!req.links[req.link_id].bss) {
+ err = -EINVAL;
+ goto free;
+ }
+
+ kfree(attrs);
+ attrs = NULL;
+ } else {
+ if (req.link_id >= 0)
+ return -EINVAL;
+
+ req.bss = nl80211_assoc_bss(rdev, ssid, ssid_len, info->attrs,
+ &bssid);
+ if (IS_ERR(req.bss))
+ return PTR_ERR(req.bss);
+ }
err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
if (!err) {
@@ -10605,7 +10686,11 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
wdev_unlock(dev->ieee80211_ptr);
}
+free:
+ for (link_id = 0; link_id < ARRAY_SIZE(req.links); link_id++)
+ cfg80211_put_bss(&rdev->wiphy, req.links[link_id].bss);
cfg80211_put_bss(&rdev->wiphy, req.bss);
+ kfree(attrs);
return err;
}
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index c8a99b90723b..b3c6ce4f85ee 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -177,6 +177,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev,
params->ssid, params->ssid_len,
IEEE80211_BSS_TYPE_ESS,
IEEE80211_PRIVACY_ANY);
+ auth_req.link_id = -1;
err = cfg80211_mlme_auth(rdev, wdev->netdev, &auth_req);
cfg80211_put_bss(&rdev->wiphy, auth_req.bss);
return err;
@@ -198,6 +199,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev,
req.ht_capa_mask = params->ht_capa_mask;
req.vht_capa = params->vht_capa;
req.vht_capa_mask = params->vht_capa_mask;
+ req.link_id = -1;
req.bss = cfg80211_get_bss(&rdev->wiphy, params->channel,
params->bssid,