summaryrefslogtreecommitdiff
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/Makefile4
-rw-r--r--net/wireless/core.c10
-rw-r--r--net/wireless/nl80211.c452
-rw-r--r--net/wireless/rdev-ops.h14
-rw-r--r--net/wireless/scan.c59
-rw-r--r--net/wireless/trace.h31
-rw-r--r--net/wireless/util.c2
7 files changed, 436 insertions, 136 deletions
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index af590ae606b6..756e7de7e33f 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -26,7 +26,7 @@ endif
$(obj)/shipped-certs.c: $(wildcard $(srctree)/$(src)/certs/*.hex)
@$(kecho) " GEN $@"
- @(echo '#include "reg.h"'; \
+ $(Q)(echo '#include "reg.h"'; \
echo 'const u8 shipped_regdb_certs[] = {'; \
echo | cat - $^ ; \
echo '};'; \
@@ -36,7 +36,7 @@ $(obj)/shipped-certs.c: $(wildcard $(srctree)/$(src)/certs/*.hex)
$(obj)/extra-certs.c: $(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR:"%"=%) \
$(wildcard $(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR:"%"=%)/*.x509)
@$(kecho) " GEN $@"
- @(set -e; \
+ $(Q)(set -e; \
allf=""; \
for f in $^ ; do \
test -f $$f || continue;\
diff --git a/net/wireless/core.c b/net/wireless/core.c
index aaba847d79eb..eb297e1015e0 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1081,6 +1081,16 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
cfg80211_put_bss(&rdev->wiphy, &scan->pub);
mutex_destroy(&rdev->wiphy.mtx);
+
+ /*
+ * The 'regd' can only be non-NULL if we never finished
+ * initializing the wiphy and thus never went through the
+ * unregister path - e.g. in failure scenarios. Thus, it
+ * cannot have been visible to anyone if non-NULL, so we
+ * can just free it here.
+ */
+ kfree(rcu_dereference_raw(rdev->wiphy.regd));
+
kfree(rdev);
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index bf7cd4752547..81232b73df8f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -437,6 +437,16 @@ sar_policy[NL80211_SAR_ATTR_MAX + 1] = {
[NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy),
};
+static const struct nla_policy
+nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = {
+ [NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES] = NLA_POLICY_MIN(NLA_U8, 2),
+ [NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY] =
+ NLA_POLICY_MIN(NLA_U8, 1),
+ [NL80211_MBSSID_CONFIG_ATTR_INDEX] = { .type = NLA_U8 },
+ [NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 },
+ [NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG },
+};
+
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
@@ -763,6 +773,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 },
[NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 },
[NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy),
+ [NL80211_ATTR_MBSSID_CONFIG] =
+ NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
+ [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
};
/* policy for the key attributes */
@@ -853,6 +866,7 @@ nl80211_match_band_rssi_policy[NUM_NL80211_BANDS] = {
[NL80211_BAND_5GHZ] = { .type = NLA_S32 },
[NL80211_BAND_6GHZ] = { .type = NLA_S32 },
[NL80211_BAND_60GHZ] = { .type = NLA_S32 },
+ [NL80211_BAND_LC] = { .type = NLA_S32 },
};
static const struct nla_policy
@@ -2207,6 +2221,35 @@ fail:
return -ENOBUFS;
}
+static int nl80211_put_mbssid_support(struct wiphy *wiphy, struct sk_buff *msg)
+{
+ struct nlattr *config;
+
+ if (!wiphy->mbssid_max_interfaces)
+ return 0;
+
+ config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG);
+ if (!config)
+ return -ENOBUFS;
+
+ if (nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES,
+ wiphy->mbssid_max_interfaces))
+ goto fail;
+
+ if (wiphy->ema_max_profile_periodicity &&
+ nla_put_u8(msg,
+ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY,
+ wiphy->ema_max_profile_periodicity))
+ goto fail;
+
+ nla_nest_end(msg, config);
+ return 0;
+
+fail:
+ nla_nest_cancel(msg, config);
+ return -ENOBUFS;
+}
+
struct nl80211_dump_wiphy_state {
s64 filter_wiphy;
long start;
@@ -2792,6 +2835,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
if (nl80211_put_sar_specs(rdev, msg))
goto nla_put_failure;
+ if (nl80211_put_mbssid_support(&rdev->wiphy, msg))
+ goto nla_put_failure;
+
/* done */
state->split_start = 0;
break;
@@ -4981,6 +5027,96 @@ static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
return 0;
}
+static int nl80211_parse_mbssid_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct nlattr *attrs,
+ struct cfg80211_mbssid_config *config,
+ u8 num_elems)
+{
+ struct nlattr *tb[NL80211_MBSSID_CONFIG_ATTR_MAX + 1];
+
+ if (!wiphy->mbssid_max_interfaces)
+ return -EOPNOTSUPP;
+
+ if (nla_parse_nested(tb, NL80211_MBSSID_CONFIG_ATTR_MAX, attrs, NULL,
+ NULL) ||
+ !tb[NL80211_MBSSID_CONFIG_ATTR_INDEX])
+ return -EINVAL;
+
+ config->ema = nla_get_flag(tb[NL80211_MBSSID_CONFIG_ATTR_EMA]);
+ if (config->ema) {
+ if (!wiphy->ema_max_profile_periodicity)
+ return -EOPNOTSUPP;
+
+ if (num_elems > wiphy->ema_max_profile_periodicity)
+ return -EINVAL;
+ }
+
+ config->index = nla_get_u8(tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]);
+ if (config->index >= wiphy->mbssid_max_interfaces ||
+ (!config->index && !num_elems))
+ return -EINVAL;
+
+ if (tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]) {
+ u32 tx_ifindex =
+ nla_get_u32(tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]);
+
+ if ((!config->index && tx_ifindex != dev->ifindex) ||
+ (config->index && tx_ifindex == dev->ifindex))
+ return -EINVAL;
+
+ if (tx_ifindex != dev->ifindex) {
+ struct net_device *tx_netdev =
+ dev_get_by_index(wiphy_net(wiphy), tx_ifindex);
+
+ if (!tx_netdev || !tx_netdev->ieee80211_ptr ||
+ tx_netdev->ieee80211_ptr->wiphy != wiphy ||
+ tx_netdev->ieee80211_ptr->iftype !=
+ NL80211_IFTYPE_AP) {
+ dev_put(tx_netdev);
+ return -EINVAL;
+ }
+
+ config->tx_wdev = tx_netdev->ieee80211_ptr;
+ } else {
+ config->tx_wdev = dev->ieee80211_ptr;
+ }
+ } else if (!config->index) {
+ config->tx_wdev = dev->ieee80211_ptr;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct cfg80211_mbssid_elems *
+nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs)
+{
+ struct nlattr *nl_elems;
+ struct cfg80211_mbssid_elems *elems;
+ int rem_elems;
+ u8 i = 0, num_elems = 0;
+
+ if (!wiphy->mbssid_max_interfaces)
+ return ERR_PTR(-EINVAL);
+
+ nla_for_each_nested(nl_elems, attrs, rem_elems)
+ 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_beacon(struct cfg80211_registered_device *rdev,
struct nlattr *attrs[],
struct cfg80211_beacon_data *bcn)
@@ -5061,6 +5197,17 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
bcn->ftm_responder = -1;
}
+ if (attrs[NL80211_ATTR_MBSSID_ELEMS]) {
+ struct cfg80211_mbssid_elems *mbssid =
+ nl80211_parse_mbssid_elems(&rdev->wiphy,
+ attrs[NL80211_ATTR_MBSSID_ELEMS]);
+
+ if (IS_ERR(mbssid))
+ return PTR_ERR(mbssid);
+
+ bcn->mbssid_ies = mbssid;
+ }
+
return 0;
}
@@ -5192,21 +5339,21 @@ nl80211_parse_unsol_bcast_probe_resp(struct cfg80211_registered_device *rdev,
}
static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
- const u8 *rates)
+ const struct element *rates)
{
int i;
if (!rates)
return;
- for (i = 0; i < rates[1]; i++) {
- if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
+ for (i = 0; i < rates->datalen; i++) {
+ if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
params->ht_required = true;
- if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
+ if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
params->vht_required = true;
- if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
+ if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
params->he_required = true;
- if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_SAE_H2E)
+ if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_SAE_H2E)
params->sae_h2e_required = true;
}
}
@@ -5221,27 +5368,27 @@ static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
const struct cfg80211_beacon_data *bcn = &params->beacon;
size_t ies_len = bcn->tail_len;
const u8 *ies = bcn->tail;
- const u8 *rates;
- const u8 *cap;
+ const struct element *rates;
+ const struct element *cap;
- rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
+ rates = cfg80211_find_elem(WLAN_EID_SUPP_RATES, ies, ies_len);
nl80211_check_ap_rate_selectors(params, rates);
- rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
+ rates = cfg80211_find_elem(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
nl80211_check_ap_rate_selectors(params, rates);
- cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
- if (cap && cap[1] >= sizeof(*params->ht_cap))
- params->ht_cap = (void *)(cap + 2);
- cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
- if (cap && cap[1] >= sizeof(*params->vht_cap))
- params->vht_cap = (void *)(cap + 2);
- cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
- if (cap && cap[1] >= sizeof(*params->he_cap) + 1)
- params->he_cap = (void *)(cap + 3);
- cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
- if (cap && cap[1] >= sizeof(*params->he_oper) + 1)
- params->he_oper = (void *)(cap + 3);
+ cap = cfg80211_find_elem(WLAN_EID_HT_CAPABILITY, ies, ies_len);
+ if (cap && cap->datalen >= sizeof(*params->ht_cap))
+ params->ht_cap = (void *)cap->data;
+ cap = cfg80211_find_elem(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
+ if (cap && cap->datalen >= sizeof(*params->vht_cap))
+ params->vht_cap = (void *)cap->data;
+ cap = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
+ if (cap && cap->datalen >= sizeof(*params->he_cap) + 1)
+ params->he_cap = (void *)(cap->data + 1);
+ cap = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
+ if (cap && cap->datalen >= sizeof(*params->he_oper) + 1)
+ params->he_oper = (void *)(cap->data + 1);
}
static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
@@ -5323,7 +5470,7 @@ static int nl80211_start_ap(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 wireless_dev *wdev = dev->ieee80211_ptr;
- struct cfg80211_ap_settings params;
+ struct cfg80211_ap_settings *params;
int err;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
@@ -5336,27 +5483,29 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (wdev->beacon_interval)
return -EALREADY;
- memset(&params, 0, sizeof(params));
-
/* these are required for START_AP */
if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
!info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
!info->attrs[NL80211_ATTR_BEACON_HEAD])
return -EINVAL;
- err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon);
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ err = nl80211_parse_beacon(rdev, info->attrs, &params->beacon);
if (err)
- return err;
+ goto out;
- params.beacon_interval =
+ params->beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- params.dtim_period =
+ params->dtim_period =
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
- params.beacon_interval);
+ params->beacon_interval);
if (err)
- return err;
+ goto out;
/*
* In theory, some of these attributes should be required here
@@ -5366,129 +5515,157 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
* additional information -- drivers must check!
*/
if (info->attrs[NL80211_ATTR_SSID]) {
- params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
- params.ssid_len =
+ params->ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ params->ssid_len =
nla_len(info->attrs[NL80211_ATTR_SSID]);
- if (params.ssid_len == 0)
- return -EINVAL;
+ if (params->ssid_len == 0) {
+ err = -EINVAL;
+ goto out;
+ }
}
if (info->attrs[NL80211_ATTR_HIDDEN_SSID])
- params.hidden_ssid = nla_get_u32(
+ params->hidden_ssid = nla_get_u32(
info->attrs[NL80211_ATTR_HIDDEN_SSID]);
- params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+ params->privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
- params.auth_type = nla_get_u32(
+ params->auth_type = nla_get_u32(
info->attrs[NL80211_ATTR_AUTH_TYPE]);
- if (!nl80211_valid_auth_type(rdev, params.auth_type,
- NL80211_CMD_START_AP))
- return -EINVAL;
+ if (!nl80211_valid_auth_type(rdev, params->auth_type,
+ NL80211_CMD_START_AP)) {
+ err = -EINVAL;
+ goto out;
+ }
} else
- params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+ params->auth_type = NL80211_AUTHTYPE_AUTOMATIC;
- err = nl80211_crypto_settings(rdev, info, &params.crypto,
+ err = nl80211_crypto_settings(rdev, info, &params->crypto,
NL80211_MAX_NR_CIPHER_SUITES);
if (err)
- return err;
+ goto out;
if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
- if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
- return -EOPNOTSUPP;
- params.inactivity_timeout = nla_get_u16(
+ if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER)) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+ params->inactivity_timeout = nla_get_u16(
info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
}
if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
- return -EINVAL;
- params.p2p_ctwindow =
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
+ err = -EINVAL;
+ goto out;
+ }
+ params->p2p_ctwindow =
nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
- if (params.p2p_ctwindow != 0 &&
- !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
- return -EINVAL;
+ if (params->p2p_ctwindow != 0 &&
+ !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) {
+ err = -EINVAL;
+ goto out;
+ }
}
if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
u8 tmp;
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
- return -EINVAL;
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
+ err = -EINVAL;
+ goto out;
+ }
tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
- params.p2p_opp_ps = tmp;
- if (params.p2p_opp_ps != 0 &&
- !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
- return -EINVAL;
+ params->p2p_opp_ps = tmp;
+ if (params->p2p_opp_ps != 0 &&
+ !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) {
+ err = -EINVAL;
+ goto out;
+ }
}
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
- err = nl80211_parse_chandef(rdev, info, &params.chandef);
+ err = nl80211_parse_chandef(rdev, info, &params->chandef);
if (err)
- return err;
+ goto out;
} else if (wdev->preset_chandef.chan) {
- params.chandef = wdev->preset_chandef;
- } else if (!nl80211_get_ap_channel(rdev, &params))
- return -EINVAL;
+ params->chandef = wdev->preset_chandef;
+ } else if (!nl80211_get_ap_channel(rdev, params)) {
+ err = -EINVAL;
+ goto out;
+ }
- if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
- wdev->iftype))
- return -EINVAL;
+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params->chandef,
+ wdev->iftype)) {
+ err = -EINVAL;
+ goto out;
+ }
if (info->attrs[NL80211_ATTR_TX_RATES]) {
err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
NL80211_ATTR_TX_RATES,
- &params.beacon_rate,
+ &params->beacon_rate,
dev, false);
if (err)
- return err;
+ goto out;
- err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
- &params.beacon_rate);
+ err = validate_beacon_tx_rate(rdev, params->chandef.chan->band,
+ &params->beacon_rate);
if (err)
- return err;
+ goto out;
}
if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
- params.smps_mode =
+ params->smps_mode =
nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
- switch (params.smps_mode) {
+ switch (params->smps_mode) {
case NL80211_SMPS_OFF:
break;
case NL80211_SMPS_STATIC:
if (!(rdev->wiphy.features &
- NL80211_FEATURE_STATIC_SMPS))
- return -EINVAL;
+ NL80211_FEATURE_STATIC_SMPS)) {
+ err = -EINVAL;
+ goto out;
+ }
break;
case NL80211_SMPS_DYNAMIC:
if (!(rdev->wiphy.features &
- NL80211_FEATURE_DYNAMIC_SMPS))
- return -EINVAL;
+ NL80211_FEATURE_DYNAMIC_SMPS)) {
+ err = -EINVAL;
+ goto out;
+ }
break;
default:
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
} else {
- params.smps_mode = NL80211_SMPS_OFF;
+ params->smps_mode = NL80211_SMPS_OFF;
}
- params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
- if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
- return -EOPNOTSUPP;
+ params->pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
+ if (params->pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
- params.acl = parse_acl_data(&rdev->wiphy, info);
- if (IS_ERR(params.acl))
- return PTR_ERR(params.acl);
+ params->acl = parse_acl_data(&rdev->wiphy, info);
+ if (IS_ERR(params->acl)) {
+ err = PTR_ERR(params->acl);
+ params->acl = NULL;
+ goto out;
+ }
}
- params.twt_responder =
+ params->twt_responder =
nla_get_flag(info->attrs[NL80211_ATTR_TWT_RESPONDER]);
if (info->attrs[NL80211_ATTR_HE_OBSS_PD]) {
err = nl80211_parse_he_obss_pd(
info->attrs[NL80211_ATTR_HE_OBSS_PD],
- &params.he_obss_pd);
+ &params->he_obss_pd);
if (err)
goto out;
}
@@ -5496,7 +5673,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_HE_BSS_COLOR]) {
err = nl80211_parse_he_bss_color(
info->attrs[NL80211_ATTR_HE_BSS_COLOR],
- &params.he_bss_color);
+ &params->he_bss_color);
if (err)
goto out;
}
@@ -5504,7 +5681,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_FILS_DISCOVERY]) {
err = nl80211_parse_fils_discovery(rdev,
info->attrs[NL80211_ATTR_FILS_DISCOVERY],
- &params);
+ params);
if (err)
goto out;
}
@@ -5512,24 +5689,35 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP]) {
err = nl80211_parse_unsol_bcast_probe_resp(
rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP],
- &params);
+ params);
+ if (err)
+ goto out;
+ }
+
+ if (info->attrs[NL80211_ATTR_MBSSID_CONFIG]) {
+ err = nl80211_parse_mbssid_config(&rdev->wiphy, dev,
+ info->attrs[NL80211_ATTR_MBSSID_CONFIG],
+ &params->mbssid_config,
+ params->beacon.mbssid_ies ?
+ params->beacon.mbssid_ies->cnt :
+ 0);
if (err)
goto out;
}
- nl80211_calculate_ap_params(&params);
+ nl80211_calculate_ap_params(params);
if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
- params.flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
+ params->flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
wdev_lock(wdev);
- err = rdev_start_ap(rdev, dev, &params);
+ err = rdev_start_ap(rdev, dev, params);
if (!err) {
- wdev->preset_chandef = params.chandef;
- wdev->beacon_interval = params.beacon_interval;
- wdev->chandef = params.chandef;
- wdev->ssid_len = params.ssid_len;
- memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
+ wdev->preset_chandef = params->chandef;
+ wdev->beacon_interval = params->beacon_interval;
+ wdev->chandef = params->chandef;
+ wdev->ssid_len = params->ssid_len;
+ memcpy(wdev->ssid, params->ssid, wdev->ssid_len);
if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
wdev->conn_owner_nlportid = info->snd_portid;
@@ -5537,7 +5725,13 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
wdev_unlock(wdev);
out:
- kfree(params.acl);
+ kfree(params->acl);
+ kfree(params->beacon.mbssid_ies);
+ if (params->mbssid_config.tx_wdev &&
+ params->mbssid_config.tx_wdev->netdev &&
+ params->mbssid_config.tx_wdev->netdev != dev)
+ dev_put(params->mbssid_config.tx_wdev->netdev);
+ kfree(params);
return err;
}
@@ -5562,12 +5756,14 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
err = nl80211_parse_beacon(rdev, info->attrs, &params);
if (err)
- return err;
+ goto out;
wdev_lock(wdev);
err = rdev_change_beacon(rdev, dev, &params);
wdev_unlock(wdev);
+out:
+ kfree(params.mbssid_ies);
return err;
}
@@ -9244,12 +9440,14 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_after);
if (err)
- return err;
+ goto free;
csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs),
GFP_KERNEL);
- if (!csa_attrs)
- return -ENOMEM;
+ if (!csa_attrs) {
+ err = -ENOMEM;
+ goto free;
+ }
err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX,
info->attrs[NL80211_ATTR_CSA_IES],
@@ -9367,6 +9565,8 @@ skip_beacons:
wdev_unlock(wdev);
free:
+ kfree(params.beacon_after.mbssid_ies);
+ kfree(params.beacon_csa.mbssid_ies);
kfree(csa_attrs);
return err;
}
@@ -11767,8 +11967,9 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
if (n_thresholds) {
struct cfg80211_cqm_config *cqm_config;
- cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
- n_thresholds * sizeof(s32), GFP_KERNEL);
+ cqm_config = kzalloc(struct_size(cqm_config, rssi_thresholds,
+ n_thresholds),
+ GFP_KERNEL);
if (!cqm_config) {
err = -ENOMEM;
goto unlock;
@@ -11777,7 +11978,8 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
cqm_config->rssi_hyst = hysteresis;
cqm_config->n_rssi_thresholds = n_thresholds;
memcpy(cqm_config->rssi_thresholds, thresholds,
- n_thresholds * sizeof(s32));
+ flex_array_size(cqm_config, rssi_thresholds,
+ n_thresholds));
wdev->cqm_config = cqm_config;
}
@@ -14900,10 +15102,35 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
wdev_unlock(wdev);
out:
+ kfree(params.beacon_next.mbssid_ies);
+ kfree(params.beacon_color_change.mbssid_ies);
kfree(tb);
return err;
}
+static int nl80211_set_fils_aad(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_fils_aad fils_aad = {};
+ u8 *nonces;
+
+ if (!info->attrs[NL80211_ATTR_MAC] ||
+ !info->attrs[NL80211_ATTR_FILS_KEK] ||
+ !info->attrs[NL80211_ATTR_FILS_NONCES])
+ return -EINVAL;
+
+ fils_aad.macaddr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ fils_aad.kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
+ fils_aad.kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
+ nonces = nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
+ fils_aad.snonce = nonces;
+ fils_aad.anonce = nonces + FILS_NONCE_LEN;
+
+ return rdev_set_fils_aad(rdev, dev, &fils_aad);
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -15081,9 +15308,7 @@ static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info)
if (specs > rdev->wiphy.sar_capa->num_freq_ranges)
return -EINVAL;
- sar_spec = kzalloc(sizeof(*sar_spec) +
- specs * sizeof(struct cfg80211_sar_sub_specs),
- GFP_KERNEL);
+ sar_spec = kzalloc(struct_size(sar_spec, sub_specs, specs), GFP_KERNEL);
if (!sar_spec)
return -ENOMEM;
@@ -15907,6 +16132,13 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_SET_FILS_AAD,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .doit = nl80211_set_fils_aad,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index ce6bf218a1a3..cc1efec4b27b 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1381,4 +1381,18 @@ static inline int rdev_color_change(struct cfg80211_registered_device *rdev,
return ret;
}
+static inline int
+rdev_set_fils_aad(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, struct cfg80211_fils_aad *fils_aad)
+{
+ int ret = -EOPNOTSUPP;
+
+ trace_rdev_set_fils_aad(&rdev->wiphy, dev, fils_aad);
+ if (rdev->ops->set_fils_aad)
+ ret = rdev->ops->set_fils_aad(&rdev->wiphy, dev, fils_aad);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+
+ return ret;
+}
+
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index adc0d14cfd86..22e92be61938 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -383,7 +383,7 @@ static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
const u8 *ssid, size_t ssid_len)
{
const struct cfg80211_bss_ies *ies;
- const u8 *ssidie;
+ const struct element *ssid_elem;
if (bssid && !ether_addr_equal(a->bssid, bssid))
return false;
@@ -394,12 +394,12 @@ static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
ies = rcu_access_pointer(a->ies);
if (!ies)
return false;
- ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
- if (!ssidie)
+ ssid_elem = cfg80211_find_elem(WLAN_EID_SSID, ies->data, ies->len);
+ if (!ssid_elem)
return false;
- if (ssidie[1] != ssid_len)
+ if (ssid_elem->datalen != ssid_len)
return false;
- return memcmp(ssidie + 2, ssid, ssid_len) == 0;
+ return memcmp(ssid_elem->data, ssid, ssid_len) == 0;
}
static int
@@ -1794,25 +1794,13 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
return NULL;
}
-/*
- * Update RX channel information based on the available frame payload
- * information. This is mainly for the 2.4 GHz band where frames can be received
- * from neighboring channels and the Beacon frames use the DSSS Parameter Set
- * element to indicate the current (transmitting) channel, but this might also
- * be needed on other bands if RX frequency does not match with the actual
- * operating channel of a BSS.
- */
-static struct ieee80211_channel *
-cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
- struct ieee80211_channel *channel,
- enum nl80211_bss_scan_width scan_width)
+int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
+ enum nl80211_band band)
{
const u8 *tmp;
- u32 freq;
int channel_number = -1;
- struct ieee80211_channel *alt_channel;
- if (channel->band == NL80211_BAND_S1GHZ) {
+ if (band == NL80211_BAND_S1GHZ) {
tmp = cfg80211_find_ie(WLAN_EID_S1G_OPERATION, ie, ielen);
if (tmp && tmp[1] >= sizeof(struct ieee80211_s1g_oper_ie)) {
struct ieee80211_s1g_oper_ie *s1gop = (void *)(tmp + 2);
@@ -1833,6 +1821,29 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
}
}
+ return channel_number;
+}
+EXPORT_SYMBOL(cfg80211_get_ies_channel_number);
+
+/*
+ * Update RX channel information based on the available frame payload
+ * information. This is mainly for the 2.4 GHz band where frames can be received
+ * from neighboring channels and the Beacon frames use the DSSS Parameter Set
+ * element to indicate the current (transmitting) channel, but this might also
+ * be needed on other bands if RX frequency does not match with the actual
+ * operating channel of a BSS.
+ */
+static struct ieee80211_channel *
+cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
+ struct ieee80211_channel *channel,
+ enum nl80211_bss_scan_width scan_width)
+{
+ u32 freq;
+ int channel_number;
+ struct ieee80211_channel *alt_channel;
+
+ channel_number = cfg80211_get_ies_channel_number(ie, ielen, channel->band);
+
if (channel_number < 0) {
/* No channel information in frame payload */
return channel;
@@ -2075,12 +2086,12 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
if (!non_tx_data)
return;
- if (!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
+ if (!cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
return;
if (!wiphy->support_mbssid)
return;
if (wiphy->support_only_he_mbssid &&
- !cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
+ !cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
return;
new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp);
@@ -2447,10 +2458,10 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
len, gfp);
if (!res || !wiphy->support_mbssid ||
- !cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
+ !cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
return res;
if (wiphy->support_only_he_mbssid &&
- !cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
+ !cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
return res;
non_tx_data.tx_bss = res;
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 19b78d472283..ad6c16a06bcb 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -167,6 +167,19 @@
__entry->center_freq1, __entry->freq1_offset, \
__entry->center_freq2
+#define FILS_AAD_ASSIGN(fa) \
+ do { \
+ if (fa) { \
+ ether_addr_copy(__entry->macaddr, fa->macaddr); \
+ __entry->kek_len = fa->kek_len; \
+ } else { \
+ eth_zero_addr(__entry->macaddr); \
+ __entry->kek_len = 0; \
+ } \
+ } while (0)
+#define FILS_AAD_PR_FMT \
+ "macaddr: %pM, kek_len: %d"
+
#define SINFO_ENTRY __field(int, generation) \
__field(u32, connected_time) \
__field(u32, inactive_time) \
@@ -2614,6 +2627,24 @@ DEFINE_EVENT(wiphy_wdev_cookie_evt, rdev_abort_pmsr,
TP_ARGS(wiphy, wdev, cookie)
);
+TRACE_EVENT(rdev_set_fils_aad,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_fils_aad *fils_aad),
+ TP_ARGS(wiphy, netdev, fils_aad),
+ TP_STRUCT__entry(WIPHY_ENTRY
+ NETDEV_ENTRY
+ __array(u8, macaddr, ETH_ALEN)
+ __field(u8, kek_len)
+ ),
+ TP_fast_assign(WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ FILS_AAD_ASSIGN(fils_aad);
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " FILS_AAD_PR_FMT,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->macaddr,
+ __entry->kek_len)
+);
+
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/
diff --git a/net/wireless/util.c b/net/wireless/util.c
index a1a99a574984..5ff1f8726faf 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -80,6 +80,7 @@ u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
return 0; /* not supported */
switch (band) {
case NL80211_BAND_2GHZ:
+ case NL80211_BAND_LC:
if (chan == 14)
return MHZ_TO_KHZ(2484);
else if (chan < 14)
@@ -209,6 +210,7 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
WARN_ON(want);
break;
case NL80211_BAND_2GHZ:
+ case NL80211_BAND_LC:
want = 7;
for (i = 0; i < sband->n_bitrates; i++) {
switch (sband->bitrates[i].bitrate) {