Commit dbbb27e1 authored by Aloka Dixit's avatar Aloka Dixit Committed by Johannes Berg

cfg80211: support RNR for EMA AP

As per IEEE Std 802.11ax-2021, 11.1.3.8.3 Discovery of a nontransmitted
BSSID profile, an EMA AP that transmits a Beacon frame carrying a partial
list of nontransmitted BSSID profiles should include in the frame
a Reduced Neighbor Report element carrying information for at least the
nontransmitted BSSIDs that are not present in the Multiple BSSID element
carried in that frame.
Add new nested attribute NL80211_ATTR_EMA_RNR_ELEMS to support the above.
Number of RNR elements must be more than or equal to the number of
MBSSID elements. This attribute can be used only when EMA is enabled.
Userspace is responsible for splitting the RNR into multiple elements such
that each element excludes the non-transmitting profiles already included
in the MBSSID element (%NL80211_ATTR_MBSSID_ELEMS) at the same index.
Each EMA beacon will be generated by adding MBSSID and RNR elements
at the same index. If the userspace provides more RNR elements than the
number of MBSSID elements then these will be added in every EMA beacon.
Signed-off-by: default avatarAloka Dixit <quic_alokad@quicinc.com>
Link: https://lore.kernel.org/r/20230323113801.6903-2-quic_alokad@quicinc.com
[Johannes: validate elements]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent f102424b
...@@ -1178,6 +1178,23 @@ struct cfg80211_mbssid_elems { ...@@ -1178,6 +1178,23 @@ struct cfg80211_mbssid_elems {
} elem[]; } elem[];
}; };
/**
* struct cfg80211_rnr_elems - Reduced neighbor report (RNR) elements
*
* @cnt: Number of elements in array %elems.
*
* @elem: Array of RNR element(s) to be added into Beacon frames.
* @elem.data: Data for RNR elements.
* @elem.len: Length of data.
*/
struct cfg80211_rnr_elems {
u8 cnt;
struct {
const u8 *data;
size_t len;
} elem[];
};
/** /**
* struct cfg80211_beacon_data - beacon data * struct cfg80211_beacon_data - beacon data
* @link_id: the link ID for the AP MLD link sending this beacon * @link_id: the link ID for the AP MLD link sending this beacon
...@@ -1198,6 +1215,7 @@ struct cfg80211_mbssid_elems { ...@@ -1198,6 +1215,7 @@ struct cfg80211_mbssid_elems {
* @probe_resp_len: length of probe response template (@probe_resp) * @probe_resp_len: length of probe response template (@probe_resp)
* @probe_resp: probe response template (AP mode only) * @probe_resp: probe response template (AP mode only)
* @mbssid_ies: multiple BSSID elements * @mbssid_ies: multiple BSSID elements
* @rnr_ies: reduced neighbor report elements
* @ftm_responder: enable FTM responder functionality; -1 for no change * @ftm_responder: enable FTM responder functionality; -1 for no change
* (which also implies no change in LCI/civic location data) * (which also implies no change in LCI/civic location data)
* @lci: Measurement Report element content, starting with Measurement Token * @lci: Measurement Report element content, starting with Measurement Token
...@@ -1221,6 +1239,7 @@ struct cfg80211_beacon_data { ...@@ -1221,6 +1239,7 @@ struct cfg80211_beacon_data {
const u8 *lci; const u8 *lci;
const u8 *civicloc; const u8 *civicloc;
struct cfg80211_mbssid_elems *mbssid_ies; struct cfg80211_mbssid_elems *mbssid_ies;
struct cfg80211_rnr_elems *rnr_ies;
s8 ftm_responder; s8 ftm_responder;
size_t head_len, tail_len; size_t head_len, tail_len;
......
...@@ -2794,6 +2794,17 @@ enum nl80211_commands { ...@@ -2794,6 +2794,17 @@ enum nl80211_commands {
* @NL80211_ATTR_HW_TIMESTAMP_ENABLED: Indicates whether HW timestamping should * @NL80211_ATTR_HW_TIMESTAMP_ENABLED: Indicates whether HW timestamping should
* be enabled or not (flag attribute). * be enabled or not (flag attribute).
* *
* @NL80211_ATTR_EMA_RNR_ELEMS: Optional nested attribute for
* reduced neighbor report (RNR) elements. This attribute can be used
* only when NL80211_MBSSID_CONFIG_ATTR_EMA is enabled.
* Userspace is responsible for splitting the RNR into multiple
* elements such that each element excludes the non-transmitting
* profiles already included in the MBSSID element
* (%NL80211_ATTR_MBSSID_ELEMS) at the same index. Each EMA beacon
* will be generated by adding MBSSID and RNR elements at the same
* index. If the userspace includes more RNR elements than number of
* MBSSID elements then these will be added in every EMA beacon.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
...@@ -3328,6 +3339,8 @@ enum nl80211_attrs { ...@@ -3328,6 +3339,8 @@ enum nl80211_attrs {
NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS, NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS,
NL80211_ATTR_HW_TIMESTAMP_ENABLED, NL80211_ATTR_HW_TIMESTAMP_ENABLED,
NL80211_ATTR_EMA_RNR_ELEMS,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
......
...@@ -809,6 +809,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { ...@@ -809,6 +809,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS] = { .type = NLA_U16 }, [NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS] = { .type = NLA_U16 },
[NL80211_ATTR_HW_TIMESTAMP_ENABLED] = { .type = NLA_FLAG }, [NL80211_ATTR_HW_TIMESTAMP_ENABLED] = { .type = NLA_FLAG },
[NL80211_ATTR_EMA_RNR_ELEMS] = { .type = NLA_NESTED },
}; };
/* policy for the key attributes */ /* policy for the key attributes */
...@@ -5425,6 +5426,38 @@ nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs) ...@@ -5425,6 +5426,38 @@ nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs)
return elems; return elems;
} }
static struct cfg80211_rnr_elems *
nl80211_parse_rnr_elems(struct wiphy *wiphy, struct nlattr *attrs,
struct netlink_ext_ack *extack)
{
struct nlattr *nl_elems;
struct cfg80211_rnr_elems *elems;
int rem_elems;
u8 i = 0, num_elems = 0;
nla_for_each_nested(nl_elems, attrs, rem_elems) {
int ret;
ret = validate_ie_attr(nl_elems, extack);
if (ret)
return ERR_PTR(ret);
num_elems++;
}
elems = kzalloc(struct_size(elems, elem, num_elems), GFP_KERNEL);
if (!elems)
return ERR_PTR(-ENOMEM);
nla_for_each_nested(nl_elems, attrs, rem_elems) {
elems->elem[i].data = nla_data(nl_elems);
elems->elem[i].len = nla_len(nl_elems);
i++;
}
elems->cnt = num_elems;
return elems;
}
static int nl80211_parse_he_bss_color(struct nlattr *attrs, static int nl80211_parse_he_bss_color(struct nlattr *attrs,
struct cfg80211_he_bss_color *he_bss_color) struct cfg80211_he_bss_color *he_bss_color)
{ {
...@@ -5451,7 +5484,8 @@ static int nl80211_parse_he_bss_color(struct nlattr *attrs, ...@@ -5451,7 +5484,8 @@ static int nl80211_parse_he_bss_color(struct nlattr *attrs,
static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
struct nlattr *attrs[], struct nlattr *attrs[],
struct cfg80211_beacon_data *bcn) struct cfg80211_beacon_data *bcn,
struct netlink_ext_ack *extack)
{ {
bool haveinfo = false; bool haveinfo = false;
int err; int err;
...@@ -5548,6 +5582,21 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, ...@@ -5548,6 +5582,21 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
return PTR_ERR(mbssid); return PTR_ERR(mbssid);
bcn->mbssid_ies = mbssid; bcn->mbssid_ies = mbssid;
if (bcn->mbssid_ies && attrs[NL80211_ATTR_EMA_RNR_ELEMS]) {
struct cfg80211_rnr_elems *rnr =
nl80211_parse_rnr_elems(&rdev->wiphy,
attrs[NL80211_ATTR_EMA_RNR_ELEMS],
extack);
if (IS_ERR(rnr))
return PTR_ERR(rnr);
if (rnr && rnr->cnt < bcn->mbssid_ies->cnt)
return -EINVAL;
bcn->rnr_ies = rnr;
}
} }
return 0; return 0;
...@@ -5866,7 +5915,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -5866,7 +5915,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (!params) if (!params)
return -ENOMEM; return -ENOMEM;
err = nl80211_parse_beacon(rdev, info->attrs, &params->beacon); err = nl80211_parse_beacon(rdev, info->attrs, &params->beacon,
info->extack);
if (err) if (err)
goto out; goto out;
...@@ -6096,6 +6146,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -6096,6 +6146,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
goto out_unlock; goto out_unlock;
} }
if (!params->mbssid_config.ema && params->beacon.rnr_ies) {
err = -EINVAL;
goto out_unlock;
}
err = nl80211_calculate_ap_params(params); err = nl80211_calculate_ap_params(params);
if (err) if (err)
goto out_unlock; goto out_unlock;
...@@ -6137,6 +6192,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -6137,6 +6192,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
params->mbssid_config.tx_wdev->netdev && params->mbssid_config.tx_wdev->netdev &&
params->mbssid_config.tx_wdev->netdev != dev) params->mbssid_config.tx_wdev->netdev != dev)
dev_put(params->mbssid_config.tx_wdev->netdev); dev_put(params->mbssid_config.tx_wdev->netdev);
kfree(params->beacon.rnr_ies);
kfree(params); kfree(params);
return err; return err;
...@@ -6161,7 +6217,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) ...@@ -6161,7 +6217,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
if (!wdev->links[link_id].ap.beacon_interval) if (!wdev->links[link_id].ap.beacon_interval)
return -EINVAL; return -EINVAL;
err = nl80211_parse_beacon(rdev, info->attrs, &params); err = nl80211_parse_beacon(rdev, info->attrs, &params, info->extack);
if (err) if (err)
goto out; goto out;
...@@ -6171,6 +6227,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) ...@@ -6171,6 +6227,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
out: out:
kfree(params.mbssid_ies); kfree(params.mbssid_ies);
kfree(params.rnr_ies);
return err; return err;
} }
...@@ -10030,7 +10087,8 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) ...@@ -10030,7 +10087,8 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
if (!need_new_beacon) if (!need_new_beacon)
goto skip_beacons; goto skip_beacons;
err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_after); err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_after,
info->extack);
if (err) if (err)
goto free; goto free;
...@@ -10047,7 +10105,8 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) ...@@ -10047,7 +10105,8 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
if (err) if (err)
goto free; goto free;
err = nl80211_parse_beacon(rdev, csa_attrs, &params.beacon_csa); err = nl80211_parse_beacon(rdev, csa_attrs, &params.beacon_csa,
info->extack);
if (err) if (err)
goto free; goto free;
...@@ -10167,6 +10226,8 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) ...@@ -10167,6 +10226,8 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
free: free:
kfree(params.beacon_after.mbssid_ies); kfree(params.beacon_after.mbssid_ies);
kfree(params.beacon_csa.mbssid_ies); kfree(params.beacon_csa.mbssid_ies);
kfree(params.beacon_after.rnr_ies);
kfree(params.beacon_csa.rnr_ies);
kfree(csa_attrs); kfree(csa_attrs);
return err; return err;
} }
...@@ -15882,7 +15943,8 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info) ...@@ -15882,7 +15943,8 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
params.count = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT]); params.count = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT]);
params.color = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR]); params.color = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR]);
err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_next); err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_next,
info->extack);
if (err) if (err)
return err; return err;
...@@ -15896,7 +15958,8 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info) ...@@ -15896,7 +15958,8 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
if (err) if (err)
goto out; goto out;
err = nl80211_parse_beacon(rdev, tb, &params.beacon_color_change); err = nl80211_parse_beacon(rdev, tb, &params.beacon_color_change,
info->extack);
if (err) if (err)
goto out; goto out;
...@@ -15952,6 +16015,8 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info) ...@@ -15952,6 +16015,8 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
out: out:
kfree(params.beacon_next.mbssid_ies); kfree(params.beacon_next.mbssid_ies);
kfree(params.beacon_color_change.mbssid_ies); kfree(params.beacon_color_change.mbssid_ies);
kfree(params.beacon_next.rnr_ies);
kfree(params.beacon_color_change.rnr_ies);
kfree(tb); kfree(tb);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment