summaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c324
1 files changed, 260 insertions, 64 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f67ddf2cebcb..775d0c4d86c3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -399,6 +399,18 @@ nl80211_unsol_bcast_probe_resp_policy[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX +
.len = IEEE80211_MAX_DATA_LEN }
};
+static const struct nla_policy
+sar_specs_policy[NL80211_SAR_ATTR_SPECS_MAX + 1] = {
+ [NL80211_SAR_ATTR_SPECS_POWER] = { .type = NLA_S32 },
+ [NL80211_SAR_ATTR_SPECS_RANGE_INDEX] = {.type = NLA_U32 },
+};
+
+static const struct nla_policy
+sar_policy[NL80211_SAR_ATTR_MAX + 1] = {
+ [NL80211_SAR_ATTR_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_SAR_TYPE),
+ [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy),
+};
+
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 },
@@ -715,6 +727,11 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
[NL80211_ATTR_S1G_CAPABILITY_MASK] =
NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
+ [NL80211_ATTR_SAE_PWE] =
+ NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK,
+ NL80211_SAE_PWE_BOTH),
+ [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
+ [NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
};
/* policy for the key attributes */
@@ -1882,7 +1899,6 @@ static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
goto nla_put_failure;
}
- CMD(set_wds_peer, SET_WDS_PEER);
if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
CMD(tdls_mgmt, TDLS_MGMT);
CMD(tdls_oper, TDLS_OPER);
@@ -2092,6 +2108,56 @@ fail:
return -ENOBUFS;
}
+static int
+nl80211_put_sar_specs(struct cfg80211_registered_device *rdev,
+ struct sk_buff *msg)
+{
+ struct nlattr *sar_capa, *specs, *sub_freq_range;
+ u8 num_freq_ranges;
+ int i;
+
+ if (!rdev->wiphy.sar_capa)
+ return 0;
+
+ num_freq_ranges = rdev->wiphy.sar_capa->num_freq_ranges;
+
+ sar_capa = nla_nest_start(msg, NL80211_ATTR_SAR_SPEC);
+ if (!sar_capa)
+ return -ENOSPC;
+
+ if (nla_put_u32(msg, NL80211_SAR_ATTR_TYPE, rdev->wiphy.sar_capa->type))
+ goto fail;
+
+ specs = nla_nest_start(msg, NL80211_SAR_ATTR_SPECS);
+ if (!specs)
+ goto fail;
+
+ /* report supported freq_ranges */
+ for (i = 0; i < num_freq_ranges; i++) {
+ sub_freq_range = nla_nest_start(msg, i + 1);
+ if (!sub_freq_range)
+ goto fail;
+
+ if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_START_FREQ,
+ rdev->wiphy.sar_capa->freq_ranges[i].start_freq))
+ goto fail;
+
+ if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_END_FREQ,
+ rdev->wiphy.sar_capa->freq_ranges[i].end_freq))
+ goto fail;
+
+ nla_nest_end(msg, sub_freq_range);
+ }
+
+ nla_nest_end(msg, specs);
+ nla_nest_end(msg, sar_capa);
+
+ return 0;
+fail:
+ nla_nest_cancel(msg, sar_capa);
+ return -ENOBUFS;
+}
+
struct nl80211_dump_wiphy_state {
s64 filter_wiphy;
long start;
@@ -2341,6 +2407,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
CMD(update_ft_ies, UPDATE_FT_IES);
+ if (rdev->wiphy.sar_capa)
+ CMD(set_sar_specs, SET_SAR_SPECS);
}
#undef CMD
@@ -2666,6 +2734,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
if (nl80211_put_tid_config_support(rdev, msg))
goto nla_put_failure;
+ state->split_start++;
+ break;
+ case 16:
+ if (nl80211_put_sar_specs(rdev, msg))
+ goto nla_put_failure;
/* done */
state->split_start = 0;
@@ -2860,8 +2933,8 @@ static int parse_txq_params(struct nlattr *tb[],
static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
{
/*
- * You can only set the channel explicitly for WDS interfaces,
- * all others have their channel managed via their respective
+ * You can only set the channel explicitly for some interfaces,
+ * most have their channel managed via their respective
* "establish a connection" command (connect, join, ...)
*
* For AP/GO and mesh mode, the channel can be set with the
@@ -3066,29 +3139,6 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
return __nl80211_set_channel(rdev, netdev, info);
}
-static int nl80211_set_wds_peer(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;
- const u8 *bssid;
-
- if (!info->attrs[NL80211_ATTR_MAC])
- return -EINVAL;
-
- if (netif_running(dev))
- return -EBUSY;
-
- if (!rdev->ops->set_wds_peer)
- return -EOPNOTSUPP;
-
- if (wdev->iftype != NL80211_IFTYPE_WDS)
- return -EOPNOTSUPP;
-
- bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
- return rdev_set_wds_peer(rdev, dev, bssid);
-}
-
static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
@@ -4260,9 +4310,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
- if (key.idx < 0)
- return -EINVAL;
-
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
@@ -4278,6 +4325,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
key.type != NL80211_KEYTYPE_GROUP)
return -EINVAL;
+ if (!cfg80211_valid_key_idx(rdev, key.idx,
+ key.type == NL80211_KEYTYPE_PAIRWISE))
+ return -EINVAL;
+
if (!rdev->ops->del_key)
return -EOPNOTSUPP;
@@ -4595,7 +4646,8 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
struct nlattr *attrs[],
enum nl80211_attrs attr,
struct cfg80211_bitrate_mask *mask,
- struct net_device *dev)
+ struct net_device *dev,
+ bool default_all_enabled)
{
struct nlattr *tb[NL80211_TXRATE_MAX + 1];
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -4610,6 +4662,9 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
for (i = 0; i < NUM_NL80211_BANDS; i++) {
const struct ieee80211_sta_he_cap *he_cap;
+ if (!default_all_enabled)
+ break;
+
sband = rdev->wiphy.bands[i];
if (!sband)
@@ -4677,6 +4732,7 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
mask->control[band].ht_mcs))
return -EINVAL;
}
+
if (tb[NL80211_TXRATE_VHT]) {
if (!vht_set_mcs_mask(
sband,
@@ -4684,6 +4740,7 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
mask->control[band].vht_mcs))
return -EINVAL;
}
+
if (tb[NL80211_TXRATE_GI]) {
mask->control[band].gi =
nla_get_u8(tb[NL80211_TXRATE_GI]);
@@ -4695,6 +4752,7 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
nla_data(tb[NL80211_TXRATE_HE]),
mask->control[band].he_mcs))
return -EINVAL;
+
if (tb[NL80211_TXRATE_HE_GI])
mask->control[band].he_gi =
nla_get_u8(tb[NL80211_TXRATE_HE_GI]);
@@ -4736,7 +4794,7 @@ static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
enum nl80211_band band,
struct cfg80211_bitrate_mask *beacon_rate)
{
- u32 count_ht, count_vht, i;
+ u32 count_ht, count_vht, count_he, i;
u32 rate = beacon_rate->control[band].legacy;
/* Allow only one rate */
@@ -4769,7 +4827,21 @@ static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
return -EINVAL;
}
- if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
+ count_he = 0;
+ for (i = 0; i < NL80211_HE_NSS_MAX; i++) {
+ if (hweight16(beacon_rate->control[band].he_mcs[i]) > 1) {
+ return -EINVAL;
+ } else if (beacon_rate->control[band].he_mcs[i]) {
+ count_he++;
+ if (count_he > 1)
+ return -EINVAL;
+ }
+ if (count_he && rate)
+ return -EINVAL;
+ }
+
+ if ((count_ht && count_vht && count_he) ||
+ (!rate && !count_ht && !count_vht && !count_he))
return -EINVAL;
if (rate &&
@@ -4784,6 +4856,10 @@ static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_BEACON_RATE_VHT))
return -EINVAL;
+ if (count_he &&
+ !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_BEACON_RATE_HE))
+ return -EINVAL;
return 0;
}
@@ -5013,6 +5089,8 @@ static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
params->vht_required = true;
if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
params->he_required = true;
+ if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_SAE_H2E)
+ params->sae_h2e_required = true;
}
}
@@ -5244,7 +5322,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
NL80211_ATTR_TX_RATES,
&params.beacon_rate,
- dev);
+ dev, false);
if (err)
return err;
@@ -8237,12 +8315,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
}
if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
- if (!wiphy_ext_feature_isset(wiphy,
- NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
- err = -EOPNOTSUPP;
- goto out_free;
- }
-
request->duration =
nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
request->duration_mandatory =
@@ -9732,6 +9804,12 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
nla_len(info->attrs[NL80211_ATTR_SAE_PASSWORD]);
}
+ if (info->attrs[NL80211_ATTR_SAE_PWE])
+ settings->sae_pwe =
+ nla_get_u8(info->attrs[NL80211_ATTR_SAE_PWE]);
+ else
+ settings->sae_pwe = NL80211_SAE_PWE_UNSPECIFIED;
+
return 0;
}
@@ -11088,7 +11166,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
NL80211_ATTR_TX_RATES, &mask,
- dev);
+ dev, true);
if (err)
return err;
@@ -11165,6 +11243,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
case NL80211_IFTYPE_P2P_DEVICE:
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
+ break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_P2P_CLIENT:
@@ -11697,7 +11776,7 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
NL80211_ATTR_TX_RATES,
&setup.beacon_rate,
- dev);
+ dev, false);
if (err)
return err;
@@ -14477,7 +14556,8 @@ static int parse_tid_conf(struct cfg80211_registered_device *rdev,
if (tid_conf->txrate_type != NL80211_TX_RATE_AUTOMATIC) {
attr = NL80211_TID_CONFIG_ATTR_TX_RATE;
err = nl80211_parse_tx_bitrate_mask(info, attrs, attr,
- &tid_conf->txrate_mask, dev);
+ &tid_conf->txrate_mask, dev,
+ true);
if (err)
return err;
@@ -14658,6 +14738,111 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
}
}
+static int nl80211_set_sar_sub_specs(struct cfg80211_registered_device *rdev,
+ struct cfg80211_sar_specs *sar_specs,
+ struct nlattr *spec[], int index)
+{
+ u32 range_index, i;
+
+ if (!sar_specs || !spec)
+ return -EINVAL;
+
+ if (!spec[NL80211_SAR_ATTR_SPECS_POWER] ||
+ !spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX])
+ return -EINVAL;
+
+ range_index = nla_get_u32(spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX]);
+
+ /* check if range_index exceeds num_freq_ranges */
+ if (range_index >= rdev->wiphy.sar_capa->num_freq_ranges)
+ return -EINVAL;
+
+ /* check if range_index duplicates */
+ for (i = 0; i < index; i++) {
+ if (sar_specs->sub_specs[i].freq_range_index == range_index)
+ return -EINVAL;
+ }
+
+ sar_specs->sub_specs[index].power =
+ nla_get_s32(spec[NL80211_SAR_ATTR_SPECS_POWER]);
+
+ sar_specs->sub_specs[index].freq_range_index = range_index;
+
+ return 0;
+}
+
+static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct nlattr *spec[NL80211_SAR_ATTR_SPECS_MAX + 1];
+ struct nlattr *tb[NL80211_SAR_ATTR_MAX + 1];
+ struct cfg80211_sar_specs *sar_spec;
+ enum nl80211_sar_type type;
+ struct nlattr *spec_list;
+ u32 specs;
+ int rem, err;
+
+ if (!rdev->wiphy.sar_capa || !rdev->ops->set_sar_specs)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_SAR_SPEC])
+ return -EINVAL;
+
+ nla_parse_nested(tb, NL80211_SAR_ATTR_MAX,
+ info->attrs[NL80211_ATTR_SAR_SPEC],
+ NULL, NULL);
+
+ if (!tb[NL80211_SAR_ATTR_TYPE] || !tb[NL80211_SAR_ATTR_SPECS])
+ return -EINVAL;
+
+ type = nla_get_u32(tb[NL80211_SAR_ATTR_TYPE]);
+ if (type != rdev->wiphy.sar_capa->type)
+ return -EINVAL;
+
+ specs = 0;
+ nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem)
+ specs++;
+
+ 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);
+ if (!sar_spec)
+ return -ENOMEM;
+
+ sar_spec->type = type;
+ specs = 0;
+ nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) {
+ nla_parse_nested(spec, NL80211_SAR_ATTR_SPECS_MAX,
+ spec_list, NULL, NULL);
+
+ switch (type) {
+ case NL80211_SAR_TYPE_POWER:
+ if (nl80211_set_sar_sub_specs(rdev, sar_spec,
+ spec, specs)) {
+ err = -EINVAL;
+ goto error;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ goto error;
+ }
+ specs++;
+ }
+
+ sar_spec->num_sub_specs = specs;
+
+ rdev->cur_cmd_info = info;
+ err = rdev_set_sar_specs(rdev, sar_spec);
+ rdev->cur_cmd_info = NULL;
+error:
+ kfree(sar_spec);
+ return err;
+}
+
static const struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -15140,14 +15325,6 @@ static const struct genl_small_ops nl80211_small_ops[] = {
NL80211_FLAG_NEED_RTNL,
},
{
- .cmd = NL80211_CMD_SET_WDS_PEER,
- .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .doit = nl80211_set_wds_peer,
- .flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
- },
- {
.cmd = NL80211_CMD_JOIN_MESH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_join_mesh,
@@ -15519,6 +15696,14 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_SET_SAR_SPECS,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .doit = nl80211_set_sar_specs,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
@@ -15854,7 +16039,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
const u8 *buf, size_t len,
enum nl80211_commands cmd, gfp_t gfp,
int uapsd_queues, const u8 *req_ies,
- size_t req_ies_len)
+ size_t req_ies_len, bool reconnect)
{
struct sk_buff *msg;
void *hdr;
@@ -15876,6 +16061,9 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies)))
goto nla_put_failure;
+ if (reconnect && nla_put_flag(msg, NL80211_ATTR_RECONNECT_REQUESTED))
+ goto nla_put_failure;
+
if (uapsd_queues >= 0) {
struct nlattr *nla_wmm =
nla_nest_start_noflag(msg, NL80211_ATTR_STA_WME);
@@ -15904,7 +16092,8 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
size_t len, gfp_t gfp)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0);
+ NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0,
+ false);
}
void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
@@ -15914,23 +16103,25 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_ASSOCIATE, gfp, uapsd_queues,
- req_ies, req_ies_len);
+ req_ies, req_ies_len, false);
}
void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf,
- size_t len, gfp_t gfp)
+ size_t len, bool reconnect, gfp_t gfp)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0);
+ NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0,
+ reconnect);
}
void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf,
- size_t len, gfp_t gfp)
+ size_t len, bool reconnect, gfp_t gfp)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0);
+ NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0,
+ reconnect);
}
void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
@@ -15961,7 +16152,7 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1,
- NULL, 0);
+ NULL, 0, false);
}
EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
@@ -17062,7 +17253,7 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef,
gfp_t gfp,
enum nl80211_commands notif,
- u8 count)
+ u8 count, bool quiet)
{
struct sk_buff *msg;
void *hdr;
@@ -17083,9 +17274,13 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
if (nl80211_send_chandef(msg, chandef))
goto nla_put_failure;
- if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) &&
- (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count)))
+ if (notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) {
+ if (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count))
goto nla_put_failure;
+ if (quiet &&
+ nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX))
+ goto nla_put_failure;
+ }
genlmsg_end(msg, hdr);
@@ -17118,13 +17313,13 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
cfg80211_sched_dfs_chan_update(rdev);
nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
- NL80211_CMD_CH_SWITCH_NOTIFY, 0);
+ NL80211_CMD_CH_SWITCH_NOTIFY, 0, false);
}
EXPORT_SYMBOL(cfg80211_ch_switch_notify);
void cfg80211_ch_switch_started_notify(struct net_device *dev,
struct cfg80211_chan_def *chandef,
- u8 count)
+ u8 count, bool quiet)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
@@ -17133,7 +17328,8 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev,
trace_cfg80211_ch_switch_started_notify(dev, chandef);
nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
- NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count);
+ NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
+ count, quiet);
}
EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);