Commit a7b2cc59 authored by Benjamin Berg's avatar Benjamin Berg Committed by Johannes Berg
Browse files

wifi: cfg80211: report per-link errors during association



When one of the links (other than the assoc_link) is misconfigured
and cannot work the association will fail. However, userspace was not
able to tell that the operation only failed because of a problem with
one of the links. Fix this, by allowing the driver to set a per-link
error code and reporting the (first) offending link by setting the
bad_attr accordingly.

This only allows us to report the first error, but that is sufficient
for userspace to e.g. remove the offending link and retry.

Signed-off-by: default avatarBenjamin Berg <benjamin.berg@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230920211508.ebe63c0bd513.I40799998f02bf987acee1501a2522dc98bb6eb5a@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent ef246a14
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -2980,12 +2980,15 @@ struct cfg80211_auth_request {
 * @elems_len: length of the elements
 * @disabled: If set this link should be included during association etc. but it
 *	should not be used until enabled by the AP MLD.
 * @error: per-link error code, must be <= 0. If there is an error, then the
 *	operation as a whole must fail.
 */
struct cfg80211_assoc_link {
	struct cfg80211_bss *bss;
	const u8 *elems;
	size_t elems_len;
	bool disabled;
	int error;
};

/**
+44 −6
Original line number Diff line number Diff line
@@ -10941,7 +10941,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
		if (cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
					   req.ie, req.ie_len)) {
			GENL_SET_ERR_MSG(info,
			NL_SET_ERR_MSG_ATTR(info->extack,
					    info->attrs[NL80211_ATTR_IE],
					    "non-inheritance makes no sense");
			return -EINVAL;
		}
@@ -11067,6 +11068,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
			if (!attrs[NL80211_ATTR_MLO_LINK_ID]) {
				err = -EINVAL;
				NL_SET_BAD_ATTR(info->extack, link);
				goto free;
			}
@@ -11074,6 +11076,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
			/* cannot use the same link ID again */
			if (req.links[link_id].bss) {
				err = -EINVAL;
				NL_SET_BAD_ATTR(info->extack, link);
				goto free;
			}
			req.links[link_id].bss =
@@ -11081,6 +11084,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
			if (IS_ERR(req.links[link_id].bss)) {
				err = PTR_ERR(req.links[link_id].bss);
				req.links[link_id].bss = NULL;
				NL_SET_ERR_MSG_ATTR(info->extack,
						    link, "Error fetching BSS for link");
				goto free;
			}
@@ -11093,7 +11098,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
				if (cfg80211_find_elem(WLAN_EID_FRAGMENT,
						       req.links[link_id].elems,
						       req.links[link_id].elems_len)) {
					GENL_SET_ERR_MSG(info,
					NL_SET_ERR_MSG_ATTR(info->extack,
							    attrs[NL80211_ATTR_IE],
							    "cannot deal with fragmentation");
					err = -EINVAL;
					goto free;
@@ -11102,7 +11108,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
				if (cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
							   req.links[link_id].elems,
							   req.links[link_id].elems_len)) {
					GENL_SET_ERR_MSG(info,
					NL_SET_ERR_MSG_ATTR(info->extack,
							    attrs[NL80211_ATTR_IE],
							    "cannot deal with non-inheritance");
					err = -EINVAL;
					goto free;
@@ -11146,6 +11153,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
	err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
	if (!err) {
		struct nlattr *link;
		int rem = 0;
		err = cfg80211_mlme_assoc(rdev, dev, &req);
		if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
@@ -11154,6 +11164,34 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
			memcpy(dev->ieee80211_ptr->disconnect_bssid,
			       ap_addr, ETH_ALEN);
		}
		/* Report error from first problematic link */
		if (info->attrs[NL80211_ATTR_MLO_LINKS]) {
			nla_for_each_nested(link,
					    info->attrs[NL80211_ATTR_MLO_LINKS],
					    rem) {
				struct nlattr *link_id_attr =
					nla_find_nested(link, NL80211_ATTR_MLO_LINK_ID);
				if (!link_id_attr)
					continue;
				link_id = nla_get_u8(link_id_attr);
				if (link_id == req.link_id)
					continue;
				if (!req.links[link_id].error ||
				    WARN_ON(req.links[link_id].error > 0))
					continue;
				WARN_ON(err >= 0);
				NL_SET_BAD_ATTR(info->extack, link);
				err = req.links[link_id].error;
				break;
			}
		}
	}
free: