return 0;
}
+static void nl80211_check_ap_rate_selectors(struct cfg80211_beacon_data *bcn,
+ const struct element *rates)
+{
+ int i;
+
+ if (!rates)
+ return;
+
+ for (i = 0; i < rates->datalen; i++) {
+ if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
+ bcn->ht_required = true;
+ if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
+ bcn->vht_required = true;
+ }
+}
+
+/*
+ * Since the nl80211 API didn't include, from the beginning, attributes about
+ * HT/VHT/... operation, we parse them out of the elements and check for
+ * validity for use by drivers/mac80211.
+ */
+static int nl80211_calculate_ap_operation(struct nlattr *attrs[],
+ struct cfg80211_beacon_data *bcn,
+ struct netlink_ext_ack *extack)
+{
+ size_t ies_len = bcn->tail_len;
+ const u8 *ies = bcn->tail;
+ const struct element *rates;
+ const struct element *op;
+
+ rates = cfg80211_find_elem(WLAN_EID_SUPP_RATES, ies, ies_len);
+ nl80211_check_ap_rate_selectors(bcn, rates);
+
+ rates = cfg80211_find_elem(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
+ nl80211_check_ap_rate_selectors(bcn, rates);
+
+ op = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
+ if (op) {
+ if (op->datalen < sizeof(*bcn->he_oper) + 1) {
+ NL_SET_ERR_MSG(extack, "bad HE operation in beacon");
+ return -EINVAL;
+ }
+ bcn->he_oper = (void *)(op->data + 1);
+ /* takes extension ID into account */
+ if (op->datalen < ieee80211_he_oper_size((void *)bcn->he_oper)) {
+ NL_SET_ERR_MSG(extack, "bad HE operation in beacon");
+ return -EINVAL;
+ }
+ }
+
+ op = cfg80211_find_elem(WLAN_EID_HT_OPERATION, ies, ies_len);
+ if (op) {
+ if (op->datalen < sizeof(*bcn->ht_oper)) {
+ NL_SET_ERR_MSG(extack, "bad HT operation in beacon");
+ return -EINVAL;
+ }
+ bcn->ht_oper = (void *)op->data;
+ }
+
+ op = cfg80211_find_elem(WLAN_EID_VHT_OPERATION, ies, ies_len);
+ if (op) {
+ if (op->datalen < sizeof(*bcn->vht_oper)) {
+ NL_SET_ERR_MSG(extack, "bad VHT operation in beacon");
+ return -EINVAL;
+ }
+ bcn->vht_oper = (void *)op->data;
+ }
+
+ op = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_OPERATION, ies, ies_len);
+ if (op) {
+ if (!ieee80211_eht_oper_size_ok(op->data + 1,
+ op->datalen - 1)) {
+ NL_SET_ERR_MSG(extack, "bad EHT operation in beacon");
+ return -EINVAL;
+ }
+ bcn->eht_oper = (void *)(op->data + 1);
+ }
+
+ op = cfg80211_find_ext_elem(WLAN_EID_EXT_UHR_OPER, ies, ies_len);
+ if (op) {
+ /* need full UHR operation separately */
+ if (!attrs[NL80211_ATTR_UHR_OPERATION]) {
+ NL_SET_ERR_MSG(extack, "missing UHR operation");
+ return -EINVAL;
+ }
+ bcn->uhr_oper = nla_data(attrs[NL80211_ATTR_UHR_OPERATION]);
+ } else if (attrs[NL80211_ATTR_UHR_OPERATION]) {
+ NL_SET_ERR_MSG(extack, "unexpected UHR operation");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
struct nlattr *attrs[],
struct cfg80211_beacon_data *bcn,
+ struct ieee80211_channel *chan,
struct netlink_ext_ack *extack)
{
bool haveinfo = false;
}
}
+ err = nl80211_calculate_ap_operation(attrs, bcn, extack);
+ if (err)
+ return err;
+
+ if (bcn->he_oper && (chan->flags & IEEE80211_CHAN_NO_HE))
+ return -EOPNOTSUPP;
+
+ if (bcn->eht_oper && (chan->flags & IEEE80211_CHAN_NO_EHT))
+ return -EOPNOTSUPP;
+
+ if (bcn->uhr_oper && (chan->flags & IEEE80211_CHAN_NO_UHR))
+ return -EOPNOTSUPP;
+
return 0;
}
return 0;
}
-static void nl80211_check_ap_rate_selectors(struct cfg80211_beacon_data *bcn,
- const struct element *rates)
-{
- int i;
-
- if (!rates)
- return;
-
- for (i = 0; i < rates->datalen; i++) {
- if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
- bcn->ht_required = true;
- if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
- bcn->vht_required = true;
- }
-}
-
/*
* Since the nl80211 API didn't include, from the beginning, attributes about
* HT/VHT/... capabilities, we parse them out of the elements and check for
return 0;
}
-/*
- * Since the nl80211 API didn't include, from the beginning, attributes about
- * HT/VHT/... operation, we parse them out of the elements and check for
- * validity for use by drivers/mac80211.
- */
-static int nl80211_calculate_ap_operation(struct genl_info *info,
- struct cfg80211_beacon_data *bcn)
-{
- size_t ies_len = bcn->tail_len;
- const u8 *ies = bcn->tail;
- const struct element *rates;
- const struct element *op;
-
- rates = cfg80211_find_elem(WLAN_EID_SUPP_RATES, ies, ies_len);
- nl80211_check_ap_rate_selectors(bcn, rates);
-
- rates = cfg80211_find_elem(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
- nl80211_check_ap_rate_selectors(bcn, rates);
-
- op = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
- if (op) {
- if (op->datalen < sizeof(*bcn->he_oper) + 1) {
- GENL_SET_ERR_MSG(info, "bad HE operation in beacon");
- return -EINVAL;
- }
- bcn->he_oper = (void *)(op->data + 1);
- /* takes extension ID into account */
- if (op->datalen < ieee80211_he_oper_size((void *)bcn->he_oper)) {
- GENL_SET_ERR_MSG(info, "bad HE operation in beacon");
- return -EINVAL;
- }
- }
-
- op = cfg80211_find_elem(WLAN_EID_HT_OPERATION, ies, ies_len);
- if (op) {
- if (op->datalen < sizeof(*bcn->ht_oper)) {
- GENL_SET_ERR_MSG(info, "bad HT operation in beacon");
- return -EINVAL;
- }
- bcn->ht_oper = (void *)op->data;
- }
-
- op = cfg80211_find_elem(WLAN_EID_VHT_OPERATION, ies, ies_len);
- if (op) {
- if (op->datalen < sizeof(*bcn->vht_oper)) {
- GENL_SET_ERR_MSG(info, "bad VHT operation in beacon");
- return -EINVAL;
- }
- bcn->vht_oper = (void *)op->data;
- }
-
- op = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_OPERATION, ies, ies_len);
- if (op) {
- if (!ieee80211_eht_oper_size_ok(op->data + 1,
- op->datalen - 1)) {
- GENL_SET_ERR_MSG(info, "bad EHT operation in beacon");
- return -EINVAL;
- }
- bcn->eht_oper = (void *)(op->data + 1);
- }
-
- op = cfg80211_find_ext_elem(WLAN_EID_EXT_UHR_OPER, ies, ies_len);
- if (op) {
- /* need full UHR operation separately */
- if (!info->attrs[NL80211_ATTR_UHR_OPERATION]) {
- GENL_SET_ERR_MSG(info, "missing UHR operation");
- return -EINVAL;
- }
- bcn->uhr_oper = nla_data(info->attrs[NL80211_ATTR_UHR_OPERATION]);
- } else if (info->attrs[NL80211_ATTR_UHR_OPERATION]) {
- GENL_SET_ERR_MSG(info, "unexpected UHR operation");
- return -EINVAL;
- }
-
- return 0;
-}
-
static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
struct cfg80211_ap_settings *params)
{
nlmsg_free(msg);
}
-static int nl80211_validate_ap_phy_operation(struct ieee80211_channel *channel,
- struct cfg80211_beacon_data *bcn)
-{
- if (bcn->he_oper && (channel->flags & IEEE80211_CHAN_NO_HE))
- return -EOPNOTSUPP;
-
- if (bcn->eht_oper && (channel->flags & IEEE80211_CHAN_NO_EHT))
- return -EOPNOTSUPP;
-
- if (bcn->uhr_oper && (channel->flags & IEEE80211_CHAN_NO_UHR))
- return -EOPNOTSUPP;
-
- return 0;
-}
-
static int
nl80211_parse_s1g_short_beacon(struct cfg80211_registered_device *rdev,
struct nlattr *attrs,
if (!params)
return -ENOMEM;
- err = nl80211_parse_beacon(rdev, info->attrs, ¶ms->beacon,
- info->extack);
- if (err)
- goto out;
-
params->beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
params->dtim_period =
goto out;
}
+ err = nl80211_parse_beacon(rdev, info->attrs, ¶ms->beacon,
+ params->chandef.chan, info->extack);
+ if (err)
+ goto out;
+
beacon_check.iftype = wdev->iftype;
beacon_check.relax = true;
beacon_check.reg_power =
if (err)
goto out;
- err = nl80211_calculate_ap_operation(info, ¶ms->beacon);
- if (err)
- goto out;
-
- err = nl80211_validate_ap_phy_operation(params->chandef.chan,
- ¶ms->beacon);
- if (err)
- goto out;
-
if (info->attrs[NL80211_ATTR_AP_SETTINGS_FLAGS])
params->flags = nla_get_u32(
info->attrs[NL80211_ATTR_AP_SETTINGS_FLAGS]);
return -ENOMEM;
err = nl80211_parse_beacon(rdev, info->attrs, ¶ms->beacon,
+ wdev->links[link_id].ap.chandef.chan,
info->extack);
if (err)
goto out;
- err = nl80211_calculate_ap_operation(info, ¶ms->beacon);
- if (err)
- goto out;
-
- err = nl80211_validate_ap_phy_operation(wdev->links[link_id].ap.chandef.chan,
- ¶ms->beacon);
- if (err)
- goto out;
-
/* recheck beaconing is permitted with possibly changed power type */
beacon_check.iftype = wdev->iftype;
beacon_check.relax = true;
params.count = cs_count;
+ err = nl80211_parse_chandef(rdev, info->extack, info->attrs,
+ ¶ms.chandef);
+ if (err)
+ goto free;
+
if (!need_new_beacon)
goto skip_beacons;
err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after,
- info->extack);
+ params.chandef.chan, info->extack);
if (err)
goto free;
goto free;
err = nl80211_parse_beacon(rdev, csa_attrs, ¶ms.beacon_csa,
+ wdev->links[link_id].ap.chandef.chan,
info->extack);
if (err)
goto free;
goto free;
skip_beacons:
- err = nl80211_parse_chandef(rdev, info->extack, info->attrs,
- ¶ms.chandef);
- if (err)
- goto free;
-
if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
wdev->iftype)) {
err = -EINVAL;
params.color = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR]);
err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_next,
+ wdev->links[params.link_id].ap.chandef.chan,
info->extack);
if (err)
return err;
goto out;
err = nl80211_parse_beacon(rdev, tb, ¶ms.beacon_color_change,
+ wdev->links[params.link_id].ap.chandef.chan,
info->extack);
if (err)
goto out;