blob: 6ee3bc48d776180fd06ea7ce4341d1d87f70fff4 [file] [log] [blame]
Thomas Gleixner457c8992019-05-19 13:08:55 +01001// SPDX-License-Identifier: GPL-2.0-only
Johannes Berg55682962007-09-20 13:09:35 -04002/*
3 * This is the new netlink-based wireless configuration interface.
4 *
Jouni Malinen026331c2010-02-15 12:53:10 +02005 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
Johannes Berg2740f0c2014-09-03 15:24:58 +03006 * Copyright 2013-2014 Intel Mobile Communications GmbH
Johannes Berg66cd7942017-02-07 22:40:44 +02007 * Copyright 2015-2017 Intel Deutschland GmbH
Shaul Triebitz7e8d6f12020-01-31 13:12:54 +02008 * Copyright (C) 2018-2020 Intel Corporation
Johannes Berg55682962007-09-20 13:09:35 -04009 */
10
11#include <linux/if.h>
12#include <linux/module.h>
13#include <linux/err.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Johannes Berg55682962007-09-20 13:09:35 -040015#include <linux/list.h>
16#include <linux/if_ether.h>
17#include <linux/ieee80211.h>
18#include <linux/nl80211.h>
19#include <linux/rtnetlink.h>
20#include <linux/netlink.h>
Dan Williams259d8c12018-01-29 17:03:15 -080021#include <linux/nospec.h>
Johannes Berg2a519312009-02-10 21:25:55 +010022#include <linux/etherdevice.h>
Johannes Berge3ae39e2020-02-24 09:38:15 +010023#include <linux/if_vlan.h>
Johannes Berg463d0182009-07-14 00:33:35 +020024#include <net/net_namespace.h>
Johannes Berg55682962007-09-20 13:09:35 -040025#include <net/genetlink.h>
26#include <net/cfg80211.h>
Johannes Berg463d0182009-07-14 00:33:35 +020027#include <net/sock.h>
Johannes Berg2a0e0472013-01-23 22:57:40 +010028#include <net/inet_connection_sock.h>
Johannes Berg55682962007-09-20 13:09:35 -040029#include "core.h"
30#include "nl80211.h"
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070031#include "reg.h"
Hila Gonene35e4d22012-06-27 17:19:42 +030032#include "rdev-ops.h"
Johannes Berg55682962007-09-20 13:09:35 -040033
Jouni Malinen5fb628e2011-08-10 23:54:35 +030034static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
35 struct genl_info *info,
36 struct cfg80211_crypto_settings *settings,
37 int cipher_limit);
38
Johannes Berg55682962007-09-20 13:09:35 -040039/* the netlink family */
Johannes Berg489111e2016-10-24 14:40:03 +020040static struct genl_family nl80211_fam;
Johannes Berg55682962007-09-20 13:09:35 -040041
Johannes Berg2a94fe42013-11-19 15:19:39 +010042/* multicast groups */
43enum nl80211_multicast_groups {
44 NL80211_MCGRP_CONFIG,
45 NL80211_MCGRP_SCAN,
46 NL80211_MCGRP_REGULATORY,
47 NL80211_MCGRP_MLME,
Johannes Berg567ffc32013-12-18 14:43:31 +010048 NL80211_MCGRP_VENDOR,
Ayala Beker50bcd312016-09-20 17:31:17 +030049 NL80211_MCGRP_NAN,
Johannes Berg2a94fe42013-11-19 15:19:39 +010050 NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
51};
52
53static const struct genl_multicast_group nl80211_mcgrps[] = {
Johannes Berg71b836e2014-12-23 17:17:38 +010054 [NL80211_MCGRP_CONFIG] = { .name = NL80211_MULTICAST_GROUP_CONFIG },
55 [NL80211_MCGRP_SCAN] = { .name = NL80211_MULTICAST_GROUP_SCAN },
56 [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG },
57 [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME },
58 [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR },
Ayala Beker50bcd312016-09-20 17:31:17 +030059 [NL80211_MCGRP_NAN] = { .name = NL80211_MULTICAST_GROUP_NAN },
Johannes Berg2a94fe42013-11-19 15:19:39 +010060#ifdef CONFIG_NL80211_TESTMODE
Johannes Berg71b836e2014-12-23 17:17:38 +010061 [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }
Johannes Berg2a94fe42013-11-19 15:19:39 +010062#endif
63};
64
Johannes Berg89a54e42012-06-15 14:33:17 +020065/* returns ERR_PTR values */
66static struct wireless_dev *
67__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
Johannes Berg55682962007-09-20 13:09:35 -040068{
Johannes Berg89a54e42012-06-15 14:33:17 +020069 struct cfg80211_registered_device *rdev;
70 struct wireless_dev *result = NULL;
71 bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
72 bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
73 u64 wdev_id;
74 int wiphy_idx = -1;
75 int ifidx = -1;
Johannes Berg55682962007-09-20 13:09:35 -040076
Johannes Berg5fe231e2013-05-08 21:45:15 +020077 ASSERT_RTNL();
Johannes Berg55682962007-09-20 13:09:35 -040078
Johannes Berg89a54e42012-06-15 14:33:17 +020079 if (!have_ifidx && !have_wdev_id)
80 return ERR_PTR(-EINVAL);
Johannes Berg55682962007-09-20 13:09:35 -040081
Johannes Berg89a54e42012-06-15 14:33:17 +020082 if (have_ifidx)
83 ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
84 if (have_wdev_id) {
85 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
86 wiphy_idx = wdev_id >> 32;
Johannes Berg55682962007-09-20 13:09:35 -040087 }
88
Johannes Berg89a54e42012-06-15 14:33:17 +020089 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
90 struct wireless_dev *wdev;
91
92 if (wiphy_net(&rdev->wiphy) != netns)
93 continue;
94
95 if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
96 continue;
97
Johannes Berg53873f12016-05-03 16:52:04 +030098 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Berg89a54e42012-06-15 14:33:17 +020099 if (have_ifidx && wdev->netdev &&
100 wdev->netdev->ifindex == ifidx) {
101 result = wdev;
102 break;
103 }
104 if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
105 result = wdev;
106 break;
107 }
108 }
Johannes Berg89a54e42012-06-15 14:33:17 +0200109
110 if (result)
111 break;
112 }
113
114 if (result)
115 return result;
116 return ERR_PTR(-ENODEV);
Johannes Berg55682962007-09-20 13:09:35 -0400117}
118
Johannes Berga9455402012-06-15 13:32:49 +0200119static struct cfg80211_registered_device *
Johannes Berg878d9ec2012-06-15 14:18:32 +0200120__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
Johannes Berga9455402012-06-15 13:32:49 +0200121{
Johannes Berg7fee47782012-06-15 14:09:58 +0200122 struct cfg80211_registered_device *rdev = NULL, *tmp;
123 struct net_device *netdev;
Johannes Berga9455402012-06-15 13:32:49 +0200124
Johannes Berg5fe231e2013-05-08 21:45:15 +0200125 ASSERT_RTNL();
Johannes Berga9455402012-06-15 13:32:49 +0200126
Johannes Berg878d9ec2012-06-15 14:18:32 +0200127 if (!attrs[NL80211_ATTR_WIPHY] &&
Johannes Berg89a54e42012-06-15 14:33:17 +0200128 !attrs[NL80211_ATTR_IFINDEX] &&
129 !attrs[NL80211_ATTR_WDEV])
Johannes Berg7fee47782012-06-15 14:09:58 +0200130 return ERR_PTR(-EINVAL);
131
Johannes Berg878d9ec2012-06-15 14:18:32 +0200132 if (attrs[NL80211_ATTR_WIPHY])
Johannes Berg7fee47782012-06-15 14:09:58 +0200133 rdev = cfg80211_rdev_by_wiphy_idx(
Johannes Berg878d9ec2012-06-15 14:18:32 +0200134 nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
Johannes Berga9455402012-06-15 13:32:49 +0200135
Johannes Berg89a54e42012-06-15 14:33:17 +0200136 if (attrs[NL80211_ATTR_WDEV]) {
137 u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
138 struct wireless_dev *wdev;
139 bool found = false;
140
141 tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
142 if (tmp) {
143 /* make sure wdev exists */
Johannes Berg53873f12016-05-03 16:52:04 +0300144 list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
Johannes Berg89a54e42012-06-15 14:33:17 +0200145 if (wdev->identifier != (u32)wdev_id)
146 continue;
147 found = true;
148 break;
149 }
Johannes Berg89a54e42012-06-15 14:33:17 +0200150
151 if (!found)
152 tmp = NULL;
153
154 if (rdev && tmp != rdev)
155 return ERR_PTR(-EINVAL);
156 rdev = tmp;
157 }
158 }
159
Johannes Berg878d9ec2012-06-15 14:18:32 +0200160 if (attrs[NL80211_ATTR_IFINDEX]) {
161 int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -0700162
Ying Xue7f2b8562014-01-15 10:23:45 +0800163 netdev = __dev_get_by_index(netns, ifindex);
Johannes Berg7fee47782012-06-15 14:09:58 +0200164 if (netdev) {
165 if (netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800166 tmp = wiphy_to_rdev(
167 netdev->ieee80211_ptr->wiphy);
Johannes Berg7fee47782012-06-15 14:09:58 +0200168 else
169 tmp = NULL;
170
Johannes Berg7fee47782012-06-15 14:09:58 +0200171 /* not wireless device -- return error */
172 if (!tmp)
173 return ERR_PTR(-EINVAL);
174
175 /* mismatch -- return error */
176 if (rdev && tmp != rdev)
177 return ERR_PTR(-EINVAL);
178
179 rdev = tmp;
Johannes Berga9455402012-06-15 13:32:49 +0200180 }
Johannes Berga9455402012-06-15 13:32:49 +0200181 }
182
Johannes Berg4f7eff12012-06-15 14:14:22 +0200183 if (!rdev)
184 return ERR_PTR(-ENODEV);
Johannes Berga9455402012-06-15 13:32:49 +0200185
Johannes Berg4f7eff12012-06-15 14:14:22 +0200186 if (netns != wiphy_net(&rdev->wiphy))
187 return ERR_PTR(-ENODEV);
188
189 return rdev;
Johannes Berga9455402012-06-15 13:32:49 +0200190}
191
192/*
193 * This function returns a pointer to the driver
194 * that the genl_info item that is passed refers to.
Johannes Berga9455402012-06-15 13:32:49 +0200195 *
196 * The result of this can be a PTR_ERR and hence must
197 * be checked with IS_ERR() for errors.
198 */
199static struct cfg80211_registered_device *
Johannes Berg4f7eff12012-06-15 14:14:22 +0200200cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
Johannes Berga9455402012-06-15 13:32:49 +0200201{
Johannes Berg5fe231e2013-05-08 21:45:15 +0200202 return __cfg80211_rdev_from_attrs(netns, info->attrs);
Johannes Berga9455402012-06-15 13:32:49 +0200203}
204
Johannes Bergf88eb7c2019-09-20 21:54:17 +0200205static int validate_beacon_head(const struct nlattr *attr,
206 struct netlink_ext_ack *extack)
207{
208 const u8 *data = nla_data(attr);
209 unsigned int len = nla_len(attr);
210 const struct element *elem;
211 const struct ieee80211_mgmt *mgmt = (void *)data;
212 unsigned int fixedlen = offsetof(struct ieee80211_mgmt,
213 u.beacon.variable);
214
215 if (len < fixedlen)
216 goto err;
217
218 if (ieee80211_hdrlen(mgmt->frame_control) !=
219 offsetof(struct ieee80211_mgmt, u.beacon))
220 goto err;
221
222 data += fixedlen;
223 len -= fixedlen;
224
225 for_each_element(elem, data, len) {
226 /* nothing */
227 }
228
229 if (for_each_element_completed(elem, data, len))
230 return 0;
231
232err:
233 NL_SET_ERR_MSG_ATTR(extack, attr, "malformed beacon head");
234 return -EINVAL;
235}
236
Johannes Berg3d7af872018-10-02 10:00:08 +0200237static int validate_ie_attr(const struct nlattr *attr,
238 struct netlink_ext_ack *extack)
239{
Johannes Berg9f308612019-02-07 23:39:19 +0100240 const u8 *data = nla_data(attr);
241 unsigned int len = nla_len(attr);
Jouni Malinen7388afe2019-02-11 16:29:04 +0200242 const struct element *elem;
Johannes Berg3d7af872018-10-02 10:00:08 +0200243
Johannes Berg9f308612019-02-07 23:39:19 +0100244 for_each_element(elem, data, len) {
245 /* nothing */
Johannes Berg3d7af872018-10-02 10:00:08 +0200246 }
247
Johannes Berg9f308612019-02-07 23:39:19 +0100248 if (for_each_element_completed(elem, data, len))
249 return 0;
250
Johannes Berg3d7af872018-10-02 10:00:08 +0200251 NL_SET_ERR_MSG_ATTR(extack, attr, "malformed information elements");
252 return -EINVAL;
253}
254
Johannes Berg55682962007-09-20 13:09:35 -0400255/* policy for the attributes */
Johannes Bergd15da2a2020-04-30 22:13:07 +0200256static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR];
257
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -0700258static const struct nla_policy
259nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
260 [NL80211_FTM_RESP_ATTR_ENABLED] = { .type = NLA_FLAG, },
261 [NL80211_FTM_RESP_ATTR_LCI] = { .type = NLA_BINARY,
262 .len = U8_MAX },
263 [NL80211_FTM_RESP_ATTR_CIVICLOC] = { .type = NLA_BINARY,
264 .len = U8_MAX },
265};
266
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200267static const struct nla_policy
268nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = {
269 [NL80211_PMSR_FTM_REQ_ATTR_ASAP] = { .type = NLA_FLAG },
270 [NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] = { .type = NLA_U32 },
271 [NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP] =
272 NLA_POLICY_MAX(NLA_U8, 15),
273 [NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 },
274 [NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] =
275 NLA_POLICY_MAX(NLA_U8, 15),
276 [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] =
Aviya Erenfeldea187092019-02-06 13:17:08 +0200277 NLA_POLICY_MAX(NLA_U8, 31),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200278 [NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES] = { .type = NLA_U8 },
279 [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI] = { .type = NLA_FLAG },
280 [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC] = { .type = NLA_FLAG },
Avraham Sternefb55202020-01-31 13:12:38 +0200281 [NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED] = { .type = NLA_FLAG },
282 [NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED] = { .type = NLA_FLAG },
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200283};
284
285static const struct nla_policy
286nl80211_pmsr_req_data_policy[NL80211_PMSR_TYPE_MAX + 1] = {
287 [NL80211_PMSR_TYPE_FTM] =
Johannes Berg23323282019-01-25 10:08:28 +0100288 NLA_POLICY_NESTED(nl80211_pmsr_ftm_req_attr_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200289};
290
291static const struct nla_policy
292nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = {
293 [NL80211_PMSR_REQ_ATTR_DATA] =
Johannes Berg23323282019-01-25 10:08:28 +0100294 NLA_POLICY_NESTED(nl80211_pmsr_req_data_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200295 [NL80211_PMSR_REQ_ATTR_GET_AP_TSF] = { .type = NLA_FLAG },
296};
297
298static const struct nla_policy
299nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
300 [NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR,
Johannes Bergd15da2a2020-04-30 22:13:07 +0200301 [NL80211_PMSR_PEER_ATTR_CHAN] = NLA_POLICY_NESTED(nl80211_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200302 [NL80211_PMSR_PEER_ATTR_REQ] =
Johannes Berg23323282019-01-25 10:08:28 +0100303 NLA_POLICY_NESTED(nl80211_pmsr_req_attr_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200304 [NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_REJECT },
305};
306
307static const struct nla_policy
308nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
309 [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_REJECT },
310 [NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_REJECT },
311 [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT },
312 [NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_REJECT },
313 [NL80211_PMSR_ATTR_PEERS] =
Johannes Berg23323282019-01-25 10:08:28 +0100314 NLA_POLICY_NESTED_ARRAY(nl80211_psmr_peer_attr_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200315};
316
John Crispin796e90f2019-07-30 18:37:00 +0200317static const struct nla_policy
318he_obss_pd_policy[NL80211_HE_OBSS_PD_ATTR_MAX + 1] = {
319 [NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET] =
320 NLA_POLICY_RANGE(NLA_U8, 1, 20),
321 [NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET] =
322 NLA_POLICY_RANGE(NLA_U8, 1, 20),
323};
324
John Crispin5c5e52d2019-12-17 15:19:18 +0100325static const struct nla_policy
326he_bss_color_policy[NL80211_HE_BSS_COLOR_ATTR_MAX + 1] = {
327 [NL80211_HE_BSS_COLOR_ATTR_COLOR] = NLA_POLICY_RANGE(NLA_U8, 1, 63),
328 [NL80211_HE_BSS_COLOR_ATTR_DISABLED] = { .type = NLA_FLAG },
329 [NL80211_HE_BSS_COLOR_ATTR_PARTIAL] = { .type = NLA_FLAG },
330};
331
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +0530332static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
333 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
334 .len = NL80211_MAX_SUPP_RATES },
335 [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
336 .len = NL80211_MAX_SUPP_HT_RATES },
337 [NL80211_TXRATE_VHT] = NLA_POLICY_EXACT_LEN_WARN(sizeof(struct nl80211_txrate_vht)),
338 [NL80211_TXRATE_GI] = { .type = NLA_U8 },
339};
340
Tamizh chelvam77f576d2020-01-20 13:21:22 +0530341static const struct nla_policy
342nl80211_tid_config_attr_policy[NL80211_TID_CONFIG_ATTR_MAX + 1] = {
Johannes Berg3710a8a2020-02-24 11:34:25 +0100343 [NL80211_TID_CONFIG_ATTR_VIF_SUPP] = { .type = NLA_U64 },
344 [NL80211_TID_CONFIG_ATTR_PEER_SUPP] = { .type = NLA_U64 },
Tamizh chelvam77f576d2020-01-20 13:21:22 +0530345 [NL80211_TID_CONFIG_ATTR_OVERRIDE] = { .type = NLA_FLAG },
Johannes Berg3710a8a2020-02-24 11:34:25 +0100346 [NL80211_TID_CONFIG_ATTR_TIDS] = NLA_POLICY_RANGE(NLA_U16, 1, 0xff),
Tamizh chelvam77f576d2020-01-20 13:21:22 +0530347 [NL80211_TID_CONFIG_ATTR_NOACK] =
348 NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
Tamizh chelvam6a21d162020-01-20 13:21:23 +0530349 [NL80211_TID_CONFIG_ATTR_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
350 [NL80211_TID_CONFIG_ATTR_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
Tamizh chelvamade274b2020-01-20 13:21:24 +0530351 [NL80211_TID_CONFIG_ATTR_AMPDU_CTRL] =
352 NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
Tamizh chelvam04f7d142020-01-20 13:21:25 +0530353 [NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL] =
354 NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
Sergey Matyukevich33462e62020-04-24 14:29:03 +0300355 [NL80211_TID_CONFIG_ATTR_AMSDU_CTRL] =
356 NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +0530357 [NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE] =
358 NLA_POLICY_MAX(NLA_U8, NL80211_TX_RATE_FIXED),
359 [NL80211_TID_CONFIG_ATTR_TX_RATE] =
360 NLA_POLICY_NESTED(nl80211_txattr_policy),
Tamizh chelvam77f576d2020-01-20 13:21:22 +0530361};
362
Johannes Bergd15da2a2020-04-30 22:13:07 +0200363static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
Johannes Berg6d4dd4e2019-07-31 10:58:20 +0200364 [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
Johannes Berg55682962007-09-20 13:09:35 -0400365 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
366 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
David S. Miller079e24e2009-05-26 21:15:00 -0700367 .len = 20-1 },
Jouni Malinen31888482008-10-30 16:59:24 +0200368 [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100369
Jouni Malinen72bdcf32008-11-26 16:15:24 +0200370 [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
Sujith094d05d2008-12-12 11:57:43 +0530371 [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300372 [NL80211_ATTR_WIPHY_EDMG_CHANNELS] = NLA_POLICY_RANGE(NLA_U8,
373 NL80211_EDMG_CHANNELS_MIN,
374 NL80211_EDMG_CHANNELS_MAX),
375 [NL80211_ATTR_WIPHY_EDMG_BW_CONFIG] = NLA_POLICY_RANGE(NLA_U8,
376 NL80211_EDMG_BW_CONFIG_MIN,
377 NL80211_EDMG_BW_CONFIG_MAX),
378
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100379 [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
380 [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
Thomas Pedersen942ba882020-04-30 10:25:51 -0700381 [NL80211_ATTR_CENTER_FREQ1_OFFSET] = NLA_POLICY_RANGE(NLA_U32, 0, 999),
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100382 [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
383
Johannes Bergab0d76f2018-10-02 10:00:07 +0200384 [NL80211_ATTR_WIPHY_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
385 [NL80211_ATTR_WIPHY_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +0200386 [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
387 [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
Lukáš Turek81077e82009-12-21 22:50:47 +0100388 [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +0200389 [NL80211_ATTR_WIPHY_DYN_ACK] = { .type = NLA_FLAG },
Johannes Berg55682962007-09-20 13:09:35 -0400390
Johannes Bergab0d76f2018-10-02 10:00:07 +0200391 [NL80211_ATTR_IFTYPE] = NLA_POLICY_MAX(NLA_U32, NL80211_IFTYPE_MAX),
Johannes Berg55682962007-09-20 13:09:35 -0400392 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
393 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
Johannes Berg41ade002007-12-19 02:03:29 +0100394
Johannes Bergc7721c02020-04-30 22:13:10 +0200395 [NL80211_ATTR_MAC] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
396 [NL80211_ATTR_PREV_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Johannes Berg41ade002007-12-19 02:03:29 +0100397
Johannes Bergb9454e82009-07-08 13:29:08 +0200398 [NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
Johannes Berg41ade002007-12-19 02:03:29 +0100399 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
400 .len = WLAN_MAX_KEY_LEN },
Jouni Malinen56be3932020-02-22 15:25:43 +0200401 [NL80211_ATTR_KEY_IDX] = NLA_POLICY_MAX(NLA_U8, 7),
Johannes Berg41ade002007-12-19 02:03:29 +0100402 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
403 [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
Jouni Malinen81962262011-11-02 23:36:31 +0200404 [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200405 [NL80211_ATTR_KEY_TYPE] =
406 NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES),
Johannes Berged1b6cc2007-12-19 02:03:32 +0100407
408 [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
409 [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
Johannes Bergf88eb7c2019-09-20 21:54:17 +0200410 [NL80211_ATTR_BEACON_HEAD] =
411 NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_beacon_head,
412 IEEE80211_MAX_DATA_LEN),
Johannes Berg3d7af872018-10-02 10:00:08 +0200413 [NL80211_ATTR_BEACON_TAIL] =
414 NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
415 IEEE80211_MAX_DATA_LEN),
Johannes Bergab0d76f2018-10-02 10:00:07 +0200416 [NL80211_ATTR_STA_AID] =
417 NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
Johannes Berg5727ef12007-12-19 02:03:34 +0100418 [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
419 [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
420 [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
421 .len = NL80211_MAX_SUPP_RATES },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200422 [NL80211_ATTR_STA_PLINK_ACTION] =
423 NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_ACTIONS - 1),
Ashok Raj Nagarajane96d1cd2019-03-29 16:18:21 +0530424 [NL80211_ATTR_STA_TX_POWER_SETTING] =
425 NLA_POLICY_RANGE(NLA_U8,
426 NL80211_TX_POWER_AUTOMATIC,
427 NL80211_TX_POWER_FIXED),
428 [NL80211_ATTR_STA_TX_POWER] = { .type = NLA_S16 },
Johannes Berg5727ef12007-12-19 02:03:34 +0100429 [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
Johannes Berg0a9542e2008-10-15 11:54:04 +0200430 [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100431 [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +0800432 .len = IEEE80211_MAX_MESH_ID_LEN },
Markus Theil1fab1b82019-10-29 10:30:03 +0100433 [NL80211_ATTR_MPATH_NEXT_HOP] = NLA_POLICY_ETH_ADDR_COMPAT,
Jouni Malinen9f1ba902008-08-07 20:07:01 +0300434
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700435 [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
436 [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
437
Jouni Malinen9f1ba902008-08-07 20:07:01 +0300438 [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
439 [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
440 [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
Jouni Malinen90c97a02008-10-30 16:59:22 +0200441 [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY,
442 .len = NL80211_MAX_SUPP_RATES },
Helmut Schaa50b12f52010-11-19 12:40:25 +0100443 [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 },
Jouni Malinen36aedc92008-08-25 11:58:58 +0300444
Javier Cardona24bdd9f2010-12-16 17:37:48 -0800445 [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
Javier Cardona15d5dda2011-04-07 15:08:28 -0700446 [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -0700447
Johannes Bergc7721c02020-04-30 22:13:10 +0200448 [NL80211_ATTR_HT_CAPABILITY] = NLA_POLICY_EXACT_LEN_WARN(NL80211_HT_CAPABILITY_LEN),
Jouni Malinen9aed3cc2009-01-13 16:03:29 +0200449
450 [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
Johannes Berg3d7af872018-10-02 10:00:08 +0200451 [NL80211_ATTR_IE] = NLA_POLICY_VALIDATE_FN(NLA_BINARY,
452 validate_ie_attr,
453 IEEE80211_MAX_DATA_LEN),
Johannes Berg2a519312009-02-10 21:25:55 +0100454 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
455 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
Jouni Malinen636a5d32009-03-19 13:39:22 +0200456
457 [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
458 .len = IEEE80211_MAX_SSID_LEN },
459 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
460 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
Johannes Berg04a773a2009-04-19 21:24:32 +0200461 [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
Jouni Malinen1965c852009-04-22 21:38:25 +0300462 [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200463 [NL80211_ATTR_USE_MFP] = NLA_POLICY_RANGE(NLA_U32,
464 NL80211_MFP_NO,
465 NL80211_MFP_OPTIONAL),
Johannes Bergeccb8e82009-05-11 21:57:56 +0300466 [NL80211_ATTR_STA_FLAGS2] = {
467 .len = sizeof(struct nl80211_sta_flag_update),
468 },
Jouni Malinen3f77316c2009-05-11 21:57:57 +0300469 [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
Johannes Bergc0692b82010-08-27 14:26:53 +0300470 [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
471 [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
Denis Kenzior64bf3d42018-03-26 12:52:43 -0500472 [NL80211_ATTR_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG },
Samuel Ortizb23aa672009-07-01 21:26:54 +0200473 [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
Sergey Matyukevichea750802020-02-13 13:16:16 +0000474 [NL80211_ATTR_STATUS_CODE] = { .type = NLA_U16 },
Samuel Ortizb23aa672009-07-01 21:26:54 +0200475 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
476 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
Johannes Berg463d0182009-07-14 00:33:35 +0200477 [NL80211_ATTR_PID] = { .type = NLA_U32 },
Felix Fietkau8b787642009-11-10 18:53:10 +0100478 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
Johannes Bergc7721c02020-04-30 22:13:10 +0200479 [NL80211_ATTR_PMKID] = NLA_POLICY_EXACT_LEN_WARN(WLAN_PMKID_LEN),
Jouni Malinen9588bbd2009-12-23 13:15:41 +0100480 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
481 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +0200482 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
Jouni Malinen026331c2010-02-15 12:53:10 +0200483 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
484 .len = IEEE80211_MAX_DATA_LEN },
485 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200486 [NL80211_ATTR_PS_STATE] = NLA_POLICY_RANGE(NLA_U32,
487 NL80211_PS_DISABLED,
488 NL80211_PS_ENABLED),
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +0200489 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
Jouni Malinend5cdfac2010-04-04 09:37:19 +0300490 [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +0200491 [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +0300492 [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
493 [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
Johannes Berg2e161f782010-08-12 15:38:38 +0200494 [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
Bruno Randolfafe0cbf2010-11-10 12:50:50 +0900495 [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 },
496 [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
Felix Fietkau885a46d2010-11-11 15:07:22 +0100497 [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
Johannes Bergf7ca38d2010-11-25 10:02:29 +0100498 [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100499 [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200500 [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200501 [NL80211_ATTR_STA_PLINK_STATE] =
502 NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_STATES - 1),
Jakub Kicinski056e9372020-03-02 21:10:57 -0800503 [NL80211_ATTR_MEASUREMENT_DURATION] = { .type = NLA_U16 },
504 [NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY] = { .type = NLA_FLAG },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200505 [NL80211_ATTR_MESH_PEER_AID] =
506 NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
Luciano Coelhobbe6ad62011-05-11 17:09:37 +0300507 [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
Johannes Berge5497d72011-07-05 16:35:40 +0200508 [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
Johannes Berg34850ab2011-07-18 18:08:35 +0200509 [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200510 [NL80211_ATTR_HIDDEN_SSID] =
511 NLA_POLICY_RANGE(NLA_U32,
512 NL80211_HIDDEN_SSID_NOT_IN_USE,
513 NL80211_HIDDEN_SSID_ZERO_CONTENTS),
Johannes Berg3d7af872018-10-02 10:00:08 +0200514 [NL80211_ATTR_IE_PROBE_RESP] =
515 NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
516 IEEE80211_MAX_DATA_LEN),
517 [NL80211_ATTR_IE_ASSOC_RESP] =
518 NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
519 IEEE80211_MAX_DATA_LEN),
Vivek Natarajanf4b34b52011-08-29 14:23:03 +0530520 [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300521 [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +0530522 [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
Arik Nemtsov109086c2011-09-28 14:12:50 +0300523 [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
524 [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
525 [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
526 [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
527 [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
Arik Nemtsov31fa97c2014-06-11 17:18:21 +0300528 [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG },
Johannes Berge247bd902011-11-04 11:18:21 +0100529 [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
Arik Nemtsov00f740e2011-11-10 11:28:56 +0200530 [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
531 .len = IEEE80211_MAX_DATA_LEN },
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -0700532 [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
Ben Greear7e7c8922011-11-18 11:31:59 -0800533 [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
534 [NL80211_ATTR_HT_CAPABILITY_MASK] = {
535 .len = NL80211_HT_CAPABILITY_LEN
536 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +0100537 [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +0530538 [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
Bala Shanmugam4486ea92012-03-07 17:27:12 +0530539 [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
Johannes Berg89a54e42012-06-15 14:33:17 +0200540 [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -0700541 [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
Johannes Bergcb9abd42020-08-05 15:47:16 +0200542
543 /* need to include at least Auth Transaction and Status Code */
544 [NL80211_ATTR_AUTH_DATA] = NLA_POLICY_MIN_LEN(4),
545
Johannes Bergc7721c02020-04-30 22:13:10 +0200546 [NL80211_ATTR_VHT_CAPABILITY] = NLA_POLICY_EXACT_LEN_WARN(NL80211_VHT_CAPABILITY_LEN),
Sam Lefflered4737712012-10-11 21:03:31 -0700547 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200548 [NL80211_ATTR_P2P_CTWINDOW] = NLA_POLICY_MAX(NLA_U8, 127),
549 [NL80211_ATTR_P2P_OPPPS] = NLA_POLICY_MAX(NLA_U8, 1),
550 [NL80211_ATTR_LOCAL_MESH_POWER_MODE] =
551 NLA_POLICY_RANGE(NLA_U32,
552 NL80211_MESH_POWER_UNKNOWN + 1,
553 NL80211_MESH_POWER_MAX),
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +0530554 [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
555 [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
Jouni Malinen9d62a982013-02-14 21:10:13 +0200556 [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
557 [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
Johannes Berg3713b4e2013-02-14 16:19:38 +0100558 [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
Johannes Bergee2aca32013-02-21 17:36:01 +0100559 [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG },
560 [NL80211_ATTR_VHT_CAPABILITY_MASK] = {
561 .len = NL80211_VHT_CAPABILITY_LEN,
562 },
Jouni Malinen355199e2013-02-27 17:14:27 +0200563 [NL80211_ATTR_MDID] = { .type = NLA_U16 },
564 [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
565 .len = IEEE80211_MAX_DATA_LEN },
Jakub Kicinski0e1a1d82020-03-02 21:10:56 -0800566 [NL80211_ATTR_CRIT_PROT_ID] = { .type = NLA_U16 },
Johannes Bergcb9abd42020-08-05 15:47:16 +0200567 [NL80211_ATTR_MAX_CRIT_PROT_DURATION] =
568 NLA_POLICY_MAX(NLA_U16, NL80211_CRIT_PROTO_MAX_DURATION),
Johannes Bergab0d76f2018-10-02 10:00:07 +0200569 [NL80211_ATTR_PEER_AID] =
570 NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +0200571 [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
572 [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
573 [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +0300574 [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_BINARY },
575 [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_BINARY },
Johannes Bergcb9abd42020-08-05 15:47:16 +0200576 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = NLA_POLICY_MIN_LEN(2),
Johannes Bergc8b82802020-08-19 08:56:43 +0200577 /*
578 * The value of the Length field of the Supported Operating
579 * Classes element is between 2 and 253.
580 */
581 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] =
582 NLA_POLICY_RANGE(NLA_BINARY, 2, 253),
Simon Wunderlich5336fa82013-10-07 18:41:05 +0200583 [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +0100584 [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
Johannes Bergad7e7182013-11-13 13:37:47 +0100585 [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
586 [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
587 [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
Johannes Bergc8b82802020-08-19 08:56:43 +0200588 [NL80211_ATTR_QOS_MAP] = NLA_POLICY_RANGE(NLA_BINARY,
589 IEEE80211_QOS_MAP_LEN_MIN,
590 IEEE80211_QOS_MAP_LEN_MAX),
Johannes Bergc7721c02020-04-30 22:13:10 +0200591 [NL80211_ATTR_MAC_HINT] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Jouni Malinen1df4a512014-01-15 00:00:47 +0200592 [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +0530593 [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
Jukka Rissanen18e5ca62014-11-13 17:25:14 +0200594 [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +0300595 [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
Assaf Kraussbab5ab72014-09-03 15:25:01 +0300596 [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200597 [NL80211_ATTR_TSID] = NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_TIDS - 1),
598 [NL80211_ATTR_USER_PRIO] =
599 NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_UPS - 1),
Johannes Berg960d01a2014-09-09 22:55:35 +0300600 [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
Eliad Peller18998c32014-09-10 14:07:34 +0300601 [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
Jakub Kicinski5cde05c2020-03-02 21:10:58 -0800602 [NL80211_ATTR_OPER_CLASS] = { .type = NLA_U8 },
Johannes Bergc7721c02020-04-30 22:13:10 +0200603 [NL80211_ATTR_MAC_MASK] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Arik Nemtsov1bdd7162014-12-15 19:26:01 +0200604 [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
Vadim Kochan4b681c82015-01-12 16:34:05 +0200605 [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
Luciano Coelho9c748932015-01-16 16:04:09 +0200606 [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
Ilan peer05050752015-03-04 00:32:06 -0500607 [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
Lior David34d50512016-01-28 10:58:25 +0200608 [NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
Arend van Spriel38de03d2016-03-02 20:37:18 +0100609 [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200610 [NL80211_ATTR_STA_SUPPORT_P2P_PS] =
611 NLA_POLICY_MAX(NLA_U8, NUM_NL80211_P2P_PS_STATUS - 1),
Aviya Erenfeldc6e6a0c2016-07-05 15:23:08 +0300612 [NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
613 .len = VHT_MUMIMO_GROUPS_DATA_LEN
614 },
Johannes Bergc7721c02020-04-30 22:13:10 +0200615 [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Johannes Bergab0d76f2018-10-02 10:00:07 +0200616 [NL80211_ATTR_NAN_MASTER_PREF] = NLA_POLICY_MIN(NLA_U8, 1),
Luca Coelho85859892017-02-08 15:00:34 +0200617 [NL80211_ATTR_BANDS] = { .type = NLA_U32 },
Ayala Bekera442b762016-09-20 17:31:15 +0300618 [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
Jouni Malinen348bd452016-10-27 00:42:03 +0300619 [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
620 .len = FILS_MAX_KEK_LEN },
Johannes Bergc7721c02020-04-30 22:13:10 +0200621 [NL80211_ATTR_FILS_NONCES] = NLA_POLICY_EXACT_LEN_WARN(2 * FILS_NONCE_LEN),
Michael Braunce0ce132016-10-10 19:12:22 +0200622 [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
Johannes Bergc7721c02020-04-30 22:13:10 +0200623 [NL80211_ATTR_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
vamsi krishnabf95ecd2017-01-13 01:12:20 +0200624 [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
625 [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
626 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
627 },
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +0200628 [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +0300629 [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
630 .len = FILS_ERP_MAX_USERNAME_LEN },
631 [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
632 .len = FILS_ERP_MAX_REALM_LEN },
633 [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
634 [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
635 .len = FILS_ERP_MAX_RRK_LEN },
Johannes Bergc7721c02020-04-30 22:13:10 +0200636 [NL80211_ATTR_FILS_CACHE_ID] = NLA_POLICY_EXACT_LEN_WARN(2),
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +0300637 [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
Johannes Bergcb9abd42020-08-05 15:47:16 +0200638 [NL80211_ATTR_PMKR0_NAME] = NLA_POLICY_EXACT_LEN(WLAN_PMK_NAME_LEN),
Arend Van Sprielca986ad2017-04-21 13:05:00 +0100639 [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
Srinivas Dasari40cbfa92018-01-25 17:13:38 +0200640 [NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +0200641
642 [NL80211_ATTR_TXQ_LIMIT] = { .type = NLA_U32 },
643 [NL80211_ATTR_TXQ_MEMORY_LIMIT] = { .type = NLA_U32 },
644 [NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
Johannes Bergc8b82802020-08-19 08:56:43 +0200645 [NL80211_ATTR_HE_CAPABILITY] =
646 NLA_POLICY_RANGE(NLA_BINARY,
647 NL80211_HE_MIN_CAPABILITY_LEN,
648 NL80211_HE_MAX_CAPABILITY_LEN),
Johannes Berg0e012b42020-04-12 00:40:30 +0200649 [NL80211_ATTR_FTM_RESPONDER] =
650 NLA_POLICY_NESTED(nl80211_ftm_responder_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200651 [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1),
652 [NL80211_ATTR_PEER_MEASUREMENTS] =
Johannes Berg23323282019-01-25 10:08:28 +0100653 NLA_POLICY_NESTED(nl80211_pmsr_attr_policy),
Toke Høiland-Jørgensen36647052018-12-18 17:02:07 -0800654 [NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
Chung-Hsien Hsu26f70442019-05-09 09:49:06 +0000655 [NL80211_ATTR_SAE_PASSWORD] = { .type = NLA_BINARY,
656 .len = SAE_PASSWORD_MAX_LEN },
John Crispina0de1ca32019-05-28 13:49:48 +0200657 [NL80211_ATTR_TWT_RESPONDER] = { .type = NLA_FLAG },
John Crispin796e90f2019-07-30 18:37:00 +0200658 [NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy),
Gurumoorthi Gnanasambandhan14f34e362019-10-31 23:46:40 +0200659 [NL80211_ATTR_VLAN_ID] = NLA_POLICY_RANGE(NLA_U16, 1, VLAN_N_VID - 2),
John Crispin5c5e52d2019-12-17 15:19:18 +0100660 [NL80211_ATTR_HE_BSS_COLOR] = NLA_POLICY_NESTED(he_bss_color_policy),
Tamizh chelvam77f576d2020-01-20 13:21:22 +0530661 [NL80211_ATTR_TID_CONFIG] =
662 NLA_POLICY_NESTED_ARRAY(nl80211_tid_config_attr_policy),
Markus Theil5631d962020-03-12 10:10:53 +0100663 [NL80211_ATTR_CONTROL_PORT_NO_PREAUTH] = { .type = NLA_FLAG },
Veerendranath Jakkam7fc82af2020-03-13 01:59:03 +0200664 [NL80211_ATTR_PMK_LIFETIME] = NLA_POLICY_MIN(NLA_U32, 1),
665 [NL80211_ATTR_PMK_REAUTH_THRESHOLD] = NLA_POLICY_RANGE(NLA_U8, 1, 100),
Johannes Berg9dba48a2020-04-17 12:40:15 +0200666 [NL80211_ATTR_RECEIVE_MULTICAST] = { .type = NLA_FLAG },
Thomas Pedersen942ba882020-04-30 10:25:51 -0700667 [NL80211_ATTR_WIPHY_FREQ_OFFSET] = NLA_POLICY_RANGE(NLA_U32, 0, 999),
Thomas Pedersen2032f3b2020-04-30 10:25:52 -0700668 [NL80211_ATTR_SCAN_FREQ_KHZ] = { .type = NLA_NESTED },
Johannes Berg81408602020-08-18 10:17:31 +0200669 [NL80211_ATTR_HE_6GHZ_CAPABILITY] =
670 NLA_POLICY_EXACT_LEN(sizeof(struct ieee80211_he_6ghz_capa)),
Johannes Berg55682962007-09-20 13:09:35 -0400671};
672
Johannes Berge31b8212010-10-05 19:39:30 +0200673/* policy for the key attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000674static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
Johannes Bergfffd0932009-07-08 14:22:54 +0200675 [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
Johannes Bergb9454e82009-07-08 13:29:08 +0200676 [NL80211_KEY_IDX] = { .type = NLA_U8 },
677 [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
Jouni Malinen81962262011-11-02 23:36:31 +0200678 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Bergb9454e82009-07-08 13:29:08 +0200679 [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
680 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200681 [NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1),
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100682 [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
Alexander Wetzel6cdd3972019-03-19 21:34:07 +0100683 [NL80211_KEY_MODE] = NLA_POLICY_RANGE(NLA_U8, 0, NL80211_KEY_SET_TX),
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100684};
685
686/* policy for the key default flags */
687static const struct nla_policy
688nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
689 [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
690 [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
Johannes Bergb9454e82009-07-08 13:29:08 +0200691};
692
Johannes Bergf83ace32016-10-17 08:04:07 +0200693#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +0200694/* policy for WoWLAN attributes */
695static const struct nla_policy
696nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
697 [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
698 [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
699 [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
700 [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
Johannes Berg77dbbb12011-07-13 10:48:55 +0200701 [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG },
702 [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG },
703 [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG },
704 [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100705 [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED },
Luciano Coelho8cd4d452014-09-17 11:55:28 +0300706 [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100707};
708
709static const struct nla_policy
710nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
711 [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
712 [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
Johannes Bergc7721c02020-04-30 22:13:10 +0200713 [NL80211_WOWLAN_TCP_DST_MAC] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Johannes Berg2a0e0472013-01-23 22:57:40 +0100714 [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
715 [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
Johannes Bergbc043582020-08-18 10:17:32 +0200716 [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = NLA_POLICY_MIN_LEN(1),
Johannes Berg2a0e0472013-01-23 22:57:40 +0100717 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
718 .len = sizeof(struct nl80211_wowlan_tcp_data_seq)
719 },
720 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = {
721 .len = sizeof(struct nl80211_wowlan_tcp_data_token)
722 },
723 [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
Johannes Bergbc043582020-08-18 10:17:32 +0200724 [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = NLA_POLICY_MIN_LEN(1),
725 [NL80211_WOWLAN_TCP_WAKE_MASK] = NLA_POLICY_MIN_LEN(1),
Johannes Bergff1b6e62011-05-04 15:37:28 +0200726};
Johannes Bergf83ace32016-10-17 08:04:07 +0200727#endif /* CONFIG_PM */
Johannes Bergff1b6e62011-05-04 15:37:28 +0200728
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -0700729/* policy for coalesce rule attributes */
730static const struct nla_policy
731nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
732 [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200733 [NL80211_ATTR_COALESCE_RULE_CONDITION] =
734 NLA_POLICY_RANGE(NLA_U32,
735 NL80211_COALESCE_CONDITION_MATCH,
736 NL80211_COALESCE_CONDITION_NO_MATCH),
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -0700737 [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
738};
739
Johannes Berge5497d72011-07-05 16:35:40 +0200740/* policy for GTK rekey offload attributes */
741static const struct nla_policy
742nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
Nathan Errera093a48d2020-05-28 21:22:38 +0200743 [NL80211_REKEY_DATA_KEK] = {
744 .type = NLA_BINARY,
745 .len = NL80211_KEK_EXT_LEN
746 },
747 [NL80211_REKEY_DATA_KCK] = {
748 .type = NLA_BINARY,
749 .len = NL80211_KCK_EXT_LEN
750 },
Johannes Bergcb9abd42020-08-05 15:47:16 +0200751 [NL80211_REKEY_DATA_REPLAY_CTR] = NLA_POLICY_EXACT_LEN(NL80211_REPLAY_CTR_LEN),
Nathan Errera093a48d2020-05-28 21:22:38 +0200752 [NL80211_REKEY_DATA_AKM] = { .type = NLA_U32 },
Johannes Berge5497d72011-07-05 16:35:40 +0200753};
754
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300755static const struct nla_policy
vamsi krishna1e1b11b2019-02-01 18:34:51 +0530756nl80211_match_band_rssi_policy[NUM_NL80211_BANDS] = {
757 [NL80211_BAND_2GHZ] = { .type = NLA_S32 },
758 [NL80211_BAND_5GHZ] = { .type = NLA_S32 },
Arend van Spriele548a1c2019-08-02 13:31:02 +0200759 [NL80211_BAND_6GHZ] = { .type = NLA_S32 },
vamsi krishna1e1b11b2019-02-01 18:34:51 +0530760 [NL80211_BAND_60GHZ] = { .type = NLA_S32 },
761};
762
763static const struct nla_policy
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300764nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
Johannes Berg4a4ab0d2012-06-13 11:17:11 +0200765 [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300766 .len = IEEE80211_MAX_SSID_LEN },
Johannes Bergc7721c02020-04-30 22:13:10 +0200767 [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Thomas Pedersen88e920b2012-06-21 11:09:54 -0700768 [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
vamsi krishna1e1b11b2019-02-01 18:34:51 +0530769 [NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] =
770 NLA_POLICY_NESTED(nl80211_match_band_rssi_policy),
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300771};
772
Avraham Stern3b06d272015-10-12 09:51:34 +0300773static const struct nla_policy
774nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
775 [NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
776 [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
777};
778
Arend van Spriel38de03d2016-03-02 20:37:18 +0100779static const struct nla_policy
780nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
781 [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
782 [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
783 [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
784 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
785 },
786};
787
Ayala Bekera442b762016-09-20 17:31:15 +0300788/* policy for NAN function attributes */
789static const struct nla_policy
790nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
Johannes Bergcb9abd42020-08-05 15:47:16 +0200791 [NL80211_NAN_FUNC_TYPE] =
792 NLA_POLICY_MAX(NLA_U8, NL80211_NAN_FUNC_MAX_TYPE),
Srinivas Dasari0a278442017-07-07 01:43:40 +0300793 [NL80211_NAN_FUNC_SERVICE_ID] = {
Ayala Bekera442b762016-09-20 17:31:15 +0300794 .len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
795 [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
796 [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
797 [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
798 [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
799 [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
Johannes Bergc7721c02020-04-30 22:13:10 +0200800 [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Ayala Bekera442b762016-09-20 17:31:15 +0300801 [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
802 [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
803 [NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
804 .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN },
805 [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
806 [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
807 [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
808 [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8 },
809 [NL80211_NAN_FUNC_TERM_REASON] = { .type = NLA_U8 },
810};
811
812/* policy for Service Response Filter attributes */
813static const struct nla_policy
814nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
815 [NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG },
816 [NL80211_NAN_SRF_BF] = { .type = NLA_BINARY,
817 .len = NL80211_NAN_FUNC_SRF_MAX_LEN },
818 [NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 },
819 [NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED },
820};
821
Peng Xuad670232017-10-03 23:21:51 +0300822/* policy for packet pattern attributes */
823static const struct nla_policy
824nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
825 [NL80211_PKTPAT_MASK] = { .type = NLA_BINARY, },
826 [NL80211_PKTPAT_PATTERN] = { .type = NLA_BINARY, },
827 [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 },
828};
829
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200830int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
831 struct cfg80211_registered_device **rdev,
832 struct wireless_dev **wdev)
Holger Schuriga0438972009-11-11 11:30:02 +0100833{
Johannes Berg67748892010-10-04 21:14:06 +0200834 int err;
835
Johannes Berg97990a02013-04-19 01:02:55 +0200836 if (!cb->args[0]) {
Johannes Berg50508d92019-07-29 16:31:09 +0200837 struct nlattr **attrbuf;
838
839 attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
840 GFP_KERNEL);
841 if (!attrbuf)
842 return -ENOMEM;
843
Johannes Berg8cb08172019-04-26 14:07:28 +0200844 err = nlmsg_parse_deprecated(cb->nlh,
845 GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Berg50508d92019-07-29 16:31:09 +0200846 attrbuf, nl80211_fam.maxattr,
Johannes Berg8cb08172019-04-26 14:07:28 +0200847 nl80211_policy, NULL);
Johannes Berg50508d92019-07-29 16:31:09 +0200848 if (err) {
849 kfree(attrbuf);
Johannes Bergea90e0d2017-03-15 14:26:04 +0100850 return err;
Johannes Berg50508d92019-07-29 16:31:09 +0200851 }
Johannes Berg97990a02013-04-19 01:02:55 +0200852
Johannes Berg50508d92019-07-29 16:31:09 +0200853 *wdev = __cfg80211_wdev_from_attrs(sock_net(cb->skb->sk),
854 attrbuf);
855 kfree(attrbuf);
Johannes Bergea90e0d2017-03-15 14:26:04 +0100856 if (IS_ERR(*wdev))
857 return PTR_ERR(*wdev);
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800858 *rdev = wiphy_to_rdev((*wdev)->wiphy);
Johannes Bergc319d502013-07-30 22:34:28 +0200859 /* 0 is the first index - add 1 to parse only once */
860 cb->args[0] = (*rdev)->wiphy_idx + 1;
Johannes Berg97990a02013-04-19 01:02:55 +0200861 cb->args[1] = (*wdev)->identifier;
862 } else {
Johannes Bergc319d502013-07-30 22:34:28 +0200863 /* subtract the 1 again here */
864 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
Johannes Berg97990a02013-04-19 01:02:55 +0200865 struct wireless_dev *tmp;
866
Johannes Bergea90e0d2017-03-15 14:26:04 +0100867 if (!wiphy)
868 return -ENODEV;
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800869 *rdev = wiphy_to_rdev(wiphy);
Johannes Berg97990a02013-04-19 01:02:55 +0200870 *wdev = NULL;
871
Johannes Berg53873f12016-05-03 16:52:04 +0300872 list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
Johannes Berg97990a02013-04-19 01:02:55 +0200873 if (tmp->identifier == cb->args[1]) {
874 *wdev = tmp;
875 break;
876 }
877 }
Johannes Berg97990a02013-04-19 01:02:55 +0200878
Johannes Bergea90e0d2017-03-15 14:26:04 +0100879 if (!*wdev)
880 return -ENODEV;
Johannes Berg67748892010-10-04 21:14:06 +0200881 }
882
Johannes Berg67748892010-10-04 21:14:06 +0200883 return 0;
Johannes Berg67748892010-10-04 21:14:06 +0200884}
885
Johannes Berg55682962007-09-20 13:09:35 -0400886/* message building helper */
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200887void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
888 int flags, u8 cmd)
Johannes Berg55682962007-09-20 13:09:35 -0400889{
890 /* since there is no private header just add the generic one */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000891 return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -0400892}
893
Haim Dreyfuss50f32712018-04-20 13:49:26 +0300894static int nl80211_msg_put_wmm_rules(struct sk_buff *msg,
895 const struct ieee80211_reg_rule *rule)
896{
897 int j;
898 struct nlattr *nl_wmm_rules =
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200899 nla_nest_start_noflag(msg, NL80211_FREQUENCY_ATTR_WMM);
Haim Dreyfuss50f32712018-04-20 13:49:26 +0300900
901 if (!nl_wmm_rules)
902 goto nla_put_failure;
903
904 for (j = 0; j < IEEE80211_NUM_ACS; j++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200905 struct nlattr *nl_wmm_rule = nla_nest_start_noflag(msg, j);
Haim Dreyfuss50f32712018-04-20 13:49:26 +0300906
907 if (!nl_wmm_rule)
908 goto nla_put_failure;
909
910 if (nla_put_u16(msg, NL80211_WMMR_CW_MIN,
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +0200911 rule->wmm_rule.client[j].cw_min) ||
Haim Dreyfuss50f32712018-04-20 13:49:26 +0300912 nla_put_u16(msg, NL80211_WMMR_CW_MAX,
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +0200913 rule->wmm_rule.client[j].cw_max) ||
Haim Dreyfuss50f32712018-04-20 13:49:26 +0300914 nla_put_u8(msg, NL80211_WMMR_AIFSN,
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +0200915 rule->wmm_rule.client[j].aifsn) ||
Haim Dreyfussd3c89bb2018-08-21 09:22:19 +0300916 nla_put_u16(msg, NL80211_WMMR_TXOP,
917 rule->wmm_rule.client[j].cot))
Haim Dreyfuss50f32712018-04-20 13:49:26 +0300918 goto nla_put_failure;
919
920 nla_nest_end(msg, nl_wmm_rule);
921 }
922 nla_nest_end(msg, nl_wmm_rules);
923
924 return 0;
925
926nla_put_failure:
927 return -ENOBUFS;
928}
929
930static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
Johannes Bergcdc89b92013-02-18 23:54:36 +0100931 struct ieee80211_channel *chan,
932 bool large)
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400933{
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200934 /* Some channels must be completely excluded from the
935 * list to protect old user-space tools from breaking
936 */
937 if (!large && chan->flags &
938 (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
939 return 0;
940
David S. Miller9360ffd2012-03-29 04:41:26 -0400941 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
942 chan->center_freq))
943 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400944
Thomas Pedersen942ba882020-04-30 10:25:51 -0700945 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_OFFSET, chan->freq_offset))
946 goto nla_put_failure;
947
David S. Miller9360ffd2012-03-29 04:41:26 -0400948 if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
949 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
950 goto nla_put_failure;
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200951 if (chan->flags & IEEE80211_CHAN_NO_IR) {
952 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
953 goto nla_put_failure;
954 if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
955 goto nla_put_failure;
956 }
Johannes Bergcdc89b92013-02-18 23:54:36 +0100957 if (chan->flags & IEEE80211_CHAN_RADAR) {
958 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
959 goto nla_put_failure;
960 if (large) {
961 u32 time;
962
963 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
964
965 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
966 chan->dfs_state))
967 goto nla_put_failure;
968 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
969 time))
970 goto nla_put_failure;
Janusz Dziedzic089027e2014-02-21 19:46:12 +0100971 if (nla_put_u32(msg,
972 NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
973 chan->dfs_cac_ms))
974 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +0100975 }
976 }
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400977
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100978 if (large) {
979 if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
980 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
981 goto nla_put_failure;
982 if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
983 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
984 goto nla_put_failure;
985 if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
986 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
987 goto nla_put_failure;
988 if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
989 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
990 goto nla_put_failure;
David Spinadel570dbde2014-02-23 09:12:59 +0200991 if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
992 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
993 goto nla_put_failure;
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300994 if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
995 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
David Spinadel570dbde2014-02-23 09:12:59 +0200996 goto nla_put_failure;
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200997 if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
998 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
999 goto nla_put_failure;
1000 if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
1001 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
1002 goto nla_put_failure;
Haim Dreyfuss1e61d822020-01-21 10:12:13 +02001003 if ((chan->flags & IEEE80211_CHAN_NO_HE) &&
1004 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HE))
1005 goto nla_put_failure;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001006 }
1007
David S. Miller9360ffd2012-03-29 04:41:26 -04001008 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
1009 DBM_TO_MBM(chan->max_power)))
1010 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -04001011
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001012 if (large) {
1013 const struct ieee80211_reg_rule *rule =
Haim Dreyfussb88d26d2018-08-21 09:22:20 +03001014 freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001015
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +02001016 if (!IS_ERR_OR_NULL(rule) && rule->has_wmm) {
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001017 if (nl80211_msg_put_wmm_rules(msg, rule))
1018 goto nla_put_failure;
1019 }
1020 }
1021
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -04001022 return 0;
1023
1024 nla_put_failure:
1025 return -ENOBUFS;
1026}
1027
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02001028static bool nl80211_put_txq_stats(struct sk_buff *msg,
1029 struct cfg80211_txq_stats *txqstats,
1030 int attrtype)
1031{
1032 struct nlattr *txqattr;
1033
1034#define PUT_TXQVAL_U32(attr, memb) do { \
1035 if (txqstats->filled & BIT(NL80211_TXQ_STATS_ ## attr) && \
1036 nla_put_u32(msg, NL80211_TXQ_STATS_ ## attr, txqstats->memb)) \
1037 return false; \
1038 } while (0)
1039
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001040 txqattr = nla_nest_start_noflag(msg, attrtype);
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02001041 if (!txqattr)
1042 return false;
1043
1044 PUT_TXQVAL_U32(BACKLOG_BYTES, backlog_bytes);
1045 PUT_TXQVAL_U32(BACKLOG_PACKETS, backlog_packets);
1046 PUT_TXQVAL_U32(FLOWS, flows);
1047 PUT_TXQVAL_U32(DROPS, drops);
1048 PUT_TXQVAL_U32(ECN_MARKS, ecn_marks);
1049 PUT_TXQVAL_U32(OVERLIMIT, overlimit);
1050 PUT_TXQVAL_U32(OVERMEMORY, overmemory);
1051 PUT_TXQVAL_U32(COLLISIONS, collisions);
1052 PUT_TXQVAL_U32(TX_BYTES, tx_bytes);
1053 PUT_TXQVAL_U32(TX_PACKETS, tx_packets);
1054 PUT_TXQVAL_U32(MAX_FLOWS, max_flows);
1055 nla_nest_end(msg, txqattr);
1056
1057#undef PUT_TXQVAL_U32
1058 return true;
1059}
1060
Johannes Berg55682962007-09-20 13:09:35 -04001061/* netlink command implementations */
1062
Johannes Bergb9454e82009-07-08 13:29:08 +02001063struct key_parse {
1064 struct key_params p;
1065 int idx;
Johannes Berge31b8212010-10-05 19:39:30 +02001066 int type;
Jouni Malinen56be3932020-02-22 15:25:43 +02001067 bool def, defmgmt, defbeacon;
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001068 bool def_uni, def_multi;
Johannes Bergb9454e82009-07-08 13:29:08 +02001069};
1070
Johannes Berg768075e2017-11-13 15:35:06 +01001071static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
1072 struct key_parse *k)
Johannes Bergb9454e82009-07-08 13:29:08 +02001073{
1074 struct nlattr *tb[NL80211_KEY_MAX + 1];
Johannes Berg8cb08172019-04-26 14:07:28 +02001075 int err = nla_parse_nested_deprecated(tb, NL80211_KEY_MAX, key,
1076 nl80211_key_policy,
1077 info->extack);
Johannes Bergb9454e82009-07-08 13:29:08 +02001078 if (err)
1079 return err;
1080
1081 k->def = !!tb[NL80211_KEY_DEFAULT];
1082 k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
Jouni Malinen56be3932020-02-22 15:25:43 +02001083 k->defbeacon = !!tb[NL80211_KEY_DEFAULT_BEACON];
Johannes Bergb9454e82009-07-08 13:29:08 +02001084
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001085 if (k->def) {
1086 k->def_uni = true;
1087 k->def_multi = true;
1088 }
Jouni Malinen56be3932020-02-22 15:25:43 +02001089 if (k->defmgmt || k->defbeacon)
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001090 k->def_multi = true;
1091
Johannes Bergb9454e82009-07-08 13:29:08 +02001092 if (tb[NL80211_KEY_IDX])
1093 k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
1094
1095 if (tb[NL80211_KEY_DATA]) {
1096 k->p.key = nla_data(tb[NL80211_KEY_DATA]);
1097 k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
1098 }
1099
1100 if (tb[NL80211_KEY_SEQ]) {
1101 k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
1102 k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
1103 }
1104
1105 if (tb[NL80211_KEY_CIPHER])
1106 k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
1107
Johannes Bergab0d76f2018-10-02 10:00:07 +02001108 if (tb[NL80211_KEY_TYPE])
Johannes Berge31b8212010-10-05 19:39:30 +02001109 k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
Johannes Berge31b8212010-10-05 19:39:30 +02001110
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001111 if (tb[NL80211_KEY_DEFAULT_TYPES]) {
1112 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07001113
Johannes Berg8cb08172019-04-26 14:07:28 +02001114 err = nla_parse_nested_deprecated(kdt,
1115 NUM_NL80211_KEY_DEFAULT_TYPES - 1,
1116 tb[NL80211_KEY_DEFAULT_TYPES],
1117 nl80211_key_default_policy,
1118 info->extack);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001119 if (err)
1120 return err;
1121
1122 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
1123 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
1124 }
1125
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01001126 if (tb[NL80211_KEY_MODE])
1127 k->p.mode = nla_get_u8(tb[NL80211_KEY_MODE]);
1128
Johannes Bergb9454e82009-07-08 13:29:08 +02001129 return 0;
1130}
1131
1132static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
1133{
1134 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
1135 k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
1136 k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
1137 }
1138
1139 if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
1140 k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
1141 k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
1142 }
1143
1144 if (info->attrs[NL80211_ATTR_KEY_IDX])
1145 k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
1146
1147 if (info->attrs[NL80211_ATTR_KEY_CIPHER])
1148 k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
1149
1150 k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
1151 k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
1152
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001153 if (k->def) {
1154 k->def_uni = true;
1155 k->def_multi = true;
1156 }
1157 if (k->defmgmt)
1158 k->def_multi = true;
1159
Johannes Bergab0d76f2018-10-02 10:00:07 +02001160 if (info->attrs[NL80211_ATTR_KEY_TYPE])
Johannes Berge31b8212010-10-05 19:39:30 +02001161 k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Johannes Berge31b8212010-10-05 19:39:30 +02001162
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001163 if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
1164 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Johannes Berg8cb08172019-04-26 14:07:28 +02001165 int err = nla_parse_nested_deprecated(kdt,
1166 NUM_NL80211_KEY_DEFAULT_TYPES - 1,
1167 info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
1168 nl80211_key_default_policy,
1169 info->extack);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001170 if (err)
1171 return err;
1172
1173 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
1174 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
1175 }
1176
Johannes Bergb9454e82009-07-08 13:29:08 +02001177 return 0;
1178}
1179
1180static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
1181{
1182 int err;
1183
1184 memset(k, 0, sizeof(*k));
1185 k->idx = -1;
Johannes Berge31b8212010-10-05 19:39:30 +02001186 k->type = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +02001187
1188 if (info->attrs[NL80211_ATTR_KEY])
Johannes Berg768075e2017-11-13 15:35:06 +01001189 err = nl80211_parse_key_new(info, info->attrs[NL80211_ATTR_KEY], k);
Johannes Bergb9454e82009-07-08 13:29:08 +02001190 else
1191 err = nl80211_parse_key_old(info, k);
1192
1193 if (err)
1194 return err;
1195
Jouni Malinen56be3932020-02-22 15:25:43 +02001196 if ((k->def ? 1 : 0) + (k->defmgmt ? 1 : 0) +
1197 (k->defbeacon ? 1 : 0) > 1) {
1198 GENL_SET_ERR_MSG(info,
1199 "key with multiple default flags is invalid");
Johannes Bergb9454e82009-07-08 13:29:08 +02001200 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001201 }
Johannes Bergb9454e82009-07-08 13:29:08 +02001202
Jouni Malinen56be3932020-02-22 15:25:43 +02001203 if (k->defmgmt || k->defbeacon) {
Johannes Berg768075e2017-11-13 15:35:06 +01001204 if (k->def_uni || !k->def_multi) {
Jouni Malinen56be3932020-02-22 15:25:43 +02001205 GENL_SET_ERR_MSG(info,
1206 "defmgmt/defbeacon key must be mcast");
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001207 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001208 }
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001209 }
1210
Johannes Bergb9454e82009-07-08 13:29:08 +02001211 if (k->idx != -1) {
1212 if (k->defmgmt) {
Johannes Berg768075e2017-11-13 15:35:06 +01001213 if (k->idx < 4 || k->idx > 5) {
1214 GENL_SET_ERR_MSG(info,
1215 "defmgmt key idx not 4 or 5");
Johannes Bergb9454e82009-07-08 13:29:08 +02001216 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001217 }
Jouni Malinen56be3932020-02-22 15:25:43 +02001218 } else if (k->defbeacon) {
1219 if (k->idx < 6 || k->idx > 7) {
1220 GENL_SET_ERR_MSG(info,
1221 "defbeacon key idx not 6 or 7");
1222 return -EINVAL;
1223 }
Johannes Bergb9454e82009-07-08 13:29:08 +02001224 } else if (k->def) {
Johannes Berg768075e2017-11-13 15:35:06 +01001225 if (k->idx < 0 || k->idx > 3) {
1226 GENL_SET_ERR_MSG(info, "def key idx not 0-3");
Johannes Bergb9454e82009-07-08 13:29:08 +02001227 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001228 }
Johannes Bergb9454e82009-07-08 13:29:08 +02001229 } else {
Jouni Malinen56be3932020-02-22 15:25:43 +02001230 if (k->idx < 0 || k->idx > 7) {
1231 GENL_SET_ERR_MSG(info, "key idx not 0-7");
Johannes Bergb9454e82009-07-08 13:29:08 +02001232 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001233 }
Johannes Bergb9454e82009-07-08 13:29:08 +02001234 }
1235 }
1236
1237 return 0;
1238}
1239
Johannes Bergfffd0932009-07-08 14:22:54 +02001240static struct cfg80211_cached_keys *
1241nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
Johannes Berg768075e2017-11-13 15:35:06 +01001242 struct genl_info *info, bool *no_ht)
Johannes Bergfffd0932009-07-08 14:22:54 +02001243{
Johannes Berg768075e2017-11-13 15:35:06 +01001244 struct nlattr *keys = info->attrs[NL80211_ATTR_KEYS];
Johannes Bergfffd0932009-07-08 14:22:54 +02001245 struct key_parse parse;
1246 struct nlattr *key;
1247 struct cfg80211_cached_keys *result;
1248 int rem, err, def = 0;
Johannes Bergf1c1f172016-09-13 17:08:23 +02001249 bool have_key = false;
1250
1251 nla_for_each_nested(key, keys, rem) {
1252 have_key = true;
1253 break;
1254 }
1255
1256 if (!have_key)
1257 return NULL;
Johannes Bergfffd0932009-07-08 14:22:54 +02001258
1259 result = kzalloc(sizeof(*result), GFP_KERNEL);
1260 if (!result)
1261 return ERR_PTR(-ENOMEM);
1262
1263 result->def = -1;
Johannes Bergfffd0932009-07-08 14:22:54 +02001264
1265 nla_for_each_nested(key, keys, rem) {
1266 memset(&parse, 0, sizeof(parse));
1267 parse.idx = -1;
1268
Johannes Berg768075e2017-11-13 15:35:06 +01001269 err = nl80211_parse_key_new(info, key, &parse);
Johannes Bergfffd0932009-07-08 14:22:54 +02001270 if (err)
1271 goto error;
1272 err = -EINVAL;
1273 if (!parse.p.key)
1274 goto error;
Johannes Berg768075e2017-11-13 15:35:06 +01001275 if (parse.idx < 0 || parse.idx > 3) {
1276 GENL_SET_ERR_MSG(info, "key index out of range [0-3]");
Johannes Bergfffd0932009-07-08 14:22:54 +02001277 goto error;
Johannes Berg768075e2017-11-13 15:35:06 +01001278 }
Johannes Bergfffd0932009-07-08 14:22:54 +02001279 if (parse.def) {
Johannes Berg768075e2017-11-13 15:35:06 +01001280 if (def) {
1281 GENL_SET_ERR_MSG(info,
1282 "only one key can be default");
Johannes Bergfffd0932009-07-08 14:22:54 +02001283 goto error;
Johannes Berg768075e2017-11-13 15:35:06 +01001284 }
Johannes Bergfffd0932009-07-08 14:22:54 +02001285 def = 1;
1286 result->def = parse.idx;
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001287 if (!parse.def_uni || !parse.def_multi)
1288 goto error;
Johannes Bergfffd0932009-07-08 14:22:54 +02001289 } else if (parse.defmgmt)
1290 goto error;
1291 err = cfg80211_validate_key_settings(rdev, &parse.p,
Johannes Berge31b8212010-10-05 19:39:30 +02001292 parse.idx, false, NULL);
Johannes Bergfffd0932009-07-08 14:22:54 +02001293 if (err)
1294 goto error;
Johannes Berg386b1f22016-09-13 16:10:02 +02001295 if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
1296 parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) {
Johannes Berg768075e2017-11-13 15:35:06 +01001297 GENL_SET_ERR_MSG(info, "connect key must be WEP");
Johannes Berg386b1f22016-09-13 16:10:02 +02001298 err = -EINVAL;
1299 goto error;
1300 }
Johannes Bergfffd0932009-07-08 14:22:54 +02001301 result->params[parse.idx].cipher = parse.p.cipher;
1302 result->params[parse.idx].key_len = parse.p.key_len;
1303 result->params[parse.idx].key = result->data[parse.idx];
1304 memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
Sujith Manoharande7044e2012-10-18 10:19:28 +05301305
Johannes Berg386b1f22016-09-13 16:10:02 +02001306 /* must be WEP key if we got here */
1307 if (no_ht)
1308 *no_ht = true;
Johannes Bergfffd0932009-07-08 14:22:54 +02001309 }
1310
Johannes Bergf1c1f172016-09-13 17:08:23 +02001311 if (result->def < 0) {
1312 err = -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001313 GENL_SET_ERR_MSG(info, "need a default/TX key");
Johannes Bergf1c1f172016-09-13 17:08:23 +02001314 goto error;
1315 }
1316
Johannes Bergfffd0932009-07-08 14:22:54 +02001317 return result;
1318 error:
1319 kfree(result);
1320 return ERR_PTR(err);
1321}
1322
1323static int nl80211_key_allowed(struct wireless_dev *wdev)
1324{
1325 ASSERT_WDEV_LOCK(wdev);
1326
Johannes Bergfffd0932009-07-08 14:22:54 +02001327 switch (wdev->iftype) {
1328 case NL80211_IFTYPE_AP:
1329 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02001330 case NL80211_IFTYPE_P2P_GO:
Thomas Pedersenff973af2011-05-03 16:57:12 -07001331 case NL80211_IFTYPE_MESH_POINT:
Johannes Bergfffd0932009-07-08 14:22:54 +02001332 break;
1333 case NL80211_IFTYPE_ADHOC:
Johannes Bergfffd0932009-07-08 14:22:54 +02001334 case NL80211_IFTYPE_STATION:
Johannes Berg074ac8d2010-09-16 14:58:22 +02001335 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Bergceca7b72013-05-16 00:55:45 +02001336 if (!wdev->current_bss)
Johannes Bergfffd0932009-07-08 14:22:54 +02001337 return -ENOLINK;
1338 break;
Johannes Bergde4fcba2014-10-31 14:16:12 +01001339 case NL80211_IFTYPE_UNSPECIFIED:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01001340 case NL80211_IFTYPE_OCB:
Johannes Bergde4fcba2014-10-31 14:16:12 +01001341 case NL80211_IFTYPE_MONITOR:
Ayala Bekercb3b7d82016-09-20 17:31:13 +03001342 case NL80211_IFTYPE_NAN:
Johannes Bergde4fcba2014-10-31 14:16:12 +01001343 case NL80211_IFTYPE_P2P_DEVICE:
1344 case NL80211_IFTYPE_WDS:
1345 case NUM_NL80211_IFTYPES:
Johannes Bergfffd0932009-07-08 14:22:54 +02001346 return -EINVAL;
1347 }
1348
1349 return 0;
1350}
1351
Jouni Malinen664834d2014-01-15 00:01:44 +02001352static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
Thomas Pedersen942ba882020-04-30 10:25:51 -07001353 u32 freq)
Jouni Malinen664834d2014-01-15 00:01:44 +02001354{
1355 struct ieee80211_channel *chan;
1356
Thomas Pedersen942ba882020-04-30 10:25:51 -07001357 chan = ieee80211_get_channel_khz(wiphy, freq);
Jouni Malinen664834d2014-01-15 00:01:44 +02001358 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
1359 return NULL;
1360 return chan;
1361}
1362
Johannes Berg7527a782011-05-13 10:58:57 +02001363static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
1364{
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001365 struct nlattr *nl_modes = nla_nest_start_noflag(msg, attr);
Johannes Berg7527a782011-05-13 10:58:57 +02001366 int i;
1367
1368 if (!nl_modes)
1369 goto nla_put_failure;
1370
1371 i = 0;
1372 while (ifmodes) {
David S. Miller9360ffd2012-03-29 04:41:26 -04001373 if ((ifmodes & 1) && nla_put_flag(msg, i))
1374 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001375 ifmodes >>= 1;
1376 i++;
1377 }
1378
1379 nla_nest_end(msg, nl_modes);
1380 return 0;
1381
1382nla_put_failure:
1383 return -ENOBUFS;
1384}
1385
1386static int nl80211_put_iface_combinations(struct wiphy *wiphy,
Johannes Bergcdc89b92013-02-18 23:54:36 +01001387 struct sk_buff *msg,
1388 bool large)
Johannes Berg7527a782011-05-13 10:58:57 +02001389{
1390 struct nlattr *nl_combis;
1391 int i, j;
1392
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001393 nl_combis = nla_nest_start_noflag(msg,
1394 NL80211_ATTR_INTERFACE_COMBINATIONS);
Johannes Berg7527a782011-05-13 10:58:57 +02001395 if (!nl_combis)
1396 goto nla_put_failure;
1397
1398 for (i = 0; i < wiphy->n_iface_combinations; i++) {
1399 const struct ieee80211_iface_combination *c;
1400 struct nlattr *nl_combi, *nl_limits;
1401
1402 c = &wiphy->iface_combinations[i];
1403
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001404 nl_combi = nla_nest_start_noflag(msg, i + 1);
Johannes Berg7527a782011-05-13 10:58:57 +02001405 if (!nl_combi)
1406 goto nla_put_failure;
1407
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001408 nl_limits = nla_nest_start_noflag(msg,
1409 NL80211_IFACE_COMB_LIMITS);
Johannes Berg7527a782011-05-13 10:58:57 +02001410 if (!nl_limits)
1411 goto nla_put_failure;
1412
1413 for (j = 0; j < c->n_limits; j++) {
1414 struct nlattr *nl_limit;
1415
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001416 nl_limit = nla_nest_start_noflag(msg, j + 1);
Johannes Berg7527a782011-05-13 10:58:57 +02001417 if (!nl_limit)
1418 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04001419 if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
1420 c->limits[j].max))
1421 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001422 if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
1423 c->limits[j].types))
1424 goto nla_put_failure;
1425 nla_nest_end(msg, nl_limit);
1426 }
1427
1428 nla_nest_end(msg, nl_limits);
1429
David S. Miller9360ffd2012-03-29 04:41:26 -04001430 if (c->beacon_int_infra_match &&
1431 nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
1432 goto nla_put_failure;
1433 if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
1434 c->num_different_channels) ||
1435 nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
1436 c->max_interfaces))
1437 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +01001438 if (large &&
Felix Fietkau8c48b502014-05-05 11:48:40 +02001439 (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
1440 c->radar_detect_widths) ||
1441 nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
1442 c->radar_detect_regions)))
Johannes Bergcdc89b92013-02-18 23:54:36 +01001443 goto nla_put_failure;
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05301444 if (c->beacon_int_min_gcd &&
1445 nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
1446 c->beacon_int_min_gcd))
1447 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001448
1449 nla_nest_end(msg, nl_combi);
1450 }
1451
1452 nla_nest_end(msg, nl_combis);
1453
1454 return 0;
1455nla_put_failure:
1456 return -ENOBUFS;
1457}
1458
Johannes Berg3713b4e2013-02-14 16:19:38 +01001459#ifdef CONFIG_PM
Johannes Bergb56cf722013-02-20 01:02:38 +01001460static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
1461 struct sk_buff *msg)
1462{
Johannes Berg964dc9e2013-06-03 17:25:34 +02001463 const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
Johannes Bergb56cf722013-02-20 01:02:38 +01001464 struct nlattr *nl_tcp;
1465
1466 if (!tcp)
1467 return 0;
1468
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001469 nl_tcp = nla_nest_start_noflag(msg,
1470 NL80211_WOWLAN_TRIG_TCP_CONNECTION);
Johannes Bergb56cf722013-02-20 01:02:38 +01001471 if (!nl_tcp)
1472 return -ENOBUFS;
1473
1474 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1475 tcp->data_payload_max))
1476 return -ENOBUFS;
1477
1478 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1479 tcp->data_payload_max))
1480 return -ENOBUFS;
1481
1482 if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
1483 return -ENOBUFS;
1484
1485 if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
1486 sizeof(*tcp->tok), tcp->tok))
1487 return -ENOBUFS;
1488
1489 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
1490 tcp->data_interval_max))
1491 return -ENOBUFS;
1492
1493 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
1494 tcp->wake_payload_max))
1495 return -ENOBUFS;
1496
1497 nla_nest_end(msg, nl_tcp);
1498 return 0;
1499}
1500
Johannes Berg3713b4e2013-02-14 16:19:38 +01001501static int nl80211_send_wowlan(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001502 struct cfg80211_registered_device *rdev,
Johannes Bergb56cf722013-02-20 01:02:38 +01001503 bool large)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001504{
1505 struct nlattr *nl_wowlan;
1506
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001507 if (!rdev->wiphy.wowlan)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001508 return 0;
1509
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001510 nl_wowlan = nla_nest_start_noflag(msg,
1511 NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001512 if (!nl_wowlan)
1513 return -ENOBUFS;
1514
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001515 if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001516 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001517 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001518 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001519 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001520 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001521 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001522 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001523 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001524 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001525 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001526 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001527 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001528 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001529 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001530 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
1531 return -ENOBUFS;
1532
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001533 if (rdev->wiphy.wowlan->n_patterns) {
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07001534 struct nl80211_pattern_support pat = {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001535 .max_patterns = rdev->wiphy.wowlan->n_patterns,
1536 .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
1537 .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
1538 .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001539 };
1540
1541 if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
1542 sizeof(pat), &pat))
1543 return -ENOBUFS;
1544 }
1545
Luciano Coelho75453cc2015-01-09 14:06:37 +02001546 if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
1547 nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
1548 rdev->wiphy.wowlan->max_nd_match_sets))
1549 return -ENOBUFS;
1550
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001551 if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
Johannes Bergb56cf722013-02-20 01:02:38 +01001552 return -ENOBUFS;
1553
Johannes Berg3713b4e2013-02-14 16:19:38 +01001554 nla_nest_end(msg, nl_wowlan);
1555
1556 return 0;
1557}
1558#endif
1559
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001560static int nl80211_send_coalesce(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001561 struct cfg80211_registered_device *rdev)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001562{
1563 struct nl80211_coalesce_rule_support rule;
1564
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001565 if (!rdev->wiphy.coalesce)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001566 return 0;
1567
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001568 rule.max_rules = rdev->wiphy.coalesce->n_rules;
1569 rule.max_delay = rdev->wiphy.coalesce->max_delay;
1570 rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
1571 rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
1572 rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
1573 rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001574
1575 if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
1576 return -ENOBUFS;
1577
1578 return 0;
1579}
1580
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001581static int
1582nl80211_send_iftype_data(struct sk_buff *msg,
Johannes Berg22395212020-05-28 21:34:31 +02001583 const struct ieee80211_supported_band *sband,
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001584 const struct ieee80211_sband_iftype_data *iftdata)
1585{
1586 const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap;
1587
1588 if (nl80211_put_iftypes(msg, NL80211_BAND_IFTYPE_ATTR_IFTYPES,
1589 iftdata->types_mask))
1590 return -ENOBUFS;
1591
1592 if (he_cap->has_he) {
1593 if (nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
1594 sizeof(he_cap->he_cap_elem.mac_cap_info),
1595 he_cap->he_cap_elem.mac_cap_info) ||
1596 nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
1597 sizeof(he_cap->he_cap_elem.phy_cap_info),
1598 he_cap->he_cap_elem.phy_cap_info) ||
1599 nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
1600 sizeof(he_cap->he_mcs_nss_supp),
1601 &he_cap->he_mcs_nss_supp) ||
1602 nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
1603 sizeof(he_cap->ppe_thres), he_cap->ppe_thres))
1604 return -ENOBUFS;
1605 }
1606
Johannes Berg22395212020-05-28 21:34:31 +02001607 if (sband->band == NL80211_BAND_6GHZ &&
1608 nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
1609 sizeof(iftdata->he_6ghz_capa),
1610 &iftdata->he_6ghz_capa))
1611 return -ENOBUFS;
1612
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001613 return 0;
1614}
1615
Johannes Berg3713b4e2013-02-14 16:19:38 +01001616static int nl80211_send_band_rateinfo(struct sk_buff *msg,
1617 struct ieee80211_supported_band *sband)
1618{
1619 struct nlattr *nl_rates, *nl_rate;
1620 struct ieee80211_rate *rate;
1621 int i;
1622
1623 /* add HT info */
1624 if (sband->ht_cap.ht_supported &&
1625 (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
1626 sizeof(sband->ht_cap.mcs),
1627 &sband->ht_cap.mcs) ||
1628 nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
1629 sband->ht_cap.cap) ||
1630 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
1631 sband->ht_cap.ampdu_factor) ||
1632 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
1633 sband->ht_cap.ampdu_density)))
1634 return -ENOBUFS;
1635
1636 /* add VHT info */
1637 if (sband->vht_cap.vht_supported &&
1638 (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
1639 sizeof(sband->vht_cap.vht_mcs),
1640 &sband->vht_cap.vht_mcs) ||
1641 nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
1642 sband->vht_cap.cap)))
1643 return -ENOBUFS;
1644
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001645 if (sband->n_iftype_data) {
1646 struct nlattr *nl_iftype_data =
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001647 nla_nest_start_noflag(msg,
1648 NL80211_BAND_ATTR_IFTYPE_DATA);
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001649 int err;
1650
1651 if (!nl_iftype_data)
1652 return -ENOBUFS;
1653
1654 for (i = 0; i < sband->n_iftype_data; i++) {
1655 struct nlattr *iftdata;
1656
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001657 iftdata = nla_nest_start_noflag(msg, i + 1);
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001658 if (!iftdata)
1659 return -ENOBUFS;
1660
Johannes Berg22395212020-05-28 21:34:31 +02001661 err = nl80211_send_iftype_data(msg, sband,
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001662 &sband->iftype_data[i]);
1663 if (err)
1664 return err;
1665
1666 nla_nest_end(msg, iftdata);
1667 }
1668
1669 nla_nest_end(msg, nl_iftype_data);
1670 }
1671
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +03001672 /* add EDMG info */
1673 if (sband->edmg_cap.channels &&
1674 (nla_put_u8(msg, NL80211_BAND_ATTR_EDMG_CHANNELS,
1675 sband->edmg_cap.channels) ||
1676 nla_put_u8(msg, NL80211_BAND_ATTR_EDMG_BW_CONFIG,
1677 sband->edmg_cap.bw_config)))
1678
1679 return -ENOBUFS;
1680
Johannes Berg3713b4e2013-02-14 16:19:38 +01001681 /* add bitrates */
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001682 nl_rates = nla_nest_start_noflag(msg, NL80211_BAND_ATTR_RATES);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001683 if (!nl_rates)
1684 return -ENOBUFS;
1685
1686 for (i = 0; i < sband->n_bitrates; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001687 nl_rate = nla_nest_start_noflag(msg, i);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001688 if (!nl_rate)
1689 return -ENOBUFS;
1690
1691 rate = &sband->bitrates[i];
1692 if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
1693 rate->bitrate))
1694 return -ENOBUFS;
1695 if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
1696 nla_put_flag(msg,
1697 NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
1698 return -ENOBUFS;
1699
1700 nla_nest_end(msg, nl_rate);
1701 }
1702
1703 nla_nest_end(msg, nl_rates);
1704
1705 return 0;
1706}
1707
1708static int
1709nl80211_send_mgmt_stypes(struct sk_buff *msg,
1710 const struct ieee80211_txrx_stypes *mgmt_stypes)
1711{
1712 u16 stypes;
1713 struct nlattr *nl_ftypes, *nl_ifs;
1714 enum nl80211_iftype ift;
1715 int i;
1716
1717 if (!mgmt_stypes)
1718 return 0;
1719
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001720 nl_ifs = nla_nest_start_noflag(msg, NL80211_ATTR_TX_FRAME_TYPES);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001721 if (!nl_ifs)
1722 return -ENOBUFS;
1723
1724 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001725 nl_ftypes = nla_nest_start_noflag(msg, ift);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001726 if (!nl_ftypes)
1727 return -ENOBUFS;
1728 i = 0;
1729 stypes = mgmt_stypes[ift].tx;
1730 while (stypes) {
1731 if ((stypes & 1) &&
1732 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1733 (i << 4) | IEEE80211_FTYPE_MGMT))
1734 return -ENOBUFS;
1735 stypes >>= 1;
1736 i++;
1737 }
1738 nla_nest_end(msg, nl_ftypes);
1739 }
1740
1741 nla_nest_end(msg, nl_ifs);
1742
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001743 nl_ifs = nla_nest_start_noflag(msg, NL80211_ATTR_RX_FRAME_TYPES);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001744 if (!nl_ifs)
1745 return -ENOBUFS;
1746
1747 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001748 nl_ftypes = nla_nest_start_noflag(msg, ift);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001749 if (!nl_ftypes)
1750 return -ENOBUFS;
1751 i = 0;
1752 stypes = mgmt_stypes[ift].rx;
1753 while (stypes) {
1754 if ((stypes & 1) &&
1755 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1756 (i << 4) | IEEE80211_FTYPE_MGMT))
1757 return -ENOBUFS;
1758 stypes >>= 1;
1759 i++;
1760 }
1761 nla_nest_end(msg, nl_ftypes);
1762 }
1763 nla_nest_end(msg, nl_ifs);
1764
1765 return 0;
1766}
1767
Johannes Berg17948992016-10-26 11:42:04 +02001768#define CMD(op, n) \
1769 do { \
1770 if (rdev->ops->op) { \
1771 i++; \
1772 if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
1773 goto nla_put_failure; \
1774 } \
1775 } while (0)
1776
1777static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
1778 struct sk_buff *msg)
1779{
1780 int i = 0;
1781
1782 /*
1783 * do *NOT* add anything into this function, new things need to be
1784 * advertised only to new versions of userspace that can deal with
1785 * the split (and they can't possibly care about new features...
1786 */
1787 CMD(add_virtual_intf, NEW_INTERFACE);
1788 CMD(change_virtual_intf, SET_INTERFACE);
1789 CMD(add_key, NEW_KEY);
1790 CMD(start_ap, START_AP);
1791 CMD(add_station, NEW_STATION);
1792 CMD(add_mpath, NEW_MPATH);
1793 CMD(update_mesh_config, SET_MESH_CONFIG);
1794 CMD(change_bss, SET_BSS);
1795 CMD(auth, AUTHENTICATE);
1796 CMD(assoc, ASSOCIATE);
1797 CMD(deauth, DEAUTHENTICATE);
1798 CMD(disassoc, DISASSOCIATE);
1799 CMD(join_ibss, JOIN_IBSS);
1800 CMD(join_mesh, JOIN_MESH);
1801 CMD(set_pmksa, SET_PMKSA);
1802 CMD(del_pmksa, DEL_PMKSA);
1803 CMD(flush_pmksa, FLUSH_PMKSA);
1804 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
1805 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
1806 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
1807 CMD(mgmt_tx, FRAME);
1808 CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
1809 if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
1810 i++;
1811 if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
1812 goto nla_put_failure;
1813 }
1814 if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
1815 rdev->ops->join_mesh) {
1816 i++;
1817 if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
1818 goto nla_put_failure;
1819 }
1820 CMD(set_wds_peer, SET_WDS_PEER);
1821 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
1822 CMD(tdls_mgmt, TDLS_MGMT);
1823 CMD(tdls_oper, TDLS_OPER);
1824 }
Arend Van Sprielca986ad2017-04-21 13:05:00 +01001825 if (rdev->wiphy.max_sched_scan_reqs)
Johannes Berg17948992016-10-26 11:42:04 +02001826 CMD(sched_scan_start, START_SCHED_SCAN);
1827 CMD(probe_client, PROBE_CLIENT);
1828 CMD(set_noack_map, SET_NOACK_MAP);
1829 if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
1830 i++;
1831 if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1832 goto nla_put_failure;
1833 }
1834 CMD(start_p2p_device, START_P2P_DEVICE);
1835 CMD(set_mcast_rate, SET_MCAST_RATE);
1836#ifdef CONFIG_NL80211_TESTMODE
1837 CMD(testmode_cmd, TESTMODE);
1838#endif
1839
1840 if (rdev->ops->connect || rdev->ops->auth) {
1841 i++;
1842 if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
1843 goto nla_put_failure;
1844 }
1845
1846 if (rdev->ops->disconnect || rdev->ops->deauth) {
1847 i++;
1848 if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
1849 goto nla_put_failure;
1850 }
1851
1852 return i;
1853 nla_put_failure:
1854 return -ENOBUFS;
1855}
1856
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02001857static int
1858nl80211_send_pmsr_ftm_capa(const struct cfg80211_pmsr_capabilities *cap,
1859 struct sk_buff *msg)
1860{
1861 struct nlattr *ftm;
1862
1863 if (!cap->ftm.supported)
1864 return 0;
1865
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001866 ftm = nla_nest_start_noflag(msg, NL80211_PMSR_TYPE_FTM);
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02001867 if (!ftm)
1868 return -ENOBUFS;
1869
1870 if (cap->ftm.asap && nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_ASAP))
1871 return -ENOBUFS;
1872 if (cap->ftm.non_asap &&
1873 nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP))
1874 return -ENOBUFS;
1875 if (cap->ftm.request_lci &&
1876 nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI))
1877 return -ENOBUFS;
1878 if (cap->ftm.request_civicloc &&
1879 nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC))
1880 return -ENOBUFS;
1881 if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES,
1882 cap->ftm.preambles))
1883 return -ENOBUFS;
1884 if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
1885 cap->ftm.bandwidths))
1886 return -ENOBUFS;
1887 if (cap->ftm.max_bursts_exponent >= 0 &&
1888 nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
1889 cap->ftm.max_bursts_exponent))
1890 return -ENOBUFS;
1891 if (cap->ftm.max_ftms_per_burst &&
1892 nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
1893 cap->ftm.max_ftms_per_burst))
1894 return -ENOBUFS;
Avraham Sternefb55202020-01-31 13:12:38 +02001895 if (cap->ftm.trigger_based &&
1896 nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED))
1897 return -ENOBUFS;
1898 if (cap->ftm.non_trigger_based &&
1899 nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED))
1900 return -ENOBUFS;
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02001901
1902 nla_nest_end(msg, ftm);
1903 return 0;
1904}
1905
1906static int nl80211_send_pmsr_capa(struct cfg80211_registered_device *rdev,
1907 struct sk_buff *msg)
1908{
1909 const struct cfg80211_pmsr_capabilities *cap = rdev->wiphy.pmsr_capa;
1910 struct nlattr *pmsr, *caps;
1911
1912 if (!cap)
1913 return 0;
1914
1915 /*
1916 * we don't need to clean up anything here since the caller
1917 * will genlmsg_cancel() if we fail
1918 */
1919
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001920 pmsr = nla_nest_start_noflag(msg, NL80211_ATTR_PEER_MEASUREMENTS);
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02001921 if (!pmsr)
1922 return -ENOBUFS;
1923
1924 if (nla_put_u32(msg, NL80211_PMSR_ATTR_MAX_PEERS, cap->max_peers))
1925 return -ENOBUFS;
1926
1927 if (cap->report_ap_tsf &&
1928 nla_put_flag(msg, NL80211_PMSR_ATTR_REPORT_AP_TSF))
1929 return -ENOBUFS;
1930
1931 if (cap->randomize_mac_addr &&
1932 nla_put_flag(msg, NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR))
1933 return -ENOBUFS;
1934
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001935 caps = nla_nest_start_noflag(msg, NL80211_PMSR_ATTR_TYPE_CAPA);
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02001936 if (!caps)
1937 return -ENOBUFS;
1938
1939 if (nl80211_send_pmsr_ftm_capa(cap, msg))
1940 return -ENOBUFS;
1941
1942 nla_nest_end(msg, caps);
1943 nla_nest_end(msg, pmsr);
1944
1945 return 0;
1946}
1947
Veerendranath Jakkamd6039a32020-01-27 02:00:32 +05301948static int
1949nl80211_put_iftype_akm_suites(struct cfg80211_registered_device *rdev,
1950 struct sk_buff *msg)
1951{
1952 int i;
1953 struct nlattr *nested, *nested_akms;
1954 const struct wiphy_iftype_akm_suites *iftype_akms;
1955
1956 if (!rdev->wiphy.num_iftype_akm_suites ||
1957 !rdev->wiphy.iftype_akm_suites)
1958 return 0;
1959
1960 nested = nla_nest_start(msg, NL80211_ATTR_IFTYPE_AKM_SUITES);
1961 if (!nested)
1962 return -ENOBUFS;
1963
1964 for (i = 0; i < rdev->wiphy.num_iftype_akm_suites; i++) {
1965 nested_akms = nla_nest_start(msg, i + 1);
1966 if (!nested_akms)
1967 return -ENOBUFS;
1968
1969 iftype_akms = &rdev->wiphy.iftype_akm_suites[i];
1970
1971 if (nl80211_put_iftypes(msg, NL80211_IFTYPE_AKM_ATTR_IFTYPES,
1972 iftype_akms->iftypes_mask))
1973 return -ENOBUFS;
1974
1975 if (nla_put(msg, NL80211_IFTYPE_AKM_ATTR_SUITES,
1976 sizeof(u32) * iftype_akms->n_akm_suites,
1977 iftype_akms->akm_suites)) {
1978 return -ENOBUFS;
1979 }
1980 nla_nest_end(msg, nested_akms);
1981 }
1982
1983 nla_nest_end(msg, nested);
1984
1985 return 0;
1986}
1987
Johannes Berg3710a8a2020-02-24 11:34:25 +01001988static int
1989nl80211_put_tid_config_support(struct cfg80211_registered_device *rdev,
1990 struct sk_buff *msg)
1991{
1992 struct nlattr *supp;
1993
1994 if (!rdev->wiphy.tid_config_support.vif &&
1995 !rdev->wiphy.tid_config_support.peer)
1996 return 0;
1997
1998 supp = nla_nest_start(msg, NL80211_ATTR_TID_CONFIG);
1999 if (!supp)
2000 return -ENOSPC;
2001
2002 if (rdev->wiphy.tid_config_support.vif &&
2003 nla_put_u64_64bit(msg, NL80211_TID_CONFIG_ATTR_VIF_SUPP,
2004 rdev->wiphy.tid_config_support.vif,
2005 NL80211_TID_CONFIG_ATTR_PAD))
2006 goto fail;
2007
2008 if (rdev->wiphy.tid_config_support.peer &&
2009 nla_put_u64_64bit(msg, NL80211_TID_CONFIG_ATTR_PEER_SUPP,
2010 rdev->wiphy.tid_config_support.peer,
2011 NL80211_TID_CONFIG_ATTR_PAD))
2012 goto fail;
2013
Tamizh chelvam6a21d162020-01-20 13:21:23 +05302014 /* for now we just use the same value ... makes more sense */
2015 if (nla_put_u8(msg, NL80211_TID_CONFIG_ATTR_RETRY_SHORT,
2016 rdev->wiphy.tid_config_support.max_retry))
2017 goto fail;
2018 if (nla_put_u8(msg, NL80211_TID_CONFIG_ATTR_RETRY_LONG,
2019 rdev->wiphy.tid_config_support.max_retry))
2020 goto fail;
2021
Johannes Berg3710a8a2020-02-24 11:34:25 +01002022 nla_nest_end(msg, supp);
2023
2024 return 0;
2025fail:
2026 nla_nest_cancel(msg, supp);
2027 return -ENOBUFS;
2028}
2029
Johannes Berg86e8cf92013-06-19 10:57:22 +02002030struct nl80211_dump_wiphy_state {
2031 s64 filter_wiphy;
2032 long start;
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05302033 long split_start, band_start, chan_start, capa_start;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002034 bool split;
2035};
2036
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002037static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
Johannes Berg3bb20552014-05-26 13:52:25 +02002038 enum nl80211_commands cmd,
Johannes Berg3713b4e2013-02-14 16:19:38 +01002039 struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002040 int flags, struct nl80211_dump_wiphy_state *state)
Johannes Berg55682962007-09-20 13:09:35 -04002041{
2042 void *hdr;
Johannes Bergee688b002008-01-24 19:38:39 +01002043 struct nlattr *nl_bands, *nl_band;
2044 struct nlattr *nl_freqs, *nl_freq;
Johannes Berg8fdc6212009-03-14 09:34:01 +01002045 struct nlattr *nl_cmds;
Johannes Berg57fbcce2016-04-12 15:56:15 +02002046 enum nl80211_band band;
Johannes Bergee688b002008-01-24 19:38:39 +01002047 struct ieee80211_channel *chan;
Johannes Bergee688b002008-01-24 19:38:39 +01002048 int i;
Johannes Berg2e161f782010-08-12 15:38:38 +02002049 const struct ieee80211_txrx_stypes *mgmt_stypes =
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002050 rdev->wiphy.mgmt_stypes;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002051 u32 features;
Johannes Berg55682962007-09-20 13:09:35 -04002052
Johannes Berg3bb20552014-05-26 13:52:25 +02002053 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04002054 if (!hdr)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002055 return -ENOBUFS;
2056
Johannes Berg86e8cf92013-06-19 10:57:22 +02002057 if (WARN_ON(!state))
2058 return -EINVAL;
Johannes Berg55682962007-09-20 13:09:35 -04002059
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002060 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002061 nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002062 wiphy_name(&rdev->wiphy)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04002063 nla_put_u32(msg, NL80211_ATTR_GENERATION,
Johannes Berg3713b4e2013-02-14 16:19:38 +01002064 cfg80211_rdev_list_generation))
David S. Miller9360ffd2012-03-29 04:41:26 -04002065 goto nla_put_failure;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002066
Johannes Berg3bb20552014-05-26 13:52:25 +02002067 if (cmd != NL80211_CMD_NEW_WIPHY)
2068 goto finish;
2069
Johannes Berg86e8cf92013-06-19 10:57:22 +02002070 switch (state->split_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01002071 case 0:
2072 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002073 rdev->wiphy.retry_short) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002074 nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002075 rdev->wiphy.retry_long) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002076 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002077 rdev->wiphy.frag_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002078 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002079 rdev->wiphy.rts_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002080 nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002081 rdev->wiphy.coverage_class) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002082 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002083 rdev->wiphy.max_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002084 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002085 rdev->wiphy.max_sched_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002086 nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002087 rdev->wiphy.max_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002088 nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002089 rdev->wiphy.max_sched_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002090 nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
Avraham Stern3b06d272015-10-12 09:51:34 +03002091 rdev->wiphy.max_match_sets) ||
2092 nla_put_u32(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
2093 rdev->wiphy.max_sched_scan_plans) ||
2094 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
2095 rdev->wiphy.max_sched_scan_plan_interval) ||
2096 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
2097 rdev->wiphy.max_sched_scan_plan_iterations))
Johannes Bergee688b002008-01-24 19:38:39 +01002098 goto nla_put_failure;
2099
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002100 if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002101 nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
2102 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002103 if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002104 nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
2105 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002106 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002107 nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
2108 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002109 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002110 nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
2111 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002112 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002113 nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
2114 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002115 if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002116 nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
David S. Miller9360ffd2012-03-29 04:41:26 -04002117 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002118 state->split_start++;
2119 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002120 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002121 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002122 case 1:
2123 if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002124 sizeof(u32) * rdev->wiphy.n_cipher_suites,
2125 rdev->wiphy.cipher_suites))
Mahesh Palivelabf0c111e2012-06-22 07:27:46 +00002126 goto nla_put_failure;
2127
Johannes Berg3713b4e2013-02-14 16:19:38 +01002128 if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002129 rdev->wiphy.max_num_pmkids))
Johannes Bergee688b002008-01-24 19:38:39 +01002130 goto nla_put_failure;
2131
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002132 if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002133 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
2134 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01002135
Johannes Berg3713b4e2013-02-14 16:19:38 +01002136 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002137 rdev->wiphy.available_antennas_tx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002138 nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002139 rdev->wiphy.available_antennas_rx))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002140 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01002141
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002142 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002143 nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002144 rdev->wiphy.probe_resp_offload))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002145 goto nla_put_failure;
Jouni Malinene2f367f262008-11-21 19:01:30 +02002146
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002147 if ((rdev->wiphy.available_antennas_tx ||
2148 rdev->wiphy.available_antennas_rx) &&
2149 rdev->ops->get_antenna) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01002150 u32 tx_ant = 0, rx_ant = 0;
2151 int res;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07002152
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002153 res = rdev_get_antenna(rdev, &tx_ant, &rx_ant);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002154 if (!res) {
2155 if (nla_put_u32(msg,
2156 NL80211_ATTR_WIPHY_ANTENNA_TX,
2157 tx_ant) ||
2158 nla_put_u32(msg,
2159 NL80211_ATTR_WIPHY_ANTENNA_RX,
2160 rx_ant))
2161 goto nla_put_failure;
2162 }
Johannes Bergee688b002008-01-24 19:38:39 +01002163 }
2164
Johannes Berg86e8cf92013-06-19 10:57:22 +02002165 state->split_start++;
2166 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002167 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002168 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002169 case 2:
2170 if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002171 rdev->wiphy.interface_modes))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002172 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002173 state->split_start++;
2174 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002175 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002176 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002177 case 3:
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002178 nl_bands = nla_nest_start_noflag(msg,
2179 NL80211_ATTR_WIPHY_BANDS);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002180 if (!nl_bands)
Johannes Bergee688b002008-01-24 19:38:39 +01002181 goto nla_put_failure;
2182
Johannes Berg86e8cf92013-06-19 10:57:22 +02002183 for (band = state->band_start;
Johannes Berg57fbcce2016-04-12 15:56:15 +02002184 band < NUM_NL80211_BANDS; band++) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01002185 struct ieee80211_supported_band *sband;
2186
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002187 sband = rdev->wiphy.bands[band];
Johannes Berg3713b4e2013-02-14 16:19:38 +01002188
2189 if (!sband)
2190 continue;
2191
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002192 nl_band = nla_nest_start_noflag(msg, band);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002193 if (!nl_band)
Johannes Bergee688b002008-01-24 19:38:39 +01002194 goto nla_put_failure;
2195
Johannes Berg86e8cf92013-06-19 10:57:22 +02002196 switch (state->chan_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01002197 case 0:
2198 if (nl80211_send_band_rateinfo(msg, sband))
2199 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002200 state->chan_start++;
2201 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002202 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002203 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002204 default:
2205 /* add frequencies */
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002206 nl_freqs = nla_nest_start_noflag(msg,
2207 NL80211_BAND_ATTR_FREQS);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002208 if (!nl_freqs)
2209 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01002210
Johannes Berg86e8cf92013-06-19 10:57:22 +02002211 for (i = state->chan_start - 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002212 i < sband->n_channels;
2213 i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002214 nl_freq = nla_nest_start_noflag(msg,
2215 i);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002216 if (!nl_freq)
2217 goto nla_put_failure;
2218
2219 chan = &sband->channels[i];
2220
Johannes Berg86e8cf92013-06-19 10:57:22 +02002221 if (nl80211_msg_put_channel(
Haim Dreyfuss50f32712018-04-20 13:49:26 +03002222 msg, &rdev->wiphy, chan,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002223 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002224 goto nla_put_failure;
2225
2226 nla_nest_end(msg, nl_freq);
Johannes Berg86e8cf92013-06-19 10:57:22 +02002227 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002228 break;
2229 }
2230 if (i < sband->n_channels)
Johannes Berg86e8cf92013-06-19 10:57:22 +02002231 state->chan_start = i + 2;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002232 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02002233 state->chan_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002234 nla_nest_end(msg, nl_freqs);
2235 }
2236
2237 nla_nest_end(msg, nl_band);
2238
Johannes Berg86e8cf92013-06-19 10:57:22 +02002239 if (state->split) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01002240 /* start again here */
Johannes Berg86e8cf92013-06-19 10:57:22 +02002241 if (state->chan_start)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002242 band--;
2243 break;
2244 }
Johannes Bergee688b002008-01-24 19:38:39 +01002245 }
Johannes Berg3713b4e2013-02-14 16:19:38 +01002246 nla_nest_end(msg, nl_bands);
Johannes Bergee688b002008-01-24 19:38:39 +01002247
Johannes Berg57fbcce2016-04-12 15:56:15 +02002248 if (band < NUM_NL80211_BANDS)
Johannes Berg86e8cf92013-06-19 10:57:22 +02002249 state->band_start = band + 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002250 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02002251 state->band_start = 0;
Johannes Bergee688b002008-01-24 19:38:39 +01002252
Johannes Berg3713b4e2013-02-14 16:19:38 +01002253 /* if bands & channels are done, continue outside */
Johannes Berg86e8cf92013-06-19 10:57:22 +02002254 if (state->band_start == 0 && state->chan_start == 0)
2255 state->split_start++;
2256 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002257 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002258 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002259 case 4:
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002260 nl_cmds = nla_nest_start_noflag(msg,
2261 NL80211_ATTR_SUPPORTED_COMMANDS);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002262 if (!nl_cmds)
David S. Miller9360ffd2012-03-29 04:41:26 -04002263 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002264
Johannes Berg17948992016-10-26 11:42:04 +02002265 i = nl80211_add_commands_unsplit(rdev, msg);
2266 if (i < 0)
2267 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002268 if (state->split) {
Arend van Spriel5de17982013-04-18 15:49:00 +02002269 CMD(crit_proto_start, CRIT_PROTOCOL_START);
2270 CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002271 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02002272 CMD(channel_switch, CHANNEL_SWITCH);
Johannes Berg02df00e2014-06-10 14:06:25 +02002273 CMD(set_qos_map, SET_QOS_MAP);
Johannes Berg723e73a2014-10-22 09:25:06 +02002274 if (rdev->wiphy.features &
2275 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
Johannes Berg960d01a2014-09-09 22:55:35 +03002276 CMD(add_tx_ts, ADD_TX_TS);
Michael Braunce0ce132016-10-10 19:12:22 +02002277 CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
vamsi krishna088e8df2016-10-27 16:51:11 +03002278 CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
Matthew Wang70109982019-08-22 10:48:06 -07002279 CMD(update_ft_ies, UPDATE_FT_IES);
Arend van Spriel5de17982013-04-18 15:49:00 +02002280 }
Johannes Berg8fdc6212009-03-14 09:34:01 +01002281#undef CMD
Samuel Ortizb23aa672009-07-01 21:26:54 +02002282
Johannes Berg3713b4e2013-02-14 16:19:38 +01002283 nla_nest_end(msg, nl_cmds);
Johannes Berg86e8cf92013-06-19 10:57:22 +02002284 state->split_start++;
2285 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002286 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002287 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002288 case 5:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002289 if (rdev->ops->remain_on_channel &&
2290 (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002291 nla_put_u32(msg,
2292 NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002293 rdev->wiphy.max_remain_on_channel_duration))
Johannes Berg2e161f782010-08-12 15:38:38 +02002294 goto nla_put_failure;
2295
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002296 if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002297 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
2298 goto nla_put_failure;
Johannes Berg2e161f782010-08-12 15:38:38 +02002299
Johannes Berg3713b4e2013-02-14 16:19:38 +01002300 if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
2301 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002302 state->split_start++;
2303 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002304 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002305 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002306 case 6:
Johannes Bergdfb89c52012-06-27 09:23:48 +02002307#ifdef CONFIG_PM
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002308 if (nl80211_send_wowlan(msg, rdev, state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002309 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002310 state->split_start++;
2311 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002312 break;
2313#else
Johannes Berg86e8cf92013-06-19 10:57:22 +02002314 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002315#endif
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002316 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002317 case 7:
2318 if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002319 rdev->wiphy.software_iftypes))
Johannes Bergff1b6e62011-05-04 15:37:28 +02002320 goto nla_put_failure;
2321
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002322 if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002323 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002324 goto nla_put_failure;
Johannes Bergff1b6e62011-05-04 15:37:28 +02002325
Johannes Berg86e8cf92013-06-19 10:57:22 +02002326 state->split_start++;
2327 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002328 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002329 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002330 case 8:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002331 if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002332 nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002333 rdev->wiphy.ap_sme_capa))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002334 goto nla_put_failure;
2335
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002336 features = rdev->wiphy.features;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002337 /*
2338 * We can only add the per-channel limit information if the
2339 * dump is split, otherwise it makes it too big. Therefore
2340 * only advertise it in that case.
2341 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02002342 if (state->split)
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002343 features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
2344 if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002345 goto nla_put_failure;
2346
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002347 if (rdev->wiphy.ht_capa_mod_mask &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002348 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002349 sizeof(*rdev->wiphy.ht_capa_mod_mask),
2350 rdev->wiphy.ht_capa_mod_mask))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002351 goto nla_put_failure;
2352
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002353 if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
2354 rdev->wiphy.max_acl_mac_addrs &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002355 nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002356 rdev->wiphy.max_acl_mac_addrs))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002357 goto nla_put_failure;
2358
2359 /*
2360 * Any information below this point is only available to
2361 * applications that can deal with it being split. This
2362 * helps ensure that newly added capabilities don't break
2363 * older tools by overrunning their buffers.
2364 *
2365 * We still increment split_start so that in the split
2366 * case we'll continue with more data in the next round,
2367 * but break unconditionally so unsplit data stops here.
2368 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02002369 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002370 break;
2371 case 9:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002372 if (rdev->wiphy.extended_capabilities &&
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002373 (nla_put(msg, NL80211_ATTR_EXT_CAPA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002374 rdev->wiphy.extended_capabilities_len,
2375 rdev->wiphy.extended_capabilities) ||
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002376 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002377 rdev->wiphy.extended_capabilities_len,
2378 rdev->wiphy.extended_capabilities_mask)))
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002379 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002380
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002381 if (rdev->wiphy.vht_capa_mod_mask &&
Johannes Bergee2aca32013-02-21 17:36:01 +01002382 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002383 sizeof(*rdev->wiphy.vht_capa_mod_mask),
2384 rdev->wiphy.vht_capa_mod_mask))
Johannes Bergee2aca32013-02-21 17:36:01 +01002385 goto nla_put_failure;
2386
Denis Kenziorae6fa4d2019-07-22 06:33:12 -05002387 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
2388 rdev->wiphy.perm_addr))
2389 goto nla_put_failure;
2390
2391 if (!is_zero_ether_addr(rdev->wiphy.addr_mask) &&
2392 nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
2393 rdev->wiphy.addr_mask))
2394 goto nla_put_failure;
2395
2396 if (rdev->wiphy.n_addresses > 1) {
2397 void *attr;
2398
2399 attr = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
2400 if (!attr)
2401 goto nla_put_failure;
2402
2403 for (i = 0; i < rdev->wiphy.n_addresses; i++)
2404 if (nla_put(msg, i + 1, ETH_ALEN,
2405 rdev->wiphy.addresses[i].addr))
2406 goto nla_put_failure;
2407
2408 nla_nest_end(msg, attr);
2409 }
2410
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07002411 state->split_start++;
2412 break;
2413 case 10:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002414 if (nl80211_send_coalesce(msg, rdev))
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07002415 goto nla_put_failure;
2416
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002417 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
Felix Fietkau01e0daa2013-11-09 14:57:54 +01002418 (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
2419 nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
2420 goto nla_put_failure;
Jouni Malinenb43504c2014-01-15 00:01:08 +02002421
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002422 if (rdev->wiphy.max_ap_assoc_sta &&
Jouni Malinenb43504c2014-01-15 00:01:08 +02002423 nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002424 rdev->wiphy.max_ap_assoc_sta))
Jouni Malinenb43504c2014-01-15 00:01:08 +02002425 goto nla_put_failure;
2426
Johannes Bergad7e7182013-11-13 13:37:47 +01002427 state->split_start++;
2428 break;
2429 case 11:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002430 if (rdev->wiphy.n_vendor_commands) {
Johannes Berg567ffc32013-12-18 14:43:31 +01002431 const struct nl80211_vendor_cmd_info *info;
2432 struct nlattr *nested;
Johannes Bergad7e7182013-11-13 13:37:47 +01002433
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002434 nested = nla_nest_start_noflag(msg,
2435 NL80211_ATTR_VENDOR_DATA);
Johannes Berg567ffc32013-12-18 14:43:31 +01002436 if (!nested)
Johannes Bergad7e7182013-11-13 13:37:47 +01002437 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01002438
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002439 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
2440 info = &rdev->wiphy.vendor_commands[i].info;
Johannes Berg567ffc32013-12-18 14:43:31 +01002441 if (nla_put(msg, i + 1, sizeof(*info), info))
2442 goto nla_put_failure;
2443 }
2444 nla_nest_end(msg, nested);
2445 }
2446
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002447 if (rdev->wiphy.n_vendor_events) {
Johannes Berg567ffc32013-12-18 14:43:31 +01002448 const struct nl80211_vendor_cmd_info *info;
2449 struct nlattr *nested;
2450
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002451 nested = nla_nest_start_noflag(msg,
2452 NL80211_ATTR_VENDOR_EVENTS);
Johannes Berg567ffc32013-12-18 14:43:31 +01002453 if (!nested)
2454 goto nla_put_failure;
2455
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002456 for (i = 0; i < rdev->wiphy.n_vendor_events; i++) {
2457 info = &rdev->wiphy.vendor_events[i];
Johannes Berg567ffc32013-12-18 14:43:31 +01002458 if (nla_put(msg, i + 1, sizeof(*info), info))
2459 goto nla_put_failure;
2460 }
2461 nla_nest_end(msg, nested);
2462 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03002463 state->split_start++;
2464 break;
2465 case 12:
2466 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
2467 nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
2468 rdev->wiphy.max_num_csa_counters))
2469 goto nla_put_failure;
Felix Fietkau01e0daa2013-11-09 14:57:54 +01002470
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02002471 if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
2472 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
2473 goto nla_put_failure;
2474
Arend Van Sprielca986ad2017-04-21 13:05:00 +01002475 if (rdev->wiphy.max_sched_scan_reqs &&
2476 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_MAX_REQS,
2477 rdev->wiphy.max_sched_scan_reqs))
2478 goto nla_put_failure;
2479
Gautam Kumar Shuklad75bb062014-12-23 16:55:19 +01002480 if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
2481 sizeof(rdev->wiphy.ext_features),
2482 rdev->wiphy.ext_features))
2483 goto nla_put_failure;
2484
Arend van Spriel38de03d2016-03-02 20:37:18 +01002485 if (rdev->wiphy.bss_select_support) {
2486 struct nlattr *nested;
2487 u32 bss_select_support = rdev->wiphy.bss_select_support;
2488
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002489 nested = nla_nest_start_noflag(msg,
2490 NL80211_ATTR_BSS_SELECT);
Arend van Spriel38de03d2016-03-02 20:37:18 +01002491 if (!nested)
2492 goto nla_put_failure;
2493
2494 i = 0;
2495 while (bss_select_support) {
2496 if ((bss_select_support & 1) &&
2497 nla_put_flag(msg, i))
2498 goto nla_put_failure;
2499 i++;
2500 bss_select_support >>= 1;
2501 }
2502 nla_nest_end(msg, nested);
2503 }
2504
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05302505 state->split_start++;
2506 break;
2507 case 13:
2508 if (rdev->wiphy.num_iftype_ext_capab &&
2509 rdev->wiphy.iftype_ext_capab) {
2510 struct nlattr *nested_ext_capab, *nested;
2511
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002512 nested = nla_nest_start_noflag(msg,
2513 NL80211_ATTR_IFTYPE_EXT_CAPA);
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05302514 if (!nested)
2515 goto nla_put_failure;
2516
2517 for (i = state->capa_start;
2518 i < rdev->wiphy.num_iftype_ext_capab; i++) {
2519 const struct wiphy_iftype_ext_capab *capab;
2520
2521 capab = &rdev->wiphy.iftype_ext_capab[i];
2522
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002523 nested_ext_capab = nla_nest_start_noflag(msg,
2524 i);
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05302525 if (!nested_ext_capab ||
2526 nla_put_u32(msg, NL80211_ATTR_IFTYPE,
2527 capab->iftype) ||
2528 nla_put(msg, NL80211_ATTR_EXT_CAPA,
2529 capab->extended_capabilities_len,
2530 capab->extended_capabilities) ||
2531 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
2532 capab->extended_capabilities_len,
2533 capab->extended_capabilities_mask))
2534 goto nla_put_failure;
2535
2536 nla_nest_end(msg, nested_ext_capab);
2537 if (state->split)
2538 break;
2539 }
2540 nla_nest_end(msg, nested);
2541 if (i < rdev->wiphy.num_iftype_ext_capab) {
2542 state->capa_start = i + 1;
2543 break;
2544 }
2545 }
2546
Luca Coelho85859892017-02-08 15:00:34 +02002547 if (nla_put_u32(msg, NL80211_ATTR_BANDS,
2548 rdev->wiphy.nan_supported_bands))
2549 goto nla_put_failure;
2550
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02002551 if (wiphy_ext_feature_isset(&rdev->wiphy,
2552 NL80211_EXT_FEATURE_TXQS)) {
2553 struct cfg80211_txq_stats txqstats = {};
2554 int res;
2555
2556 res = rdev_get_txq_stats(rdev, NULL, &txqstats);
2557 if (!res &&
2558 !nl80211_put_txq_stats(msg, &txqstats,
2559 NL80211_ATTR_TXQ_STATS))
2560 goto nla_put_failure;
2561
2562 if (nla_put_u32(msg, NL80211_ATTR_TXQ_LIMIT,
2563 rdev->wiphy.txq_limit))
2564 goto nla_put_failure;
2565 if (nla_put_u32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT,
2566 rdev->wiphy.txq_memory_limit))
2567 goto nla_put_failure;
2568 if (nla_put_u32(msg, NL80211_ATTR_TXQ_QUANTUM,
2569 rdev->wiphy.txq_quantum))
2570 goto nla_put_failure;
2571 }
2572
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02002573 state->split_start++;
2574 break;
2575 case 14:
2576 if (nl80211_send_pmsr_capa(rdev, msg))
2577 goto nla_put_failure;
2578
Veerendranath Jakkamab4dfa22018-12-19 22:52:25 +05302579 state->split_start++;
2580 break;
2581 case 15:
2582 if (rdev->wiphy.akm_suites &&
2583 nla_put(msg, NL80211_ATTR_AKM_SUITES,
2584 sizeof(u32) * rdev->wiphy.n_akm_suites,
2585 rdev->wiphy.akm_suites))
2586 goto nla_put_failure;
2587
Veerendranath Jakkamd6039a32020-01-27 02:00:32 +05302588 if (nl80211_put_iftype_akm_suites(rdev, msg))
2589 goto nla_put_failure;
2590
Johannes Berg3710a8a2020-02-24 11:34:25 +01002591 if (nl80211_put_tid_config_support(rdev, msg))
2592 goto nla_put_failure;
2593
Johannes Berg3713b4e2013-02-14 16:19:38 +01002594 /* done */
Johannes Berg86e8cf92013-06-19 10:57:22 +02002595 state->split_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002596 break;
Johannes Bergff1b6e62011-05-04 15:37:28 +02002597 }
Johannes Berg3bb20552014-05-26 13:52:25 +02002598 finish:
Johannes Berg053c0952015-01-16 22:09:00 +01002599 genlmsg_end(msg, hdr);
2600 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002601
2602 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002603 genlmsg_cancel(msg, hdr);
2604 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04002605}
2606
Johannes Berg86e8cf92013-06-19 10:57:22 +02002607static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
2608 struct netlink_callback *cb,
2609 struct nl80211_dump_wiphy_state *state)
2610{
Johannes Berg50508d92019-07-29 16:31:09 +02002611 struct nlattr **tb = kcalloc(NUM_NL80211_ATTR, sizeof(*tb), GFP_KERNEL);
2612 int ret;
2613
2614 if (!tb)
2615 return -ENOMEM;
2616
2617 ret = nlmsg_parse_deprecated(cb->nlh,
2618 GENL_HDRLEN + nl80211_fam.hdrsize,
2619 tb, nl80211_fam.maxattr,
2620 nl80211_policy, NULL);
Johannes Berg86e8cf92013-06-19 10:57:22 +02002621 /* ignore parse errors for backward compatibility */
Johannes Berg50508d92019-07-29 16:31:09 +02002622 if (ret) {
2623 ret = 0;
2624 goto out;
2625 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002626
2627 state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
2628 if (tb[NL80211_ATTR_WIPHY])
2629 state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
2630 if (tb[NL80211_ATTR_WDEV])
2631 state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
2632 if (tb[NL80211_ATTR_IFINDEX]) {
2633 struct net_device *netdev;
2634 struct cfg80211_registered_device *rdev;
2635 int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2636
Ying Xue7f2b8562014-01-15 10:23:45 +08002637 netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
Johannes Berg50508d92019-07-29 16:31:09 +02002638 if (!netdev) {
2639 ret = -ENODEV;
2640 goto out;
2641 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002642 if (netdev->ieee80211_ptr) {
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002643 rdev = wiphy_to_rdev(
Johannes Berg86e8cf92013-06-19 10:57:22 +02002644 netdev->ieee80211_ptr->wiphy);
2645 state->filter_wiphy = rdev->wiphy_idx;
2646 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002647 }
2648
Johannes Berg50508d92019-07-29 16:31:09 +02002649 ret = 0;
2650out:
2651 kfree(tb);
2652 return ret;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002653}
2654
Johannes Berg55682962007-09-20 13:09:35 -04002655static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
2656{
Johannes Berg645e77d2013-03-01 14:03:49 +01002657 int idx = 0, ret;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002658 struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002659 struct cfg80211_registered_device *rdev;
Johannes Berg3a5a4232013-06-19 10:09:57 +02002660
Johannes Berg5fe231e2013-05-08 21:45:15 +02002661 rtnl_lock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02002662 if (!state) {
2663 state = kzalloc(sizeof(*state), GFP_KERNEL);
John W. Linville57ed5cd2013-06-28 13:18:21 -04002664 if (!state) {
2665 rtnl_unlock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02002666 return -ENOMEM;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002667 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002668 state->filter_wiphy = -1;
2669 ret = nl80211_dump_wiphy_parse(skb, cb, state);
2670 if (ret) {
2671 kfree(state);
2672 rtnl_unlock();
2673 return ret;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002674 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002675 cb->args[0] = (long)state;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002676 }
2677
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002678 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2679 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02002680 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002681 if (++idx <= state->start)
Johannes Berg55682962007-09-20 13:09:35 -04002682 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002683 if (state->filter_wiphy != -1 &&
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002684 state->filter_wiphy != rdev->wiphy_idx)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002685 continue;
2686 /* attempt to fit multiple wiphy data chunks into the skb */
2687 do {
Johannes Berg3bb20552014-05-26 13:52:25 +02002688 ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY,
2689 skb,
Johannes Berg3713b4e2013-02-14 16:19:38 +01002690 NETLINK_CB(cb->skb).portid,
2691 cb->nlh->nlmsg_seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002692 NLM_F_MULTI, state);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002693 if (ret < 0) {
2694 /*
2695 * If sending the wiphy data didn't fit (ENOBUFS
2696 * or EMSGSIZE returned), this SKB is still
2697 * empty (so it's not too big because another
2698 * wiphy dataset is already in the skb) and
2699 * we've not tried to adjust the dump allocation
2700 * yet ... then adjust the alloc size to be
2701 * bigger, and return 1 but with the empty skb.
2702 * This results in an empty message being RX'ed
2703 * in userspace, but that is ignored.
2704 *
2705 * We can then retry with the larger buffer.
2706 */
2707 if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
Pontus Fuchsf12cb282014-01-16 15:00:40 +01002708 !skb->len && !state->split &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002709 cb->min_dump_alloc < 4096) {
2710 cb->min_dump_alloc = 4096;
Pontus Fuchsf12cb282014-01-16 15:00:40 +01002711 state->split_start = 0;
David S. Millerd98cae64e2013-06-19 16:49:39 -07002712 rtnl_unlock();
Johannes Berg3713b4e2013-02-14 16:19:38 +01002713 return 1;
2714 }
2715 idx--;
2716 break;
Johannes Berg645e77d2013-03-01 14:03:49 +01002717 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002718 } while (state->split_start > 0);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002719 break;
Johannes Berg55682962007-09-20 13:09:35 -04002720 }
Johannes Berg5fe231e2013-05-08 21:45:15 +02002721 rtnl_unlock();
Johannes Berg55682962007-09-20 13:09:35 -04002722
Johannes Berg86e8cf92013-06-19 10:57:22 +02002723 state->start = idx;
Johannes Berg55682962007-09-20 13:09:35 -04002724
2725 return skb->len;
2726}
2727
Johannes Berg86e8cf92013-06-19 10:57:22 +02002728static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
2729{
2730 kfree((void *)cb->args[0]);
2731 return 0;
2732}
2733
Johannes Berg55682962007-09-20 13:09:35 -04002734static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
2735{
2736 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002737 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg86e8cf92013-06-19 10:57:22 +02002738 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -04002739
Johannes Berg645e77d2013-03-01 14:03:49 +01002740 msg = nlmsg_new(4096, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002741 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002742 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002743
Johannes Berg3bb20552014-05-26 13:52:25 +02002744 if (nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY, msg,
2745 info->snd_portid, info->snd_seq, 0,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002746 &state) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002747 nlmsg_free(msg);
2748 return -ENOBUFS;
2749 }
Johannes Berg55682962007-09-20 13:09:35 -04002750
Johannes Berg134e6372009-07-10 09:51:34 +00002751 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002752}
2753
Jouni Malinen31888482008-10-30 16:59:24 +02002754static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
2755 [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 },
2756 [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 },
2757 [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 },
2758 [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 },
2759 [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 },
2760};
2761
2762static int parse_txq_params(struct nlattr *tb[],
2763 struct ieee80211_txq_params *txq_params)
2764{
Dan Williams259d8c12018-01-29 17:03:15 -08002765 u8 ac;
2766
Johannes Berga3304b02012-03-28 11:04:24 +02002767 if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
Jouni Malinen31888482008-10-30 16:59:24 +02002768 !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
2769 !tb[NL80211_TXQ_ATTR_AIFS])
2770 return -EINVAL;
2771
Dan Williams259d8c12018-01-29 17:03:15 -08002772 ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
Jouni Malinen31888482008-10-30 16:59:24 +02002773 txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
2774 txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
2775 txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
2776 txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
2777
Dan Williams259d8c12018-01-29 17:03:15 -08002778 if (ac >= NL80211_NUM_ACS)
Johannes Berga3304b02012-03-28 11:04:24 +02002779 return -EINVAL;
Dan Williams259d8c12018-01-29 17:03:15 -08002780 txq_params->ac = array_index_nospec(ac, NL80211_NUM_ACS);
Jouni Malinen31888482008-10-30 16:59:24 +02002781 return 0;
2782}
2783
Johannes Bergf444de02010-05-05 15:25:02 +02002784static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
2785{
2786 /*
Johannes Bergcc1d2802012-05-16 23:50:20 +02002787 * You can only set the channel explicitly for WDS interfaces,
2788 * all others have their channel managed via their respective
2789 * "establish a connection" command (connect, join, ...)
2790 *
2791 * For AP/GO and mesh mode, the channel can be set with the
2792 * channel userspace API, but is only stored and passed to the
2793 * low-level driver when the AP starts or the mesh is joined.
2794 * This is for backward compatibility, userspace can also give
2795 * the channel in the start-ap or join-mesh commands instead.
Johannes Bergf444de02010-05-05 15:25:02 +02002796 *
2797 * Monitors are special as they are normally slaved to
Johannes Berge8c9bd52012-06-06 08:18:22 +02002798 * whatever else is going on, so they have their own special
2799 * operation to set the monitor channel if possible.
Johannes Bergf444de02010-05-05 15:25:02 +02002800 */
2801 return !wdev ||
2802 wdev->iftype == NL80211_IFTYPE_AP ||
Johannes Bergf444de02010-05-05 15:25:02 +02002803 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
Johannes Berg074ac8d2010-09-16 14:58:22 +02002804 wdev->iftype == NL80211_IFTYPE_MONITOR ||
2805 wdev->iftype == NL80211_IFTYPE_P2P_GO;
Johannes Bergf444de02010-05-05 15:25:02 +02002806}
2807
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02002808int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
2809 struct genl_info *info,
2810 struct cfg80211_chan_def *chandef)
Johannes Berg683b6d32012-11-08 21:25:48 +01002811{
Johannes Berg49f9cf02018-10-01 11:55:09 +02002812 struct netlink_ext_ack *extack = info->extack;
2813 struct nlattr **attrs = info->attrs;
Mahesh Paliveladbeca2e2012-11-29 14:11:07 +05302814 u32 control_freq;
Johannes Berg683b6d32012-11-08 21:25:48 +01002815
Johannes Berg49f9cf02018-10-01 11:55:09 +02002816 if (!attrs[NL80211_ATTR_WIPHY_FREQ])
Johannes Berg683b6d32012-11-08 21:25:48 +01002817 return -EINVAL;
2818
Thomas Pedersen942ba882020-04-30 10:25:51 -07002819 control_freq = MHZ_TO_KHZ(
2820 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
2821 if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
2822 control_freq +=
2823 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
Johannes Berg683b6d32012-11-08 21:25:48 +01002824
Johannes Bergf43e5212019-09-23 13:51:16 +02002825 memset(chandef, 0, sizeof(*chandef));
Thomas Pedersen942ba882020-04-30 10:25:51 -07002826 chandef->chan = ieee80211_get_channel_khz(&rdev->wiphy, control_freq);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002827 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
Thomas Pedersen942ba882020-04-30 10:25:51 -07002828 chandef->center_freq1 = KHZ_TO_MHZ(control_freq);
2829 chandef->freq1_offset = control_freq % 1000;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002830 chandef->center_freq2 = 0;
Johannes Berg683b6d32012-11-08 21:25:48 +01002831
2832 /* Primary channel not allowed */
Johannes Berg49f9cf02018-10-01 11:55:09 +02002833 if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) {
2834 NL_SET_ERR_MSG_ATTR(extack, attrs[NL80211_ATTR_WIPHY_FREQ],
2835 "Channel is disabled");
Johannes Berg683b6d32012-11-08 21:25:48 +01002836 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02002837 }
Johannes Berg683b6d32012-11-08 21:25:48 +01002838
Johannes Berg49f9cf02018-10-01 11:55:09 +02002839 if (attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002840 enum nl80211_channel_type chantype;
Johannes Berg683b6d32012-11-08 21:25:48 +01002841
Johannes Berg49f9cf02018-10-01 11:55:09 +02002842 chantype = nla_get_u32(attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002843
2844 switch (chantype) {
2845 case NL80211_CHAN_NO_HT:
2846 case NL80211_CHAN_HT20:
2847 case NL80211_CHAN_HT40PLUS:
2848 case NL80211_CHAN_HT40MINUS:
2849 cfg80211_chandef_create(chandef, chandef->chan,
2850 chantype);
Tova Mussaiffa46292017-08-05 11:44:38 +03002851 /* user input for center_freq is incorrect */
Johannes Berg49f9cf02018-10-01 11:55:09 +02002852 if (attrs[NL80211_ATTR_CENTER_FREQ1] &&
2853 chandef->center_freq1 != nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1])) {
2854 NL_SET_ERR_MSG_ATTR(extack,
2855 attrs[NL80211_ATTR_CENTER_FREQ1],
2856 "bad center frequency 1");
Tova Mussaiffa46292017-08-05 11:44:38 +03002857 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02002858 }
Tova Mussaiffa46292017-08-05 11:44:38 +03002859 /* center_freq2 must be zero */
Johannes Berg49f9cf02018-10-01 11:55:09 +02002860 if (attrs[NL80211_ATTR_CENTER_FREQ2] &&
2861 nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2])) {
2862 NL_SET_ERR_MSG_ATTR(extack,
2863 attrs[NL80211_ATTR_CENTER_FREQ2],
2864 "center frequency 2 can't be used");
Tova Mussaiffa46292017-08-05 11:44:38 +03002865 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02002866 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002867 break;
2868 default:
Johannes Berg49f9cf02018-10-01 11:55:09 +02002869 NL_SET_ERR_MSG_ATTR(extack,
2870 attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
2871 "invalid channel type");
Johannes Berg683b6d32012-11-08 21:25:48 +01002872 return -EINVAL;
Johannes Berg683b6d32012-11-08 21:25:48 +01002873 }
Johannes Berg49f9cf02018-10-01 11:55:09 +02002874 } else if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002875 chandef->width =
Johannes Berg49f9cf02018-10-01 11:55:09 +02002876 nla_get_u32(attrs[NL80211_ATTR_CHANNEL_WIDTH]);
Thomas Pedersen942ba882020-04-30 10:25:51 -07002877 if (attrs[NL80211_ATTR_CENTER_FREQ1]) {
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002878 chandef->center_freq1 =
Johannes Berg49f9cf02018-10-01 11:55:09 +02002879 nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1]);
Thomas Pedersen942ba882020-04-30 10:25:51 -07002880 if (attrs[NL80211_ATTR_CENTER_FREQ1_OFFSET])
2881 chandef->freq1_offset = nla_get_u32(
2882 attrs[NL80211_ATTR_CENTER_FREQ1_OFFSET]);
2883 else
2884 chandef->freq1_offset = 0;
2885 }
Johannes Berg49f9cf02018-10-01 11:55:09 +02002886 if (attrs[NL80211_ATTR_CENTER_FREQ2])
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002887 chandef->center_freq2 =
Johannes Berg49f9cf02018-10-01 11:55:09 +02002888 nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2]);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002889 }
2890
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +03002891 if (info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]) {
2892 chandef->edmg.channels =
2893 nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]);
2894
2895 if (info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG])
2896 chandef->edmg.bw_config =
2897 nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG]);
2898 } else {
2899 chandef->edmg.bw_config = 0;
2900 chandef->edmg.channels = 0;
2901 }
2902
Johannes Berg49f9cf02018-10-01 11:55:09 +02002903 if (!cfg80211_chandef_valid(chandef)) {
2904 NL_SET_ERR_MSG(extack, "invalid channel definition");
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002905 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02002906 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002907
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002908 if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
Johannes Berg49f9cf02018-10-01 11:55:09 +02002909 IEEE80211_CHAN_DISABLED)) {
2910 NL_SET_ERR_MSG(extack, "(extension) channel is disabled");
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002911 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02002912 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002913
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02002914 if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
2915 chandef->width == NL80211_CHAN_WIDTH_10) &&
Johannes Berg49f9cf02018-10-01 11:55:09 +02002916 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ)) {
2917 NL_SET_ERR_MSG(extack, "5/10 MHz not supported");
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02002918 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02002919 }
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02002920
Johannes Berg683b6d32012-11-08 21:25:48 +01002921 return 0;
2922}
2923
Johannes Bergf444de02010-05-05 15:25:02 +02002924static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
Jouni Malinene16821b2014-04-28 11:22:08 +03002925 struct net_device *dev,
Johannes Bergf444de02010-05-05 15:25:02 +02002926 struct genl_info *info)
2927{
Johannes Berg683b6d32012-11-08 21:25:48 +01002928 struct cfg80211_chan_def chandef;
Johannes Bergf444de02010-05-05 15:25:02 +02002929 int result;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002930 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
Jouni Malinene16821b2014-04-28 11:22:08 +03002931 struct wireless_dev *wdev = NULL;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002932
Jouni Malinene16821b2014-04-28 11:22:08 +03002933 if (dev)
2934 wdev = dev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002935 if (!nl80211_can_set_dev_channel(wdev))
2936 return -EOPNOTSUPP;
Jouni Malinene16821b2014-04-28 11:22:08 +03002937 if (wdev)
2938 iftype = wdev->iftype;
Johannes Bergf444de02010-05-05 15:25:02 +02002939
Johannes Berg683b6d32012-11-08 21:25:48 +01002940 result = nl80211_parse_chandef(rdev, info, &chandef);
2941 if (result)
2942 return result;
Johannes Bergf444de02010-05-05 15:25:02 +02002943
Johannes Berge8c9bd52012-06-06 08:18:22 +02002944 switch (iftype) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002945 case NL80211_IFTYPE_AP:
2946 case NL80211_IFTYPE_P2P_GO:
Arik Nemtsov923b3522015-07-08 15:41:44 +03002947 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
2948 iftype)) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002949 result = -EINVAL;
2950 break;
2951 }
Jouni Malinene16821b2014-04-28 11:22:08 +03002952 if (wdev->beacon_interval) {
2953 if (!dev || !rdev->ops->set_ap_chanwidth ||
2954 !(rdev->wiphy.features &
2955 NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
2956 result = -EBUSY;
2957 break;
2958 }
2959
2960 /* Only allow dynamic channel width changes */
2961 if (chandef.chan != wdev->preset_chandef.chan) {
2962 result = -EBUSY;
2963 break;
2964 }
2965 result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
2966 if (result)
2967 break;
2968 }
Johannes Berg683b6d32012-11-08 21:25:48 +01002969 wdev->preset_chandef = chandef;
Johannes Bergaa430da2012-05-16 23:50:18 +02002970 result = 0;
2971 break;
Johannes Bergcc1d2802012-05-16 23:50:20 +02002972 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg683b6d32012-11-08 21:25:48 +01002973 result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
Johannes Bergcc1d2802012-05-16 23:50:20 +02002974 break;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002975 case NL80211_IFTYPE_MONITOR:
Johannes Berg683b6d32012-11-08 21:25:48 +01002976 result = cfg80211_set_monitor_channel(rdev, &chandef);
Johannes Berge8c9bd52012-06-06 08:18:22 +02002977 break;
Johannes Bergaa430da2012-05-16 23:50:18 +02002978 default:
Johannes Berge8c9bd52012-06-06 08:18:22 +02002979 result = -EINVAL;
Johannes Bergf444de02010-05-05 15:25:02 +02002980 }
Johannes Bergf444de02010-05-05 15:25:02 +02002981
2982 return result;
2983}
2984
2985static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
2986{
Johannes Berg4c476992010-10-04 21:36:35 +02002987 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2988 struct net_device *netdev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02002989
Jouni Malinene16821b2014-04-28 11:22:08 +03002990 return __nl80211_set_channel(rdev, netdev, info);
Johannes Bergf444de02010-05-05 15:25:02 +02002991}
2992
Bill Jordane8347eb2010-10-01 13:54:28 -04002993static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
2994{
Johannes Berg43b19952010-10-07 13:10:30 +02002995 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2996 struct net_device *dev = info->user_ptr[1];
2997 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg388ac772010-10-07 13:11:09 +02002998 const u8 *bssid;
Bill Jordane8347eb2010-10-01 13:54:28 -04002999
3000 if (!info->attrs[NL80211_ATTR_MAC])
3001 return -EINVAL;
3002
Johannes Berg43b19952010-10-07 13:10:30 +02003003 if (netif_running(dev))
3004 return -EBUSY;
Bill Jordane8347eb2010-10-01 13:54:28 -04003005
Johannes Berg43b19952010-10-07 13:10:30 +02003006 if (!rdev->ops->set_wds_peer)
3007 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04003008
Johannes Berg43b19952010-10-07 13:10:30 +02003009 if (wdev->iftype != NL80211_IFTYPE_WDS)
3010 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04003011
3012 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Hila Gonene35e4d22012-06-27 17:19:42 +03003013 return rdev_set_wds_peer(rdev, dev, bssid);
Bill Jordane8347eb2010-10-01 13:54:28 -04003014}
3015
Johannes Berg55682962007-09-20 13:09:35 -04003016static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
3017{
3018 struct cfg80211_registered_device *rdev;
Johannes Bergf444de02010-05-05 15:25:02 +02003019 struct net_device *netdev = NULL;
3020 struct wireless_dev *wdev;
Bill Jordana1e567c2010-09-10 11:22:32 -04003021 int result = 0, rem_txq_params = 0;
Jouni Malinen31888482008-10-30 16:59:24 +02003022 struct nlattr *nl_txq_params;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003023 u32 changed;
3024 u8 retry_short = 0, retry_long = 0;
3025 u32 frag_threshold = 0, rts_threshold = 0;
Lukáš Turek81077e82009-12-21 22:50:47 +01003026 u8 coverage_class = 0;
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003027 u32 txq_limit = 0, txq_memory_limit = 0, txq_quantum = 0;
Johannes Berg55682962007-09-20 13:09:35 -04003028
Johannes Berg5fe231e2013-05-08 21:45:15 +02003029 ASSERT_RTNL();
3030
Johannes Bergf444de02010-05-05 15:25:02 +02003031 /*
3032 * Try to find the wiphy and netdev. Normally this
3033 * function shouldn't need the netdev, but this is
3034 * done for backward compatibility -- previously
3035 * setting the channel was done per wiphy, but now
3036 * it is per netdev. Previous userland like hostapd
3037 * also passed a netdev to set_wiphy, so that it is
3038 * possible to let that go to the right netdev!
3039 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01003040
Johannes Bergf444de02010-05-05 15:25:02 +02003041 if (info->attrs[NL80211_ATTR_IFINDEX]) {
3042 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
3043
Ying Xue7f2b8562014-01-15 10:23:45 +08003044 netdev = __dev_get_by_index(genl_info_net(info), ifindex);
Johannes Berg5fe231e2013-05-08 21:45:15 +02003045 if (netdev && netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +08003046 rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
Johannes Berg5fe231e2013-05-08 21:45:15 +02003047 else
Johannes Bergf444de02010-05-05 15:25:02 +02003048 netdev = NULL;
Johannes Berg4bbf4d52009-03-24 09:35:46 +01003049 }
3050
Johannes Bergf444de02010-05-05 15:25:02 +02003051 if (!netdev) {
Johannes Berg878d9ec2012-06-15 14:18:32 +02003052 rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
3053 info->attrs);
Johannes Berg5fe231e2013-05-08 21:45:15 +02003054 if (IS_ERR(rdev))
Johannes Berg4c476992010-10-04 21:36:35 +02003055 return PTR_ERR(rdev);
Johannes Bergf444de02010-05-05 15:25:02 +02003056 wdev = NULL;
3057 netdev = NULL;
3058 result = 0;
Johannes Berg71fe96b2012-10-24 10:04:58 +02003059 } else
Johannes Bergf444de02010-05-05 15:25:02 +02003060 wdev = netdev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02003061
3062 /*
3063 * end workaround code, by now the rdev is available
3064 * and locked, and wdev may or may not be NULL.
3065 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01003066
3067 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
Jouni Malinen31888482008-10-30 16:59:24 +02003068 result = cfg80211_dev_rename(
3069 rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
Johannes Berg4bbf4d52009-03-24 09:35:46 +01003070
Johannes Berg4bbf4d52009-03-24 09:35:46 +01003071 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08003072 return result;
Johannes Berg55682962007-09-20 13:09:35 -04003073
Jouni Malinen31888482008-10-30 16:59:24 +02003074 if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
3075 struct ieee80211_txq_params txq_params;
3076 struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
3077
Ying Xue7f2b8562014-01-15 10:23:45 +08003078 if (!rdev->ops->set_txq_params)
3079 return -EOPNOTSUPP;
Jouni Malinen31888482008-10-30 16:59:24 +02003080
Ying Xue7f2b8562014-01-15 10:23:45 +08003081 if (!netdev)
3082 return -EINVAL;
Eliad Pellerf70f01c2011-09-25 20:06:53 +03003083
Johannes Berg133a3ff2011-11-03 14:50:13 +01003084 if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Ying Xue7f2b8562014-01-15 10:23:45 +08003085 netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3086 return -EINVAL;
Johannes Berg133a3ff2011-11-03 14:50:13 +01003087
Ying Xue7f2b8562014-01-15 10:23:45 +08003088 if (!netif_running(netdev))
3089 return -ENETDOWN;
Johannes Berg2b5f8b02012-04-02 10:51:55 +02003090
Jouni Malinen31888482008-10-30 16:59:24 +02003091 nla_for_each_nested(nl_txq_params,
3092 info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
3093 rem_txq_params) {
Johannes Berg8cb08172019-04-26 14:07:28 +02003094 result = nla_parse_nested_deprecated(tb,
3095 NL80211_TXQ_ATTR_MAX,
3096 nl_txq_params,
3097 txq_params_policy,
3098 info->extack);
Johannes Bergae811e22014-01-24 10:17:47 +01003099 if (result)
3100 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02003101 result = parse_txq_params(tb, &txq_params);
3102 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08003103 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02003104
Hila Gonene35e4d22012-06-27 17:19:42 +03003105 result = rdev_set_txq_params(rdev, netdev,
3106 &txq_params);
Jouni Malinen31888482008-10-30 16:59:24 +02003107 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08003108 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02003109 }
3110 }
3111
Jouni Malinen72bdcf32008-11-26 16:15:24 +02003112 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinene16821b2014-04-28 11:22:08 +03003113 result = __nl80211_set_channel(
3114 rdev,
3115 nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
3116 info);
Jouni Malinen72bdcf32008-11-26 16:15:24 +02003117 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08003118 return result;
Jouni Malinen72bdcf32008-11-26 16:15:24 +02003119 }
3120
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003121 if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
Johannes Bergc8442112012-10-24 10:17:18 +02003122 struct wireless_dev *txp_wdev = wdev;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003123 enum nl80211_tx_power_setting type;
3124 int idx, mbm = 0;
3125
Johannes Bergc8442112012-10-24 10:17:18 +02003126 if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
3127 txp_wdev = NULL;
3128
Ying Xue7f2b8562014-01-15 10:23:45 +08003129 if (!rdev->ops->set_tx_power)
3130 return -EOPNOTSUPP;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003131
3132 idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
3133 type = nla_get_u32(info->attrs[idx]);
3134
3135 if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
Ying Xue7f2b8562014-01-15 10:23:45 +08003136 (type != NL80211_TX_POWER_AUTOMATIC))
3137 return -EINVAL;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003138
3139 if (type != NL80211_TX_POWER_AUTOMATIC) {
3140 idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
3141 mbm = nla_get_u32(info->attrs[idx]);
3142 }
3143
Johannes Bergc8442112012-10-24 10:17:18 +02003144 result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003145 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08003146 return result;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003147 }
3148
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09003149 if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
3150 info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
3151 u32 tx_ant, rx_ant;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07003152
Bruno Randolf7f531e02010-12-16 11:30:22 +09003153 if ((!rdev->wiphy.available_antennas_tx &&
3154 !rdev->wiphy.available_antennas_rx) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08003155 !rdev->ops->set_antenna)
3156 return -EOPNOTSUPP;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09003157
3158 tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
3159 rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
3160
Bruno Randolfa7ffac92010-12-08 13:59:24 +09003161 /* reject antenna configurations which don't match the
Bruno Randolf7f531e02010-12-16 11:30:22 +09003162 * available antenna masks, except for the "all" mask */
3163 if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08003164 (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
3165 return -EINVAL;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09003166
Bruno Randolf7f531e02010-12-16 11:30:22 +09003167 tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
3168 rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09003169
Hila Gonene35e4d22012-06-27 17:19:42 +03003170 result = rdev_set_antenna(rdev, tx_ant, rx_ant);
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09003171 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08003172 return result;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09003173 }
3174
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003175 changed = 0;
3176
3177 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
3178 retry_short = nla_get_u8(
3179 info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
Ying Xue7f2b8562014-01-15 10:23:45 +08003180
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003181 changed |= WIPHY_PARAM_RETRY_SHORT;
3182 }
3183
3184 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
3185 retry_long = nla_get_u8(
3186 info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
Ying Xue7f2b8562014-01-15 10:23:45 +08003187
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003188 changed |= WIPHY_PARAM_RETRY_LONG;
3189 }
3190
3191 if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
3192 frag_threshold = nla_get_u32(
3193 info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
Ying Xue7f2b8562014-01-15 10:23:45 +08003194 if (frag_threshold < 256)
3195 return -EINVAL;
3196
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003197 if (frag_threshold != (u32) -1) {
3198 /*
3199 * Fragments (apart from the last one) are required to
3200 * have even length. Make the fragmentation code
3201 * simpler by stripping LSB should someone try to use
3202 * odd threshold value.
3203 */
3204 frag_threshold &= ~0x1;
3205 }
3206 changed |= WIPHY_PARAM_FRAG_THRESHOLD;
3207 }
3208
3209 if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
3210 rts_threshold = nla_get_u32(
3211 info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
3212 changed |= WIPHY_PARAM_RTS_THRESHOLD;
3213 }
3214
Lukáš Turek81077e82009-12-21 22:50:47 +01003215 if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02003216 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK])
3217 return -EINVAL;
3218
Lukáš Turek81077e82009-12-21 22:50:47 +01003219 coverage_class = nla_get_u8(
3220 info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
3221 changed |= WIPHY_PARAM_COVERAGE_CLASS;
3222 }
3223
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02003224 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
3225 if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION))
3226 return -EOPNOTSUPP;
3227
3228 changed |= WIPHY_PARAM_DYN_ACK;
3229 }
3230
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003231 if (info->attrs[NL80211_ATTR_TXQ_LIMIT]) {
3232 if (!wiphy_ext_feature_isset(&rdev->wiphy,
3233 NL80211_EXT_FEATURE_TXQS))
3234 return -EOPNOTSUPP;
3235 txq_limit = nla_get_u32(
3236 info->attrs[NL80211_ATTR_TXQ_LIMIT]);
3237 changed |= WIPHY_PARAM_TXQ_LIMIT;
3238 }
3239
3240 if (info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]) {
3241 if (!wiphy_ext_feature_isset(&rdev->wiphy,
3242 NL80211_EXT_FEATURE_TXQS))
3243 return -EOPNOTSUPP;
3244 txq_memory_limit = nla_get_u32(
3245 info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]);
3246 changed |= WIPHY_PARAM_TXQ_MEMORY_LIMIT;
3247 }
3248
3249 if (info->attrs[NL80211_ATTR_TXQ_QUANTUM]) {
3250 if (!wiphy_ext_feature_isset(&rdev->wiphy,
3251 NL80211_EXT_FEATURE_TXQS))
3252 return -EOPNOTSUPP;
3253 txq_quantum = nla_get_u32(
3254 info->attrs[NL80211_ATTR_TXQ_QUANTUM]);
3255 changed |= WIPHY_PARAM_TXQ_QUANTUM;
3256 }
3257
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003258 if (changed) {
3259 u8 old_retry_short, old_retry_long;
3260 u32 old_frag_threshold, old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01003261 u8 old_coverage_class;
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003262 u32 old_txq_limit, old_txq_memory_limit, old_txq_quantum;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003263
Ying Xue7f2b8562014-01-15 10:23:45 +08003264 if (!rdev->ops->set_wiphy_params)
3265 return -EOPNOTSUPP;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003266
3267 old_retry_short = rdev->wiphy.retry_short;
3268 old_retry_long = rdev->wiphy.retry_long;
3269 old_frag_threshold = rdev->wiphy.frag_threshold;
3270 old_rts_threshold = rdev->wiphy.rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01003271 old_coverage_class = rdev->wiphy.coverage_class;
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003272 old_txq_limit = rdev->wiphy.txq_limit;
3273 old_txq_memory_limit = rdev->wiphy.txq_memory_limit;
3274 old_txq_quantum = rdev->wiphy.txq_quantum;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003275
3276 if (changed & WIPHY_PARAM_RETRY_SHORT)
3277 rdev->wiphy.retry_short = retry_short;
3278 if (changed & WIPHY_PARAM_RETRY_LONG)
3279 rdev->wiphy.retry_long = retry_long;
3280 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
3281 rdev->wiphy.frag_threshold = frag_threshold;
3282 if (changed & WIPHY_PARAM_RTS_THRESHOLD)
3283 rdev->wiphy.rts_threshold = rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01003284 if (changed & WIPHY_PARAM_COVERAGE_CLASS)
3285 rdev->wiphy.coverage_class = coverage_class;
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003286 if (changed & WIPHY_PARAM_TXQ_LIMIT)
3287 rdev->wiphy.txq_limit = txq_limit;
3288 if (changed & WIPHY_PARAM_TXQ_MEMORY_LIMIT)
3289 rdev->wiphy.txq_memory_limit = txq_memory_limit;
3290 if (changed & WIPHY_PARAM_TXQ_QUANTUM)
3291 rdev->wiphy.txq_quantum = txq_quantum;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003292
Hila Gonene35e4d22012-06-27 17:19:42 +03003293 result = rdev_set_wiphy_params(rdev, changed);
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003294 if (result) {
3295 rdev->wiphy.retry_short = old_retry_short;
3296 rdev->wiphy.retry_long = old_retry_long;
3297 rdev->wiphy.frag_threshold = old_frag_threshold;
3298 rdev->wiphy.rts_threshold = old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01003299 rdev->wiphy.coverage_class = old_coverage_class;
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003300 rdev->wiphy.txq_limit = old_txq_limit;
3301 rdev->wiphy.txq_memory_limit = old_txq_memory_limit;
3302 rdev->wiphy.txq_quantum = old_txq_quantum;
Michal Kazior9189ee32015-08-03 10:55:24 +02003303 return result;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003304 }
3305 }
Ying Xue7f2b8562014-01-15 10:23:45 +08003306 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04003307}
3308
Johannes Berg683b6d32012-11-08 21:25:48 +01003309static int nl80211_send_chandef(struct sk_buff *msg,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01003310 const struct cfg80211_chan_def *chandef)
Johannes Berg683b6d32012-11-08 21:25:48 +01003311{
Johannes Berg601555c2014-11-27 17:26:56 +01003312 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
3313 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003314
Johannes Berg683b6d32012-11-08 21:25:48 +01003315 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
3316 chandef->chan->center_freq))
3317 return -ENOBUFS;
Thomas Pedersen942ba882020-04-30 10:25:51 -07003318 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET,
3319 chandef->chan->freq_offset))
3320 return -ENOBUFS;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003321 switch (chandef->width) {
3322 case NL80211_CHAN_WIDTH_20_NOHT:
3323 case NL80211_CHAN_WIDTH_20:
3324 case NL80211_CHAN_WIDTH_40:
3325 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
3326 cfg80211_get_chandef_type(chandef)))
3327 return -ENOBUFS;
3328 break;
3329 default:
3330 break;
3331 }
3332 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
3333 return -ENOBUFS;
3334 if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
3335 return -ENOBUFS;
3336 if (chandef->center_freq2 &&
3337 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
Johannes Berg683b6d32012-11-08 21:25:48 +01003338 return -ENOBUFS;
3339 return 0;
3340}
3341
Eric W. Biederman15e47302012-09-07 20:12:54 +00003342static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
Johannes Bergd7264052009-04-19 16:23:20 +02003343 struct cfg80211_registered_device *rdev,
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003344 struct wireless_dev *wdev,
3345 enum nl80211_commands cmd)
Johannes Berg55682962007-09-20 13:09:35 -04003346{
Johannes Berg72fb2ab2012-06-15 17:52:47 +02003347 struct net_device *dev = wdev->netdev;
Johannes Berg55682962007-09-20 13:09:35 -04003348 void *hdr;
3349
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003350 WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
3351 cmd != NL80211_CMD_DEL_INTERFACE &&
3352 cmd != NL80211_CMD_SET_INTERFACE);
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02003353
3354 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04003355 if (!hdr)
3356 return -1;
3357
Johannes Berg72fb2ab2012-06-15 17:52:47 +02003358 if (dev &&
3359 (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02003360 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
Johannes Berg72fb2ab2012-06-15 17:52:47 +02003361 goto nla_put_failure;
3362
3363 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
3364 nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02003365 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
3366 NL80211_ATTR_PAD) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02003367 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04003368 nla_put_u32(msg, NL80211_ATTR_GENERATION,
3369 rdev->devlist_generation ^
Antonio Quartulli446faa12018-06-14 09:43:06 +08003370 (cfg80211_rdev_list_generation << 2)) ||
3371 nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr))
David S. Miller9360ffd2012-03-29 04:41:26 -04003372 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02003373
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02003374 if (rdev->ops->get_channel) {
Johannes Berg683b6d32012-11-08 21:25:48 +01003375 int ret;
Johannes Bergf43e5212019-09-23 13:51:16 +02003376 struct cfg80211_chan_def chandef = {};
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02003377
Johannes Berg683b6d32012-11-08 21:25:48 +01003378 ret = rdev_get_channel(rdev, wdev, &chandef);
3379 if (ret == 0) {
3380 if (nl80211_send_chandef(msg, &chandef))
3381 goto nla_put_failure;
3382 }
Pontus Fuchsd91df0e2012-04-03 16:39:58 +02003383 }
3384
Rafał Miłeckid55d0d52015-08-31 22:59:38 +02003385 if (rdev->ops->get_tx_power) {
3386 int dbm, ret;
3387
3388 ret = rdev_get_tx_power(rdev, wdev, &dbm);
3389 if (ret == 0 &&
3390 nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
3391 DBM_TO_MBM(dbm)))
3392 goto nla_put_failure;
3393 }
3394
Johannes Berg44905262017-10-17 21:56:01 +02003395 wdev_lock(wdev);
3396 switch (wdev->iftype) {
3397 case NL80211_IFTYPE_AP:
3398 if (wdev->ssid_len &&
3399 nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
Johannes Berg4564b182017-12-11 12:33:47 +01003400 goto nla_put_failure_locked;
Johannes Berg44905262017-10-17 21:56:01 +02003401 break;
3402 case NL80211_IFTYPE_STATION:
3403 case NL80211_IFTYPE_P2P_CLIENT:
3404 case NL80211_IFTYPE_ADHOC: {
3405 const u8 *ssid_ie;
3406 if (!wdev->current_bss)
3407 break;
Dominik Brodowski7a94b8c2018-01-15 08:12:15 +01003408 rcu_read_lock();
Johannes Berg44905262017-10-17 21:56:01 +02003409 ssid_ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
3410 WLAN_EID_SSID);
Dominik Brodowski7a94b8c2018-01-15 08:12:15 +01003411 if (ssid_ie &&
3412 nla_put(msg, NL80211_ATTR_SSID, ssid_ie[1], ssid_ie + 2))
3413 goto nla_put_failure_rcu_locked;
3414 rcu_read_unlock();
Johannes Berg44905262017-10-17 21:56:01 +02003415 break;
3416 }
3417 default:
3418 /* nothing */
3419 break;
Antonio Quartullib84e7a02012-11-07 12:52:20 +01003420 }
Johannes Berg44905262017-10-17 21:56:01 +02003421 wdev_unlock(wdev);
Antonio Quartullib84e7a02012-11-07 12:52:20 +01003422
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003423 if (rdev->ops->get_txq_stats) {
3424 struct cfg80211_txq_stats txqstats = {};
3425 int ret = rdev_get_txq_stats(rdev, wdev, &txqstats);
3426
3427 if (ret == 0 &&
3428 !nl80211_put_txq_stats(msg, &txqstats,
3429 NL80211_ATTR_TXQ_STATS))
3430 goto nla_put_failure;
3431 }
3432
Johannes Berg053c0952015-01-16 22:09:00 +01003433 genlmsg_end(msg, hdr);
3434 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04003435
Dominik Brodowski7a94b8c2018-01-15 08:12:15 +01003436 nla_put_failure_rcu_locked:
3437 rcu_read_unlock();
Johannes Berg4564b182017-12-11 12:33:47 +01003438 nla_put_failure_locked:
3439 wdev_unlock(wdev);
Johannes Berg55682962007-09-20 13:09:35 -04003440 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07003441 genlmsg_cancel(msg, hdr);
3442 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04003443}
3444
3445static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
3446{
3447 int wp_idx = 0;
3448 int if_idx = 0;
3449 int wp_start = cb->args[0];
3450 int if_start = cb->args[1];
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05003451 int filter_wiphy = -1;
Johannes Bergf5ea9122009-08-07 16:17:38 +02003452 struct cfg80211_registered_device *rdev;
Johannes Berg55682962007-09-20 13:09:35 -04003453 struct wireless_dev *wdev;
Johannes Bergea90e0d2017-03-15 14:26:04 +01003454 int ret;
Johannes Berg55682962007-09-20 13:09:35 -04003455
Johannes Berg5fe231e2013-05-08 21:45:15 +02003456 rtnl_lock();
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05003457 if (!cb->args[2]) {
3458 struct nl80211_dump_wiphy_state state = {
3459 .filter_wiphy = -1,
3460 };
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05003461
3462 ret = nl80211_dump_wiphy_parse(skb, cb, &state);
3463 if (ret)
Johannes Bergea90e0d2017-03-15 14:26:04 +01003464 goto out_unlock;
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05003465
3466 filter_wiphy = state.filter_wiphy;
3467
3468 /*
3469 * if filtering, set cb->args[2] to +1 since 0 is the default
3470 * value needed to determine that parsing is necessary.
3471 */
3472 if (filter_wiphy >= 0)
3473 cb->args[2] = filter_wiphy + 1;
3474 else
3475 cb->args[2] = -1;
3476 } else if (cb->args[2] > 0) {
3477 filter_wiphy = cb->args[2] - 1;
3478 }
3479
Johannes Bergf5ea9122009-08-07 16:17:38 +02003480 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
3481 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02003482 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02003483 if (wp_idx < wp_start) {
3484 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04003485 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02003486 }
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05003487
3488 if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx)
3489 continue;
3490
Johannes Berg55682962007-09-20 13:09:35 -04003491 if_idx = 0;
3492
Johannes Berg53873f12016-05-03 16:52:04 +03003493 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02003494 if (if_idx < if_start) {
3495 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04003496 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02003497 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00003498 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
Johannes Berg55682962007-09-20 13:09:35 -04003499 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003500 rdev, wdev,
3501 NL80211_CMD_NEW_INTERFACE) < 0) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02003502 goto out;
3503 }
3504 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04003505 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02003506
3507 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04003508 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02003509 out:
Johannes Berg55682962007-09-20 13:09:35 -04003510 cb->args[0] = wp_idx;
3511 cb->args[1] = if_idx;
3512
Johannes Bergea90e0d2017-03-15 14:26:04 +01003513 ret = skb->len;
3514 out_unlock:
3515 rtnl_unlock();
3516
3517 return ret;
Johannes Berg55682962007-09-20 13:09:35 -04003518}
3519
3520static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
3521{
3522 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08003523 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg72fb2ab2012-06-15 17:52:47 +02003524 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04003525
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07003526 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04003527 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02003528 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04003529
Eric W. Biederman15e47302012-09-07 20:12:54 +00003530 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003531 rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02003532 nlmsg_free(msg);
3533 return -ENOBUFS;
3534 }
Johannes Berg55682962007-09-20 13:09:35 -04003535
Johannes Berg134e6372009-07-10 09:51:34 +00003536 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04003537}
3538
Michael Wu66f7ac52008-01-31 19:48:22 +01003539static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
3540 [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
3541 [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
3542 [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
3543 [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
3544 [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
Felix Fietkaue057d3c2013-05-28 13:01:52 +02003545 [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
Michael Wu66f7ac52008-01-31 19:48:22 +01003546};
3547
3548static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
3549{
3550 struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
3551 int flag;
3552
3553 *mntrflags = 0;
3554
3555 if (!nla)
3556 return -EINVAL;
3557
Johannes Berg8cb08172019-04-26 14:07:28 +02003558 if (nla_parse_nested_deprecated(flags, NL80211_MNTR_FLAG_MAX, nla, mntr_flags_policy, NULL))
Michael Wu66f7ac52008-01-31 19:48:22 +01003559 return -EINVAL;
3560
3561 for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
3562 if (flags[flag])
3563 *mntrflags |= (1<<flag);
3564
Johannes Berg818a9862017-04-12 11:23:28 +02003565 *mntrflags |= MONITOR_FLAG_CHANGED;
3566
Michael Wu66f7ac52008-01-31 19:48:22 +01003567 return 0;
3568}
3569
Johannes Berg1db77592017-04-12 11:36:31 +02003570static int nl80211_parse_mon_options(struct cfg80211_registered_device *rdev,
3571 enum nl80211_iftype type,
3572 struct genl_info *info,
3573 struct vif_params *params)
3574{
3575 bool change = false;
3576 int err;
3577
3578 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
3579 if (type != NL80211_IFTYPE_MONITOR)
3580 return -EINVAL;
3581
3582 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
3583 &params->flags);
3584 if (err)
3585 return err;
3586
3587 change = true;
3588 }
3589
3590 if (params->flags & MONITOR_FLAG_ACTIVE &&
3591 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
3592 return -EOPNOTSUPP;
3593
3594 if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
3595 const u8 *mumimo_groups;
3596 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
3597
3598 if (type != NL80211_IFTYPE_MONITOR)
3599 return -EINVAL;
3600
3601 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
3602 return -EOPNOTSUPP;
3603
3604 mumimo_groups =
3605 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
3606
3607 /* bits 0 and 63 are reserved and must be zero */
Johannes Berg49546012017-04-27 09:13:38 +02003608 if ((mumimo_groups[0] & BIT(0)) ||
3609 (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(7)))
Johannes Berg1db77592017-04-12 11:36:31 +02003610 return -EINVAL;
3611
3612 params->vht_mumimo_groups = mumimo_groups;
3613 change = true;
3614 }
3615
3616 if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
3617 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
3618
3619 if (type != NL80211_IFTYPE_MONITOR)
3620 return -EINVAL;
3621
3622 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
3623 return -EOPNOTSUPP;
3624
3625 params->vht_mumimo_follow_addr =
3626 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]);
3627 change = true;
3628 }
3629
3630 return change ? 1 : 0;
3631}
3632
Johannes Berg9bc383d2009-11-19 11:55:19 +01003633static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003634 struct net_device *netdev, u8 use_4addr,
3635 enum nl80211_iftype iftype)
Johannes Berg9bc383d2009-11-19 11:55:19 +01003636{
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003637 if (!use_4addr) {
Julian Wiedmann2e92a2d2020-02-20 09:00:07 +01003638 if (netdev && netif_is_bridge_port(netdev))
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003639 return -EBUSY;
Johannes Berg9bc383d2009-11-19 11:55:19 +01003640 return 0;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003641 }
Johannes Berg9bc383d2009-11-19 11:55:19 +01003642
3643 switch (iftype) {
3644 case NL80211_IFTYPE_AP_VLAN:
3645 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
3646 return 0;
3647 break;
3648 case NL80211_IFTYPE_STATION:
3649 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
3650 return 0;
3651 break;
3652 default:
3653 break;
3654 }
3655
3656 return -EOPNOTSUPP;
3657}
3658
Johannes Berg55682962007-09-20 13:09:35 -04003659static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
3660{
Johannes Berg4c476992010-10-04 21:36:35 +02003661 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003662 struct vif_params params;
Johannes Berge36d56b2009-06-09 21:04:43 +02003663 int err;
Johannes Berg04a773a2009-04-19 21:24:32 +02003664 enum nl80211_iftype otype, ntype;
Johannes Berg4c476992010-10-04 21:36:35 +02003665 struct net_device *dev = info->user_ptr[1];
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003666 bool change = false;
Johannes Berg55682962007-09-20 13:09:35 -04003667
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003668 memset(&params, 0, sizeof(params));
3669
Johannes Berg04a773a2009-04-19 21:24:32 +02003670 otype = ntype = dev->ieee80211_ptr->iftype;
Johannes Berg55682962007-09-20 13:09:35 -04003671
Johannes Berg723b0382008-09-16 20:22:09 +02003672 if (info->attrs[NL80211_ATTR_IFTYPE]) {
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003673 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
Johannes Berg04a773a2009-04-19 21:24:32 +02003674 if (otype != ntype)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003675 change = true;
Johannes Berg723b0382008-09-16 20:22:09 +02003676 }
3677
Johannes Berg92ffe052008-09-16 20:39:36 +02003678 if (info->attrs[NL80211_ATTR_MESH_ID]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01003679 struct wireless_dev *wdev = dev->ieee80211_ptr;
3680
Johannes Berg4c476992010-10-04 21:36:35 +02003681 if (ntype != NL80211_IFTYPE_MESH_POINT)
3682 return -EINVAL;
Johannes Berg29cbe682010-12-03 09:20:44 +01003683 if (netif_running(dev))
3684 return -EBUSY;
3685
3686 wdev_lock(wdev);
3687 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
3688 IEEE80211_MAX_MESH_ID_LEN);
3689 wdev->mesh_id_up_len =
3690 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
3691 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
3692 wdev->mesh_id_up_len);
3693 wdev_unlock(wdev);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003694 }
3695
Felix Fietkau8b787642009-11-10 18:53:10 +01003696 if (info->attrs[NL80211_ATTR_4ADDR]) {
3697 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
3698 change = true;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003699 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
Johannes Berg9bc383d2009-11-19 11:55:19 +01003700 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02003701 return err;
Felix Fietkau8b787642009-11-10 18:53:10 +01003702 } else {
3703 params.use_4addr = -1;
3704 }
3705
Johannes Berg1db77592017-04-12 11:36:31 +02003706 err = nl80211_parse_mon_options(rdev, ntype, info, &params);
3707 if (err < 0)
3708 return err;
3709 if (err > 0)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003710 change = true;
Felix Fietkaue057d3c2013-05-28 13:01:52 +02003711
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003712 if (change)
Johannes Berg818a9862017-04-12 11:23:28 +02003713 err = cfg80211_change_iface(rdev, dev, ntype, &params);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003714 else
3715 err = 0;
Johannes Berg60719ff2008-09-16 14:55:09 +02003716
Johannes Berg9bc383d2009-11-19 11:55:19 +01003717 if (!err && params.use_4addr != -1)
3718 dev->ieee80211_ptr->use_4addr = params.use_4addr;
3719
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003720 if (change && !err) {
3721 struct wireless_dev *wdev = dev->ieee80211_ptr;
3722
3723 nl80211_notify_iface(rdev, wdev, NL80211_CMD_SET_INTERFACE);
3724 }
3725
Johannes Berg55682962007-09-20 13:09:35 -04003726 return err;
3727}
3728
3729static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
3730{
Johannes Berg4c476992010-10-04 21:36:35 +02003731 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003732 struct vif_params params;
Johannes Berg84efbb82012-06-16 00:00:26 +02003733 struct wireless_dev *wdev;
Denis Kenzior896ff062016-08-03 16:58:33 -05003734 struct sk_buff *msg;
Johannes Berg55682962007-09-20 13:09:35 -04003735 int err;
3736 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
3737
Johannes Berg78f22b62014-03-24 17:57:27 +01003738 /* to avoid failing a new interface creation due to pending removal */
3739 cfg80211_destroy_ifaces(rdev);
3740
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003741 memset(&params, 0, sizeof(params));
3742
Johannes Berg55682962007-09-20 13:09:35 -04003743 if (!info->attrs[NL80211_ATTR_IFNAME])
3744 return -EINVAL;
3745
Johannes Bergab0d76f2018-10-02 10:00:07 +02003746 if (info->attrs[NL80211_ATTR_IFTYPE])
Johannes Berg55682962007-09-20 13:09:35 -04003747 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
Johannes Berg55682962007-09-20 13:09:35 -04003748
Manikanta Pubbisetty33d915d2019-05-08 14:55:33 +05303749 if (!rdev->ops->add_virtual_intf)
Johannes Berg4c476992010-10-04 21:36:35 +02003750 return -EOPNOTSUPP;
Johannes Berg55682962007-09-20 13:09:35 -04003751
Ayala Bekercb3b7d82016-09-20 17:31:13 +03003752 if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
Ben Greeare8f479b2014-10-22 12:23:05 -07003753 rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
3754 info->attrs[NL80211_ATTR_MAC]) {
Arend van Spriel1c18f142013-01-08 10:17:27 +01003755 nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
3756 ETH_ALEN);
3757 if (!is_valid_ether_addr(params.macaddr))
3758 return -EADDRNOTAVAIL;
3759 }
3760
Johannes Berg9bc383d2009-11-19 11:55:19 +01003761 if (info->attrs[NL80211_ATTR_4ADDR]) {
Felix Fietkau8b787642009-11-10 18:53:10 +01003762 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003763 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
Johannes Berg9bc383d2009-11-19 11:55:19 +01003764 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02003765 return err;
Johannes Berg9bc383d2009-11-19 11:55:19 +01003766 }
Felix Fietkau8b787642009-11-10 18:53:10 +01003767
Manikanta Pubbisettye6f40512019-07-22 12:44:50 +05303768 if (!cfg80211_iftype_allowed(&rdev->wiphy, type, params.use_4addr, 0))
Manikanta Pubbisetty33d915d2019-05-08 14:55:33 +05303769 return -EOPNOTSUPP;
3770
Johannes Berg1db77592017-04-12 11:36:31 +02003771 err = nl80211_parse_mon_options(rdev, type, info, &params);
3772 if (err < 0)
3773 return err;
Felix Fietkaue057d3c2013-05-28 13:01:52 +02003774
Johannes Berga18c7192015-02-24 10:56:42 +01003775 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3776 if (!msg)
3777 return -ENOMEM;
3778
Hila Gonene35e4d22012-06-27 17:19:42 +03003779 wdev = rdev_add_virtual_intf(rdev,
3780 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
Johannes Berg818a9862017-04-12 11:23:28 +02003781 NET_NAME_USER, type, &params);
Rafał Miłeckid687cbb2014-11-14 18:43:28 +01003782 if (WARN_ON(!wdev)) {
3783 nlmsg_free(msg);
3784 return -EPROTO;
3785 } else if (IS_ERR(wdev)) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02003786 nlmsg_free(msg);
Johannes Berg84efbb82012-06-16 00:00:26 +02003787 return PTR_ERR(wdev);
Johannes Berg1c90f9d2012-06-16 00:05:37 +02003788 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003789
Jukka Rissanen18e5ca62014-11-13 17:25:14 +02003790 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
Johannes Berg78f22b62014-03-24 17:57:27 +01003791 wdev->owner_nlportid = info->snd_portid;
3792
Johannes Berg98104fde2012-06-16 00:19:54 +02003793 switch (type) {
3794 case NL80211_IFTYPE_MESH_POINT:
3795 if (!info->attrs[NL80211_ATTR_MESH_ID])
3796 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01003797 wdev_lock(wdev);
3798 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
3799 IEEE80211_MAX_MESH_ID_LEN);
3800 wdev->mesh_id_up_len =
3801 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
3802 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
3803 wdev->mesh_id_up_len);
3804 wdev_unlock(wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +02003805 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03003806 case NL80211_IFTYPE_NAN:
Johannes Berg98104fde2012-06-16 00:19:54 +02003807 case NL80211_IFTYPE_P2P_DEVICE:
3808 /*
Ayala Bekercb3b7d82016-09-20 17:31:13 +03003809 * P2P Device and NAN do not have a netdev, so don't go
Johannes Berg98104fde2012-06-16 00:19:54 +02003810 * through the netdev notifier and must be added here
3811 */
Johannes Berge4d42162018-09-13 14:12:03 +02003812 cfg80211_init_wdev(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +02003813 break;
3814 default:
3815 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01003816 }
3817
Eric W. Biederman15e47302012-09-07 20:12:54 +00003818 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003819 rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02003820 nlmsg_free(msg);
3821 return -ENOBUFS;
3822 }
3823
3824 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04003825}
3826
3827static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
3828{
Johannes Berg4c476992010-10-04 21:36:35 +02003829 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg84efbb82012-06-16 00:00:26 +02003830 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04003831
Johannes Berg4c476992010-10-04 21:36:35 +02003832 if (!rdev->ops->del_virtual_intf)
3833 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01003834
Johannes Berg84efbb82012-06-16 00:00:26 +02003835 /*
3836 * If we remove a wireless device without a netdev then clear
3837 * user_ptr[1] so that nl80211_post_doit won't dereference it
3838 * to check if it needs to do dev_put(). Otherwise it crashes
3839 * since the wdev has been freed, unlike with a netdev where
3840 * we need the dev_put() for the netdev to really be freed.
3841 */
3842 if (!wdev->netdev)
3843 info->user_ptr[1] = NULL;
3844
Denis Kenzior7f8ed012016-08-03 16:58:35 -05003845 return rdev_del_virtual_intf(rdev, wdev);
Johannes Berg55682962007-09-20 13:09:35 -04003846}
3847
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003848static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
3849{
3850 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3851 struct net_device *dev = info->user_ptr[1];
3852 u16 noack_map;
3853
3854 if (!info->attrs[NL80211_ATTR_NOACK_MAP])
3855 return -EINVAL;
3856
3857 if (!rdev->ops->set_noack_map)
3858 return -EOPNOTSUPP;
3859
3860 noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
3861
Hila Gonene35e4d22012-06-27 17:19:42 +03003862 return rdev_set_noack_map(rdev, dev, noack_map);
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003863}
3864
Johannes Berg41ade002007-12-19 02:03:29 +01003865struct get_key_cookie {
3866 struct sk_buff *msg;
3867 int error;
Johannes Bergb9454e82009-07-08 13:29:08 +02003868 int idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003869};
3870
3871static void get_key_callback(void *c, struct key_params *params)
3872{
Johannes Bergb9454e82009-07-08 13:29:08 +02003873 struct nlattr *key;
Johannes Berg41ade002007-12-19 02:03:29 +01003874 struct get_key_cookie *cookie = c;
3875
David S. Miller9360ffd2012-03-29 04:41:26 -04003876 if ((params->key &&
3877 nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
3878 params->key_len, params->key)) ||
3879 (params->seq &&
3880 nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
3881 params->seq_len, params->seq)) ||
3882 (params->cipher &&
3883 nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
3884 params->cipher)))
3885 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003886
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003887 key = nla_nest_start_noflag(cookie->msg, NL80211_ATTR_KEY);
Johannes Bergb9454e82009-07-08 13:29:08 +02003888 if (!key)
3889 goto nla_put_failure;
3890
David S. Miller9360ffd2012-03-29 04:41:26 -04003891 if ((params->key &&
3892 nla_put(cookie->msg, NL80211_KEY_DATA,
3893 params->key_len, params->key)) ||
3894 (params->seq &&
3895 nla_put(cookie->msg, NL80211_KEY_SEQ,
3896 params->seq_len, params->seq)) ||
3897 (params->cipher &&
3898 nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
3899 params->cipher)))
3900 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003901
Andrew Zaborowskiefdfce72018-09-24 18:10:22 +02003902 if (nla_put_u8(cookie->msg, NL80211_KEY_IDX, cookie->idx))
David S. Miller9360ffd2012-03-29 04:41:26 -04003903 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003904
3905 nla_nest_end(cookie->msg, key);
3906
Johannes Berg41ade002007-12-19 02:03:29 +01003907 return;
3908 nla_put_failure:
3909 cookie->error = 1;
3910}
3911
3912static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
3913{
Johannes Berg4c476992010-10-04 21:36:35 +02003914 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003915 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003916 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003917 u8 key_idx = 0;
Johannes Berge31b8212010-10-05 19:39:30 +02003918 const u8 *mac_addr = NULL;
3919 bool pairwise;
Johannes Berg41ade002007-12-19 02:03:29 +01003920 struct get_key_cookie cookie = {
3921 .error = 0,
3922 };
3923 void *hdr;
3924 struct sk_buff *msg;
Johannes Berg155d7c72020-04-20 14:06:00 +02003925 bool bigtk_support = false;
3926
3927 if (wiphy_ext_feature_isset(&rdev->wiphy,
3928 NL80211_EXT_FEATURE_BEACON_PROTECTION))
3929 bigtk_support = true;
3930
3931 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
3932 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
3933 wiphy_ext_feature_isset(&rdev->wiphy,
3934 NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
3935 bigtk_support = true;
Johannes Berg41ade002007-12-19 02:03:29 +01003936
Jouni Malinen56be3932020-02-22 15:25:43 +02003937 if (info->attrs[NL80211_ATTR_KEY_IDX]) {
Johannes Berg41ade002007-12-19 02:03:29 +01003938 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
Johannes Berg155d7c72020-04-20 14:06:00 +02003939
3940 if (key_idx >= 6 && key_idx <= 7 && !bigtk_support) {
3941 GENL_SET_ERR_MSG(info, "BIGTK not supported");
Jouni Malinen56be3932020-02-22 15:25:43 +02003942 return -EINVAL;
Johannes Berg155d7c72020-04-20 14:06:00 +02003943 }
Jouni Malinen56be3932020-02-22 15:25:43 +02003944 }
Johannes Berg41ade002007-12-19 02:03:29 +01003945
Johannes Berg41ade002007-12-19 02:03:29 +01003946 if (info->attrs[NL80211_ATTR_MAC])
3947 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3948
Johannes Berge31b8212010-10-05 19:39:30 +02003949 pairwise = !!mac_addr;
3950 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
3951 u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07003952
Johannes Berge31b8212010-10-05 19:39:30 +02003953 if (kt != NL80211_KEYTYPE_GROUP &&
3954 kt != NL80211_KEYTYPE_PAIRWISE)
3955 return -EINVAL;
3956 pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
3957 }
3958
Johannes Berg4c476992010-10-04 21:36:35 +02003959 if (!rdev->ops->get_key)
3960 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003961
Johannes Berg0fa7b392015-01-23 11:10:12 +01003962 if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3963 return -ENOENT;
3964
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07003965 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02003966 if (!msg)
3967 return -ENOMEM;
Johannes Berg41ade002007-12-19 02:03:29 +01003968
Eric W. Biederman15e47302012-09-07 20:12:54 +00003969 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg41ade002007-12-19 02:03:29 +01003970 NL80211_CMD_NEW_KEY);
Dan Carpentercb35fba2013-08-14 14:50:01 +03003971 if (!hdr)
Johannes Berg9fe271a2013-10-25 11:15:12 +02003972 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003973
3974 cookie.msg = msg;
Johannes Bergb9454e82009-07-08 13:29:08 +02003975 cookie.idx = key_idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003976
David S. Miller9360ffd2012-03-29 04:41:26 -04003977 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
3978 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
3979 goto nla_put_failure;
3980 if (mac_addr &&
3981 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
3982 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003983
Hila Gonene35e4d22012-06-27 17:19:42 +03003984 err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
3985 get_key_callback);
Johannes Berg41ade002007-12-19 02:03:29 +01003986
3987 if (err)
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003988 goto free_msg;
Johannes Berg41ade002007-12-19 02:03:29 +01003989
3990 if (cookie.error)
3991 goto nla_put_failure;
3992
3993 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02003994 return genlmsg_reply(msg, info);
Johannes Berg41ade002007-12-19 02:03:29 +01003995
3996 nla_put_failure:
3997 err = -ENOBUFS;
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003998 free_msg:
Johannes Berg41ade002007-12-19 02:03:29 +01003999 nlmsg_free(msg);
Johannes Berg41ade002007-12-19 02:03:29 +01004000 return err;
4001}
4002
4003static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
4004{
Johannes Berg4c476992010-10-04 21:36:35 +02004005 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergb9454e82009-07-08 13:29:08 +02004006 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01004007 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004008 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01004009
Johannes Bergb9454e82009-07-08 13:29:08 +02004010 err = nl80211_parse_key(info, &key);
4011 if (err)
4012 return err;
4013
4014 if (key.idx < 0)
Johannes Berg41ade002007-12-19 02:03:29 +01004015 return -EINVAL;
4016
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01004017 /* Only support setting default key and
4018 * Extended Key ID action NL80211_KEY_SET_TX.
4019 */
Jouni Malinen56be3932020-02-22 15:25:43 +02004020 if (!key.def && !key.defmgmt && !key.defbeacon &&
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01004021 !(key.p.mode == NL80211_KEY_SET_TX))
Johannes Berg41ade002007-12-19 02:03:29 +01004022 return -EINVAL;
4023
Johannes Bergfffd0932009-07-08 14:22:54 +02004024 wdev_lock(dev->ieee80211_ptr);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004025
4026 if (key.def) {
4027 if (!rdev->ops->set_default_key) {
4028 err = -EOPNOTSUPP;
4029 goto out;
4030 }
4031
4032 err = nl80211_key_allowed(dev->ieee80211_ptr);
4033 if (err)
4034 goto out;
4035
Hila Gonene35e4d22012-06-27 17:19:42 +03004036 err = rdev_set_default_key(rdev, dev, key.idx,
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004037 key.def_uni, key.def_multi);
4038
4039 if (err)
4040 goto out;
Johannes Bergfffd0932009-07-08 14:22:54 +02004041
Johannes Berg3d23e342009-09-29 23:27:28 +02004042#ifdef CONFIG_CFG80211_WEXT
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004043 dev->ieee80211_ptr->wext.default_key = key.idx;
Johannes Berg08645122009-05-11 13:54:58 +02004044#endif
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01004045 } else if (key.defmgmt) {
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004046 if (key.def_uni || !key.def_multi) {
4047 err = -EINVAL;
4048 goto out;
4049 }
4050
4051 if (!rdev->ops->set_default_mgmt_key) {
4052 err = -EOPNOTSUPP;
4053 goto out;
4054 }
4055
4056 err = nl80211_key_allowed(dev->ieee80211_ptr);
4057 if (err)
4058 goto out;
4059
Hila Gonene35e4d22012-06-27 17:19:42 +03004060 err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004061 if (err)
4062 goto out;
4063
4064#ifdef CONFIG_CFG80211_WEXT
4065 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
4066#endif
Jouni Malinen56be3932020-02-22 15:25:43 +02004067 } else if (key.defbeacon) {
4068 if (key.def_uni || !key.def_multi) {
4069 err = -EINVAL;
4070 goto out;
4071 }
4072
4073 if (!rdev->ops->set_default_beacon_key) {
4074 err = -EOPNOTSUPP;
4075 goto out;
4076 }
4077
4078 err = nl80211_key_allowed(dev->ieee80211_ptr);
4079 if (err)
4080 goto out;
4081
4082 err = rdev_set_default_beacon_key(rdev, dev, key.idx);
4083 if (err)
4084 goto out;
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01004085 } else if (key.p.mode == NL80211_KEY_SET_TX &&
4086 wiphy_ext_feature_isset(&rdev->wiphy,
4087 NL80211_EXT_FEATURE_EXT_KEY_ID)) {
4088 u8 *mac_addr = NULL;
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004089
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01004090 if (info->attrs[NL80211_ATTR_MAC])
4091 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4092
4093 if (!mac_addr || key.idx < 0 || key.idx > 1) {
4094 err = -EINVAL;
4095 goto out;
4096 }
4097
4098 err = rdev_add_key(rdev, dev, key.idx,
4099 NL80211_KEYTYPE_PAIRWISE,
4100 mac_addr, &key.p);
4101 } else {
4102 err = -EINVAL;
4103 }
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004104 out:
Johannes Bergfffd0932009-07-08 14:22:54 +02004105 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01004106
Johannes Berg41ade002007-12-19 02:03:29 +01004107 return err;
4108}
4109
4110static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
4111{
Johannes Berg4c476992010-10-04 21:36:35 +02004112 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfffd0932009-07-08 14:22:54 +02004113 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004114 struct net_device *dev = info->user_ptr[1];
Johannes Bergb9454e82009-07-08 13:29:08 +02004115 struct key_parse key;
Johannes Berge31b8212010-10-05 19:39:30 +02004116 const u8 *mac_addr = NULL;
Johannes Berg41ade002007-12-19 02:03:29 +01004117
Johannes Bergb9454e82009-07-08 13:29:08 +02004118 err = nl80211_parse_key(info, &key);
4119 if (err)
4120 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01004121
Jouni Malinenf8af7642020-02-22 15:25:42 +02004122 if (!key.p.key) {
4123 GENL_SET_ERR_MSG(info, "no key");
Johannes Berg41ade002007-12-19 02:03:29 +01004124 return -EINVAL;
Jouni Malinenf8af7642020-02-22 15:25:42 +02004125 }
Johannes Berg41ade002007-12-19 02:03:29 +01004126
Johannes Berg41ade002007-12-19 02:03:29 +01004127 if (info->attrs[NL80211_ATTR_MAC])
4128 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4129
Johannes Berge31b8212010-10-05 19:39:30 +02004130 if (key.type == -1) {
4131 if (mac_addr)
4132 key.type = NL80211_KEYTYPE_PAIRWISE;
4133 else
4134 key.type = NL80211_KEYTYPE_GROUP;
4135 }
4136
4137 /* for now */
4138 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
Jouni Malinenf8af7642020-02-22 15:25:42 +02004139 key.type != NL80211_KEYTYPE_GROUP) {
4140 GENL_SET_ERR_MSG(info, "key type not pairwise or group");
Johannes Berge31b8212010-10-05 19:39:30 +02004141 return -EINVAL;
Jouni Malinenf8af7642020-02-22 15:25:42 +02004142 }
Johannes Berge31b8212010-10-05 19:39:30 +02004143
Gurumoorthi Gnanasambandhan14f34e362019-10-31 23:46:40 +02004144 if (key.type == NL80211_KEYTYPE_GROUP &&
4145 info->attrs[NL80211_ATTR_VLAN_ID])
4146 key.p.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);
4147
Johannes Berg4c476992010-10-04 21:36:35 +02004148 if (!rdev->ops->add_key)
4149 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01004150
Johannes Berge31b8212010-10-05 19:39:30 +02004151 if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
4152 key.type == NL80211_KEYTYPE_PAIRWISE,
Jouni Malinenf8af7642020-02-22 15:25:42 +02004153 mac_addr)) {
4154 GENL_SET_ERR_MSG(info, "key setting validation failed");
Johannes Berg4c476992010-10-04 21:36:35 +02004155 return -EINVAL;
Jouni Malinenf8af7642020-02-22 15:25:42 +02004156 }
Johannes Bergfffd0932009-07-08 14:22:54 +02004157
4158 wdev_lock(dev->ieee80211_ptr);
4159 err = nl80211_key_allowed(dev->ieee80211_ptr);
Jouni Malinenf8af7642020-02-22 15:25:42 +02004160 if (err)
4161 GENL_SET_ERR_MSG(info, "key not allowed");
4162 if (!err) {
Hila Gonene35e4d22012-06-27 17:19:42 +03004163 err = rdev_add_key(rdev, dev, key.idx,
4164 key.type == NL80211_KEYTYPE_PAIRWISE,
4165 mac_addr, &key.p);
Jouni Malinenf8af7642020-02-22 15:25:42 +02004166 if (err)
4167 GENL_SET_ERR_MSG(info, "key addition failed");
4168 }
Johannes Bergfffd0932009-07-08 14:22:54 +02004169 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01004170
Johannes Berg41ade002007-12-19 02:03:29 +01004171 return err;
4172}
4173
4174static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
4175{
Johannes Berg4c476992010-10-04 21:36:35 +02004176 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01004177 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004178 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01004179 u8 *mac_addr = NULL;
Johannes Bergb9454e82009-07-08 13:29:08 +02004180 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01004181
Johannes Bergb9454e82009-07-08 13:29:08 +02004182 err = nl80211_parse_key(info, &key);
4183 if (err)
4184 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01004185
4186 if (info->attrs[NL80211_ATTR_MAC])
4187 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4188
Johannes Berge31b8212010-10-05 19:39:30 +02004189 if (key.type == -1) {
4190 if (mac_addr)
4191 key.type = NL80211_KEYTYPE_PAIRWISE;
4192 else
4193 key.type = NL80211_KEYTYPE_GROUP;
4194 }
4195
4196 /* for now */
4197 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
4198 key.type != NL80211_KEYTYPE_GROUP)
4199 return -EINVAL;
4200
Johannes Berg4c476992010-10-04 21:36:35 +02004201 if (!rdev->ops->del_key)
4202 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01004203
Johannes Bergfffd0932009-07-08 14:22:54 +02004204 wdev_lock(dev->ieee80211_ptr);
4205 err = nl80211_key_allowed(dev->ieee80211_ptr);
Johannes Berge31b8212010-10-05 19:39:30 +02004206
Johannes Berg0fa7b392015-01-23 11:10:12 +01004207 if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
Johannes Berge31b8212010-10-05 19:39:30 +02004208 !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
4209 err = -ENOENT;
4210
Johannes Bergfffd0932009-07-08 14:22:54 +02004211 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03004212 err = rdev_del_key(rdev, dev, key.idx,
4213 key.type == NL80211_KEYTYPE_PAIRWISE,
4214 mac_addr);
Johannes Berg41ade002007-12-19 02:03:29 +01004215
Johannes Berg3d23e342009-09-29 23:27:28 +02004216#ifdef CONFIG_CFG80211_WEXT
Johannes Berg08645122009-05-11 13:54:58 +02004217 if (!err) {
Johannes Bergb9454e82009-07-08 13:29:08 +02004218 if (key.idx == dev->ieee80211_ptr->wext.default_key)
Johannes Berg08645122009-05-11 13:54:58 +02004219 dev->ieee80211_ptr->wext.default_key = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +02004220 else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
Johannes Berg08645122009-05-11 13:54:58 +02004221 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
4222 }
4223#endif
Johannes Bergfffd0932009-07-08 14:22:54 +02004224 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg08645122009-05-11 13:54:58 +02004225
Johannes Berg41ade002007-12-19 02:03:29 +01004226 return err;
4227}
4228
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05304229/* This function returns an error or the number of nested attributes */
4230static int validate_acl_mac_addrs(struct nlattr *nl_attr)
4231{
4232 struct nlattr *attr;
4233 int n_entries = 0, tmp;
4234
4235 nla_for_each_nested(attr, nl_attr, tmp) {
4236 if (nla_len(attr) != ETH_ALEN)
4237 return -EINVAL;
4238
4239 n_entries++;
4240 }
4241
4242 return n_entries;
4243}
4244
4245/*
4246 * This function parses ACL information and allocates memory for ACL data.
4247 * On successful return, the calling function is responsible to free the
4248 * ACL buffer returned by this function.
4249 */
4250static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
4251 struct genl_info *info)
4252{
4253 enum nl80211_acl_policy acl_policy;
4254 struct nlattr *attr;
4255 struct cfg80211_acl_data *acl;
4256 int i = 0, n_entries, tmp;
4257
4258 if (!wiphy->max_acl_mac_addrs)
4259 return ERR_PTR(-EOPNOTSUPP);
4260
4261 if (!info->attrs[NL80211_ATTR_ACL_POLICY])
4262 return ERR_PTR(-EINVAL);
4263
4264 acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
4265 if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
4266 acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
4267 return ERR_PTR(-EINVAL);
4268
4269 if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
4270 return ERR_PTR(-EINVAL);
4271
4272 n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
4273 if (n_entries < 0)
4274 return ERR_PTR(n_entries);
4275
4276 if (n_entries > wiphy->max_acl_mac_addrs)
4277 return ERR_PTR(-ENOTSUPP);
4278
Gustavo A. R. Silva391d1322019-04-03 10:37:44 -05004279 acl = kzalloc(struct_size(acl, mac_addrs, n_entries), GFP_KERNEL);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05304280 if (!acl)
4281 return ERR_PTR(-ENOMEM);
4282
4283 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
4284 memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
4285 i++;
4286 }
4287
4288 acl->n_acl_entries = n_entries;
4289 acl->acl_policy = acl_policy;
4290
4291 return acl;
4292}
4293
4294static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
4295{
4296 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4297 struct net_device *dev = info->user_ptr[1];
4298 struct cfg80211_acl_data *acl;
4299 int err;
4300
4301 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4302 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4303 return -EOPNOTSUPP;
4304
4305 if (!dev->ieee80211_ptr->beacon_interval)
4306 return -EINVAL;
4307
4308 acl = parse_acl_data(&rdev->wiphy, info);
4309 if (IS_ERR(acl))
4310 return PTR_ERR(acl);
4311
4312 err = rdev_set_mac_acl(rdev, dev, acl);
4313
4314 kfree(acl);
4315
4316 return err;
4317}
4318
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304319static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
4320 u8 *rates, u8 rates_len)
4321{
4322 u8 i;
4323 u32 mask = 0;
4324
4325 for (i = 0; i < rates_len; i++) {
4326 int rate = (rates[i] & 0x7f) * 5;
4327 int ridx;
4328
4329 for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
4330 struct ieee80211_rate *srate =
4331 &sband->bitrates[ridx];
4332 if (rate == srate->bitrate) {
4333 mask |= 1 << ridx;
4334 break;
4335 }
4336 }
4337 if (ridx == sband->n_bitrates)
4338 return 0; /* rate not found */
4339 }
4340
4341 return mask;
4342}
4343
4344static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
4345 u8 *rates, u8 rates_len,
4346 u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
4347{
4348 u8 i;
4349
4350 memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
4351
4352 for (i = 0; i < rates_len; i++) {
4353 int ridx, rbit;
4354
4355 ridx = rates[i] / 8;
4356 rbit = BIT(rates[i] % 8);
4357
4358 /* check validity */
4359 if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
4360 return false;
4361
4362 /* check availability */
Masashi Honma30fe6d52018-09-25 11:15:00 +09004363 ridx = array_index_nospec(ridx, IEEE80211_HT_MCS_MASK_LEN);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304364 if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
4365 mcs[ridx] |= rbit;
4366 else
4367 return false;
4368 }
4369
4370 return true;
4371}
4372
4373static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
4374{
4375 u16 mcs_mask = 0;
4376
4377 switch (vht_mcs_map) {
4378 case IEEE80211_VHT_MCS_NOT_SUPPORTED:
4379 break;
4380 case IEEE80211_VHT_MCS_SUPPORT_0_7:
4381 mcs_mask = 0x00FF;
4382 break;
4383 case IEEE80211_VHT_MCS_SUPPORT_0_8:
4384 mcs_mask = 0x01FF;
4385 break;
4386 case IEEE80211_VHT_MCS_SUPPORT_0_9:
4387 mcs_mask = 0x03FF;
4388 break;
4389 default:
4390 break;
4391 }
4392
4393 return mcs_mask;
4394}
4395
4396static void vht_build_mcs_mask(u16 vht_mcs_map,
4397 u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
4398{
4399 u8 nss;
4400
4401 for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
4402 vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
4403 vht_mcs_map >>= 2;
4404 }
4405}
4406
4407static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
4408 struct nl80211_txrate_vht *txrate,
4409 u16 mcs[NL80211_VHT_NSS_MAX])
4410{
4411 u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
4412 u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
4413 u8 i;
4414
4415 if (!sband->vht_cap.vht_supported)
4416 return false;
4417
4418 memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
4419
4420 /* Build vht_mcs_mask from VHT capabilities */
4421 vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
4422
4423 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
4424 if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
4425 mcs[i] = txrate->mcs[i];
4426 else
4427 return false;
4428 }
4429
4430 return true;
4431}
4432
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304433static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +05304434 struct nlattr *attrs[],
4435 enum nl80211_attrs attr,
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304436 struct cfg80211_bitrate_mask *mask)
4437{
4438 struct nlattr *tb[NL80211_TXRATE_MAX + 1];
4439 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4440 int rem, i;
4441 struct nlattr *tx_rates;
4442 struct ieee80211_supported_band *sband;
4443 u16 vht_tx_mcs_map;
4444
4445 memset(mask, 0, sizeof(*mask));
4446 /* Default to all rates enabled */
4447 for (i = 0; i < NUM_NL80211_BANDS; i++) {
4448 sband = rdev->wiphy.bands[i];
4449
4450 if (!sband)
4451 continue;
4452
4453 mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
4454 memcpy(mask->control[i].ht_mcs,
4455 sband->ht_cap.mcs.rx_mask,
4456 sizeof(mask->control[i].ht_mcs));
4457
4458 if (!sband->vht_cap.vht_supported)
4459 continue;
4460
4461 vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
4462 vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
4463 }
4464
4465 /* if no rates are given set it back to the defaults */
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +05304466 if (!attrs[attr])
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304467 goto out;
4468
4469 /* The nested attribute uses enum nl80211_band as the index. This maps
4470 * directly to the enum nl80211_band values used in cfg80211.
4471 */
4472 BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +05304473 nla_for_each_nested(tx_rates, attrs[attr], rem) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304474 enum nl80211_band band = nla_type(tx_rates);
4475 int err;
4476
4477 if (band < 0 || band >= NUM_NL80211_BANDS)
4478 return -EINVAL;
4479 sband = rdev->wiphy.bands[band];
4480 if (sband == NULL)
4481 return -EINVAL;
Johannes Berg8cb08172019-04-26 14:07:28 +02004482 err = nla_parse_nested_deprecated(tb, NL80211_TXRATE_MAX,
4483 tx_rates,
4484 nl80211_txattr_policy,
4485 info->extack);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304486 if (err)
4487 return err;
4488 if (tb[NL80211_TXRATE_LEGACY]) {
4489 mask->control[band].legacy = rateset_to_mask(
4490 sband,
4491 nla_data(tb[NL80211_TXRATE_LEGACY]),
4492 nla_len(tb[NL80211_TXRATE_LEGACY]));
4493 if ((mask->control[band].legacy == 0) &&
4494 nla_len(tb[NL80211_TXRATE_LEGACY]))
4495 return -EINVAL;
4496 }
4497 if (tb[NL80211_TXRATE_HT]) {
4498 if (!ht_rateset_to_mask(
4499 sband,
4500 nla_data(tb[NL80211_TXRATE_HT]),
4501 nla_len(tb[NL80211_TXRATE_HT]),
4502 mask->control[band].ht_mcs))
4503 return -EINVAL;
4504 }
4505 if (tb[NL80211_TXRATE_VHT]) {
4506 if (!vht_set_mcs_mask(
4507 sband,
4508 nla_data(tb[NL80211_TXRATE_VHT]),
4509 mask->control[band].vht_mcs))
4510 return -EINVAL;
4511 }
4512 if (tb[NL80211_TXRATE_GI]) {
4513 mask->control[band].gi =
4514 nla_get_u8(tb[NL80211_TXRATE_GI]);
4515 if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
4516 return -EINVAL;
4517 }
4518
4519 if (mask->control[band].legacy == 0) {
4520 /* don't allow empty legacy rates if HT or VHT
4521 * are not even supported.
4522 */
4523 if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
4524 rdev->wiphy.bands[band]->vht_cap.vht_supported))
4525 return -EINVAL;
4526
4527 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
4528 if (mask->control[band].ht_mcs[i])
4529 goto out;
4530
4531 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
4532 if (mask->control[band].vht_mcs[i])
4533 goto out;
4534
4535 /* legacy and mcs rates may not be both empty */
4536 return -EINVAL;
4537 }
4538 }
4539
4540out:
4541 return 0;
4542}
4543
Johannes Berg8564e382016-09-19 09:44:44 +02004544static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
4545 enum nl80211_band band,
4546 struct cfg80211_bitrate_mask *beacon_rate)
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304547{
Johannes Berg8564e382016-09-19 09:44:44 +02004548 u32 count_ht, count_vht, i;
4549 u32 rate = beacon_rate->control[band].legacy;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304550
4551 /* Allow only one rate */
4552 if (hweight32(rate) > 1)
4553 return -EINVAL;
4554
4555 count_ht = 0;
4556 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02004557 if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304558 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02004559 } else if (beacon_rate->control[band].ht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304560 count_ht++;
4561 if (count_ht > 1)
4562 return -EINVAL;
4563 }
4564 if (count_ht && rate)
4565 return -EINVAL;
4566 }
4567
4568 count_vht = 0;
4569 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02004570 if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304571 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02004572 } else if (beacon_rate->control[band].vht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304573 count_vht++;
4574 if (count_vht > 1)
4575 return -EINVAL;
4576 }
4577 if (count_vht && rate)
4578 return -EINVAL;
4579 }
4580
4581 if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
4582 return -EINVAL;
4583
Johannes Berg8564e382016-09-19 09:44:44 +02004584 if (rate &&
4585 !wiphy_ext_feature_isset(&rdev->wiphy,
4586 NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
4587 return -EINVAL;
4588 if (count_ht &&
4589 !wiphy_ext_feature_isset(&rdev->wiphy,
4590 NL80211_EXT_FEATURE_BEACON_RATE_HT))
4591 return -EINVAL;
4592 if (count_vht &&
4593 !wiphy_ext_feature_isset(&rdev->wiphy,
4594 NL80211_EXT_FEATURE_BEACON_RATE_VHT))
4595 return -EINVAL;
4596
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304597 return 0;
4598}
4599
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07004600static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
4601 struct nlattr *attrs[],
Johannes Berg88600202012-02-13 15:17:18 +01004602 struct cfg80211_beacon_data *bcn)
Johannes Berged1b6cc2007-12-19 02:03:32 +01004603{
Johannes Berg88600202012-02-13 15:17:18 +01004604 bool haveinfo = false;
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07004605 int err;
Johannes Berged1b6cc2007-12-19 02:03:32 +01004606
Johannes Berg88600202012-02-13 15:17:18 +01004607 memset(bcn, 0, sizeof(*bcn));
Johannes Berged1b6cc2007-12-19 02:03:32 +01004608
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004609 if (attrs[NL80211_ATTR_BEACON_HEAD]) {
4610 bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
4611 bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
Johannes Berg88600202012-02-13 15:17:18 +01004612 if (!bcn->head_len)
4613 return -EINVAL;
4614 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01004615 }
4616
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004617 if (attrs[NL80211_ATTR_BEACON_TAIL]) {
4618 bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
4619 bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
Johannes Berg88600202012-02-13 15:17:18 +01004620 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01004621 }
4622
Johannes Berg4c476992010-10-04 21:36:35 +02004623 if (!haveinfo)
4624 return -EINVAL;
Johannes Berged1b6cc2007-12-19 02:03:32 +01004625
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004626 if (attrs[NL80211_ATTR_IE]) {
4627 bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
4628 bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03004629 }
4630
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004631 if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01004632 bcn->proberesp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004633 nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01004634 bcn->proberesp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004635 nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03004636 }
4637
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004638 if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01004639 bcn->assocresp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004640 nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01004641 bcn->assocresp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004642 nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03004643 }
4644
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004645 if (attrs[NL80211_ATTR_PROBE_RESP]) {
4646 bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
4647 bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
Arik Nemtsov00f740e2011-11-10 11:28:56 +02004648 }
4649
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07004650 if (attrs[NL80211_ATTR_FTM_RESPONDER]) {
4651 struct nlattr *tb[NL80211_FTM_RESP_ATTR_MAX + 1];
4652
Johannes Berg8cb08172019-04-26 14:07:28 +02004653 err = nla_parse_nested_deprecated(tb,
4654 NL80211_FTM_RESP_ATTR_MAX,
4655 attrs[NL80211_ATTR_FTM_RESPONDER],
4656 NULL, NULL);
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07004657 if (err)
4658 return err;
4659
4660 if (tb[NL80211_FTM_RESP_ATTR_ENABLED] &&
4661 wiphy_ext_feature_isset(&rdev->wiphy,
4662 NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
4663 bcn->ftm_responder = 1;
4664 else
4665 return -EOPNOTSUPP;
4666
4667 if (tb[NL80211_FTM_RESP_ATTR_LCI]) {
4668 bcn->lci = nla_data(tb[NL80211_FTM_RESP_ATTR_LCI]);
4669 bcn->lci_len = nla_len(tb[NL80211_FTM_RESP_ATTR_LCI]);
4670 }
4671
4672 if (tb[NL80211_FTM_RESP_ATTR_CIVICLOC]) {
4673 bcn->civicloc = nla_data(tb[NL80211_FTM_RESP_ATTR_CIVICLOC]);
4674 bcn->civicloc_len = nla_len(tb[NL80211_FTM_RESP_ATTR_CIVICLOC]);
4675 }
4676 } else {
4677 bcn->ftm_responder = -1;
4678 }
4679
Johannes Berg88600202012-02-13 15:17:18 +01004680 return 0;
4681}
4682
John Crispin796e90f2019-07-30 18:37:00 +02004683static int nl80211_parse_he_obss_pd(struct nlattr *attrs,
4684 struct ieee80211_he_obss_pd *he_obss_pd)
4685{
4686 struct nlattr *tb[NL80211_HE_OBSS_PD_ATTR_MAX + 1];
4687 int err;
4688
4689 err = nla_parse_nested(tb, NL80211_HE_OBSS_PD_ATTR_MAX, attrs,
4690 he_obss_pd_policy, NULL);
4691 if (err)
4692 return err;
4693
4694 if (!tb[NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET] ||
4695 !tb[NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET])
4696 return -EINVAL;
4697
4698 he_obss_pd->min_offset =
4699 nla_get_u32(tb[NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET]);
4700 he_obss_pd->max_offset =
4701 nla_get_u32(tb[NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET]);
4702
4703 if (he_obss_pd->min_offset >= he_obss_pd->max_offset)
4704 return -EINVAL;
4705
4706 he_obss_pd->enable = true;
4707
4708 return 0;
4709}
4710
John Crispin5c5e52d2019-12-17 15:19:18 +01004711static int nl80211_parse_he_bss_color(struct nlattr *attrs,
4712 struct cfg80211_he_bss_color *he_bss_color)
4713{
4714 struct nlattr *tb[NL80211_HE_BSS_COLOR_ATTR_MAX + 1];
4715 int err;
4716
4717 err = nla_parse_nested(tb, NL80211_HE_BSS_COLOR_ATTR_MAX, attrs,
4718 he_bss_color_policy, NULL);
4719 if (err)
4720 return err;
4721
4722 if (!tb[NL80211_HE_BSS_COLOR_ATTR_COLOR])
4723 return -EINVAL;
4724
4725 he_bss_color->color =
4726 nla_get_u8(tb[NL80211_HE_BSS_COLOR_ATTR_COLOR]);
Johannes Berg75e6b592020-07-30 13:00:52 +02004727 he_bss_color->enabled =
4728 !nla_get_flag(tb[NL80211_HE_BSS_COLOR_ATTR_DISABLED]);
John Crispin5c5e52d2019-12-17 15:19:18 +01004729 he_bss_color->partial =
4730 nla_get_flag(tb[NL80211_HE_BSS_COLOR_ATTR_PARTIAL]);
4731
4732 return 0;
4733}
4734
Johannes Berg66cd7942017-02-07 22:40:44 +02004735static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
4736 const u8 *rates)
4737{
4738 int i;
4739
4740 if (!rates)
4741 return;
4742
4743 for (i = 0; i < rates[1]; i++) {
4744 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
4745 params->ht_required = true;
4746 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
4747 params->vht_required = true;
Ilan Peer2a392592020-03-26 15:09:35 +02004748 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
4749 params->he_required = true;
Johannes Berg66cd7942017-02-07 22:40:44 +02004750 }
4751}
4752
4753/*
4754 * Since the nl80211 API didn't include, from the beginning, attributes about
4755 * HT/VHT requirements/capabilities, we parse them out of the IEs for the
4756 * benefit of drivers that rebuild IEs in the firmware.
4757 */
4758static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
4759{
4760 const struct cfg80211_beacon_data *bcn = &params->beacon;
Igor Mitsyankoba83bfb2017-08-30 13:52:25 -07004761 size_t ies_len = bcn->tail_len;
4762 const u8 *ies = bcn->tail;
Johannes Berg66cd7942017-02-07 22:40:44 +02004763 const u8 *rates;
4764 const u8 *cap;
4765
4766 rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
4767 nl80211_check_ap_rate_selectors(params, rates);
4768
4769 rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
4770 nl80211_check_ap_rate_selectors(params, rates);
4771
4772 cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
4773 if (cap && cap[1] >= sizeof(*params->ht_cap))
4774 params->ht_cap = (void *)(cap + 2);
4775 cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
4776 if (cap && cap[1] >= sizeof(*params->vht_cap))
4777 params->vht_cap = (void *)(cap + 2);
Shaul Triebitz244eb9a2018-08-31 11:31:14 +03004778 cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
4779 if (cap && cap[1] >= sizeof(*params->he_cap) + 1)
4780 params->he_cap = (void *)(cap + 3);
Shaul Triebitz7e8d6f12020-01-31 13:12:54 +02004781 cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
4782 if (cap && cap[1] >= sizeof(*params->he_oper) + 1)
4783 params->he_oper = (void *)(cap + 3);
Johannes Berg66cd7942017-02-07 22:40:44 +02004784}
4785
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004786static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
4787 struct cfg80211_ap_settings *params)
4788{
4789 struct wireless_dev *wdev;
4790 bool ret = false;
4791
Johannes Berg53873f12016-05-03 16:52:04 +03004792 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004793 if (wdev->iftype != NL80211_IFTYPE_AP &&
4794 wdev->iftype != NL80211_IFTYPE_P2P_GO)
4795 continue;
4796
Johannes Berg683b6d32012-11-08 21:25:48 +01004797 if (!wdev->preset_chandef.chan)
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004798 continue;
4799
Johannes Berg683b6d32012-11-08 21:25:48 +01004800 params->chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004801 ret = true;
4802 break;
4803 }
4804
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004805 return ret;
4806}
4807
Jouni Malinene39e5b52012-09-30 19:29:39 +03004808static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
4809 enum nl80211_auth_type auth_type,
4810 enum nl80211_commands cmd)
4811{
4812 if (auth_type > NL80211_AUTHTYPE_MAX)
4813 return false;
4814
4815 switch (cmd) {
4816 case NL80211_CMD_AUTHENTICATE:
4817 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
4818 auth_type == NL80211_AUTHTYPE_SAE)
4819 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03004820 if (!wiphy_ext_feature_isset(&rdev->wiphy,
4821 NL80211_EXT_FEATURE_FILS_STA) &&
4822 (auth_type == NL80211_AUTHTYPE_FILS_SK ||
4823 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
4824 auth_type == NL80211_AUTHTYPE_FILS_PK))
4825 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03004826 return true;
4827 case NL80211_CMD_CONNECT:
Srinivas Dasari10773a72018-01-25 17:13:39 +02004828 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
Chung-Hsien Hsu26f70442019-05-09 09:49:06 +00004829 !wiphy_ext_feature_isset(&rdev->wiphy,
4830 NL80211_EXT_FEATURE_SAE_OFFLOAD) &&
Srinivas Dasari10773a72018-01-25 17:13:39 +02004831 auth_type == NL80211_AUTHTYPE_SAE)
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03004832 return false;
Srinivas Dasari10773a72018-01-25 17:13:39 +02004833
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03004834 /* FILS with SK PFS or PK not supported yet */
4835 if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
4836 auth_type == NL80211_AUTHTYPE_FILS_PK)
4837 return false;
4838 if (!wiphy_ext_feature_isset(
4839 &rdev->wiphy,
4840 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
4841 auth_type == NL80211_AUTHTYPE_FILS_SK)
4842 return false;
4843 return true;
Jouni Malinene39e5b52012-09-30 19:29:39 +03004844 case NL80211_CMD_START_AP:
4845 /* SAE not supported yet */
4846 if (auth_type == NL80211_AUTHTYPE_SAE)
4847 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03004848 /* FILS not supported yet */
4849 if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
4850 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
4851 auth_type == NL80211_AUTHTYPE_FILS_PK)
4852 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03004853 return true;
4854 default:
4855 return false;
4856 }
4857}
4858
Johannes Berg88600202012-02-13 15:17:18 +01004859static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
4860{
4861 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4862 struct net_device *dev = info->user_ptr[1];
4863 struct wireless_dev *wdev = dev->ieee80211_ptr;
4864 struct cfg80211_ap_settings params;
4865 int err;
4866
4867 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4868 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4869 return -EOPNOTSUPP;
4870
4871 if (!rdev->ops->start_ap)
4872 return -EOPNOTSUPP;
4873
4874 if (wdev->beacon_interval)
4875 return -EALREADY;
4876
4877 memset(&params, 0, sizeof(params));
4878
4879 /* these are required for START_AP */
4880 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
4881 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
4882 !info->attrs[NL80211_ATTR_BEACON_HEAD])
4883 return -EINVAL;
4884
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07004885 err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon);
Johannes Berg88600202012-02-13 15:17:18 +01004886 if (err)
4887 return err;
4888
4889 params.beacon_interval =
4890 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
4891 params.dtim_period =
4892 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
4893
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05304894 err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
4895 params.beacon_interval);
Johannes Berg88600202012-02-13 15:17:18 +01004896 if (err)
4897 return err;
4898
4899 /*
4900 * In theory, some of these attributes should be required here
4901 * but since they were not used when the command was originally
4902 * added, keep them optional for old user space programs to let
4903 * them continue to work with drivers that do not need the
4904 * additional information -- drivers must check!
4905 */
4906 if (info->attrs[NL80211_ATTR_SSID]) {
4907 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
4908 params.ssid_len =
4909 nla_len(info->attrs[NL80211_ATTR_SSID]);
Johannes Bergcb9abd42020-08-05 15:47:16 +02004910 if (params.ssid_len == 0)
Johannes Berg88600202012-02-13 15:17:18 +01004911 return -EINVAL;
4912 }
4913
Johannes Bergab0d76f2018-10-02 10:00:07 +02004914 if (info->attrs[NL80211_ATTR_HIDDEN_SSID])
Johannes Berg88600202012-02-13 15:17:18 +01004915 params.hidden_ssid = nla_get_u32(
4916 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
Johannes Berg88600202012-02-13 15:17:18 +01004917
4918 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
4919
4920 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
4921 params.auth_type = nla_get_u32(
4922 info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03004923 if (!nl80211_valid_auth_type(rdev, params.auth_type,
4924 NL80211_CMD_START_AP))
Johannes Berg88600202012-02-13 15:17:18 +01004925 return -EINVAL;
4926 } else
4927 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
4928
4929 err = nl80211_crypto_settings(rdev, info, &params.crypto,
4930 NL80211_MAX_NR_CIPHER_SUITES);
4931 if (err)
4932 return err;
4933
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +05304934 if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
4935 if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
4936 return -EOPNOTSUPP;
4937 params.inactivity_timeout = nla_get_u16(
4938 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
4939 }
4940
Johannes Berg53cabad2012-11-14 15:17:28 +01004941 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
4942 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4943 return -EINVAL;
4944 params.p2p_ctwindow =
4945 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
Johannes Berg53cabad2012-11-14 15:17:28 +01004946 if (params.p2p_ctwindow != 0 &&
4947 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
4948 return -EINVAL;
4949 }
4950
4951 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
4952 u8 tmp;
4953
4954 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4955 return -EINVAL;
4956 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
Johannes Berg53cabad2012-11-14 15:17:28 +01004957 params.p2p_opp_ps = tmp;
4958 if (params.p2p_opp_ps != 0 &&
4959 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
4960 return -EINVAL;
4961 }
4962
Johannes Bergaa430da2012-05-16 23:50:18 +02004963 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01004964 err = nl80211_parse_chandef(rdev, info, &params.chandef);
4965 if (err)
4966 return err;
4967 } else if (wdev->preset_chandef.chan) {
4968 params.chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004969 } else if (!nl80211_get_ap_channel(rdev, &params))
Johannes Bergaa430da2012-05-16 23:50:18 +02004970 return -EINVAL;
4971
Arik Nemtsov923b3522015-07-08 15:41:44 +03004972 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
4973 wdev->iftype))
Johannes Bergaa430da2012-05-16 23:50:18 +02004974 return -EINVAL;
4975
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304976 if (info->attrs[NL80211_ATTR_TX_RATES]) {
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +05304977 err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
4978 NL80211_ATTR_TX_RATES,
4979 &params.beacon_rate);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304980 if (err)
4981 return err;
4982
Johannes Berg8564e382016-09-19 09:44:44 +02004983 err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
4984 &params.beacon_rate);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304985 if (err)
4986 return err;
4987 }
4988
Eliad Peller18998c32014-09-10 14:07:34 +03004989 if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
4990 params.smps_mode =
4991 nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
4992 switch (params.smps_mode) {
4993 case NL80211_SMPS_OFF:
4994 break;
4995 case NL80211_SMPS_STATIC:
4996 if (!(rdev->wiphy.features &
4997 NL80211_FEATURE_STATIC_SMPS))
4998 return -EINVAL;
4999 break;
5000 case NL80211_SMPS_DYNAMIC:
5001 if (!(rdev->wiphy.features &
5002 NL80211_FEATURE_DYNAMIC_SMPS))
5003 return -EINVAL;
5004 break;
5005 default:
5006 return -EINVAL;
5007 }
5008 } else {
5009 params.smps_mode = NL80211_SMPS_OFF;
5010 }
5011
Purushottam Kushwaha6e8ef842016-07-05 13:44:51 +05305012 params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
5013 if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
5014 return -EOPNOTSUPP;
5015
Ola Olsson4baf6be2015-10-29 07:04:58 +01005016 if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
5017 params.acl = parse_acl_data(&rdev->wiphy, info);
5018 if (IS_ERR(params.acl))
5019 return PTR_ERR(params.acl);
5020 }
5021
John Crispina0de1ca32019-05-28 13:49:48 +02005022 params.twt_responder =
5023 nla_get_flag(info->attrs[NL80211_ATTR_TWT_RESPONDER]);
5024
John Crispin796e90f2019-07-30 18:37:00 +02005025 if (info->attrs[NL80211_ATTR_HE_OBSS_PD]) {
5026 err = nl80211_parse_he_obss_pd(
5027 info->attrs[NL80211_ATTR_HE_OBSS_PD],
5028 &params.he_obss_pd);
Luca Coelhobc7a39b2020-06-26 12:49:39 +03005029 if (err)
5030 goto out;
John Crispin796e90f2019-07-30 18:37:00 +02005031 }
5032
John Crispin5c5e52d2019-12-17 15:19:18 +01005033 if (info->attrs[NL80211_ATTR_HE_BSS_COLOR]) {
5034 err = nl80211_parse_he_bss_color(
5035 info->attrs[NL80211_ATTR_HE_BSS_COLOR],
5036 &params.he_bss_color);
5037 if (err)
Luca Coelho60a01212020-06-26 12:49:40 +03005038 goto out;
John Crispin5c5e52d2019-12-17 15:19:18 +01005039 }
5040
Johannes Berg66cd7942017-02-07 22:40:44 +02005041 nl80211_calculate_ap_params(&params);
5042
Srinivas Dasarife494372019-01-23 18:06:56 +05305043 if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
5044 params.flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
5045
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005046 wdev_lock(wdev);
Hila Gonene35e4d22012-06-27 17:19:42 +03005047 err = rdev_start_ap(rdev, dev, &params);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02005048 if (!err) {
Johannes Berg683b6d32012-11-08 21:25:48 +01005049 wdev->preset_chandef = params.chandef;
Johannes Berg88600202012-02-13 15:17:18 +01005050 wdev->beacon_interval = params.beacon_interval;
Michal Kazior9e0e2962014-01-29 14:22:27 +01005051 wdev->chandef = params.chandef;
Antonio Quartulli06e191e2012-11-07 12:52:19 +01005052 wdev->ssid_len = params.ssid_len;
5053 memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
Denis Kenzior466a3062018-03-26 12:52:47 -05005054
5055 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
5056 wdev->conn_owner_nlportid = info->snd_portid;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02005057 }
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005058 wdev_unlock(wdev);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05305059
Johannes Berg9951ebf2020-02-21 10:41:43 +01005060out:
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05305061 kfree(params.acl);
5062
Johannes Berg56d18932011-05-09 18:41:15 +02005063 return err;
Johannes Berged1b6cc2007-12-19 02:03:32 +01005064}
5065
Johannes Berg88600202012-02-13 15:17:18 +01005066static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
5067{
5068 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5069 struct net_device *dev = info->user_ptr[1];
5070 struct wireless_dev *wdev = dev->ieee80211_ptr;
5071 struct cfg80211_beacon_data params;
5072 int err;
5073
5074 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
5075 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5076 return -EOPNOTSUPP;
5077
5078 if (!rdev->ops->change_beacon)
5079 return -EOPNOTSUPP;
5080
5081 if (!wdev->beacon_interval)
5082 return -EINVAL;
5083
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07005084 err = nl80211_parse_beacon(rdev, info->attrs, &params);
Johannes Berg88600202012-02-13 15:17:18 +01005085 if (err)
5086 return err;
5087
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005088 wdev_lock(wdev);
5089 err = rdev_change_beacon(rdev, dev, &params);
5090 wdev_unlock(wdev);
5091
5092 return err;
Johannes Berg88600202012-02-13 15:17:18 +01005093}
5094
5095static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
Johannes Berged1b6cc2007-12-19 02:03:32 +01005096{
Johannes Berg4c476992010-10-04 21:36:35 +02005097 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5098 struct net_device *dev = info->user_ptr[1];
Johannes Berged1b6cc2007-12-19 02:03:32 +01005099
Ilan Peer7c8d5e02014-02-25 15:33:38 +02005100 return cfg80211_stop_ap(rdev, dev, false);
Johannes Berged1b6cc2007-12-19 02:03:32 +01005101}
5102
Johannes Berg5727ef12007-12-19 02:03:34 +01005103static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
5104 [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
5105 [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
5106 [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
Jouni Malinen0e467242009-05-11 21:57:55 +03005107 [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
Javier Cardonab39c48f2011-04-07 15:08:30 -07005108 [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
Johannes Bergd83023d2011-12-14 09:29:15 +01005109 [NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },
Johannes Berg5727ef12007-12-19 02:03:34 +01005110};
5111
Johannes Bergeccb8e82009-05-11 21:57:56 +03005112static int parse_station_flags(struct genl_info *info,
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005113 enum nl80211_iftype iftype,
Johannes Bergeccb8e82009-05-11 21:57:56 +03005114 struct station_parameters *params)
Johannes Berg5727ef12007-12-19 02:03:34 +01005115{
5116 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
Johannes Bergeccb8e82009-05-11 21:57:56 +03005117 struct nlattr *nla;
Johannes Berg5727ef12007-12-19 02:03:34 +01005118 int flag;
5119
Johannes Bergeccb8e82009-05-11 21:57:56 +03005120 /*
5121 * Try parsing the new attribute first so userspace
5122 * can specify both for older kernels.
5123 */
5124 nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
5125 if (nla) {
5126 struct nl80211_sta_flag_update *sta_flags;
Johannes Berg5727ef12007-12-19 02:03:34 +01005127
Johannes Bergeccb8e82009-05-11 21:57:56 +03005128 sta_flags = nla_data(nla);
5129 params->sta_flags_mask = sta_flags->mask;
5130 params->sta_flags_set = sta_flags->set;
Johannes Berg77ee7c82013-02-15 00:48:33 +01005131 params->sta_flags_set &= params->sta_flags_mask;
Johannes Bergeccb8e82009-05-11 21:57:56 +03005132 if ((params->sta_flags_mask |
5133 params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
5134 return -EINVAL;
5135 return 0;
5136 }
5137
5138 /* if present, parse the old attribute */
5139
5140 nla = info->attrs[NL80211_ATTR_STA_FLAGS];
Johannes Berg5727ef12007-12-19 02:03:34 +01005141 if (!nla)
5142 return 0;
5143
Johannes Berg8cb08172019-04-26 14:07:28 +02005144 if (nla_parse_nested_deprecated(flags, NL80211_STA_FLAG_MAX, nla, sta_flags_policy, info->extack))
Johannes Berg5727ef12007-12-19 02:03:34 +01005145 return -EINVAL;
5146
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005147 /*
5148 * Only allow certain flags for interface types so that
5149 * other attributes are silently ignored. Remember that
5150 * this is backward compatibility code with old userspace
5151 * and shouldn't be hit in other cases anyway.
5152 */
5153 switch (iftype) {
5154 case NL80211_IFTYPE_AP:
5155 case NL80211_IFTYPE_AP_VLAN:
5156 case NL80211_IFTYPE_P2P_GO:
5157 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
5158 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
5159 BIT(NL80211_STA_FLAG_WME) |
5160 BIT(NL80211_STA_FLAG_MFP);
5161 break;
5162 case NL80211_IFTYPE_P2P_CLIENT:
5163 case NL80211_IFTYPE_STATION:
5164 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
5165 BIT(NL80211_STA_FLAG_TDLS_PEER);
5166 break;
5167 case NL80211_IFTYPE_MESH_POINT:
5168 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5169 BIT(NL80211_STA_FLAG_MFP) |
5170 BIT(NL80211_STA_FLAG_AUTHORIZED);
Bernd Edlinger5cf30062018-07-08 09:57:22 +00005171 break;
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005172 default:
5173 return -EINVAL;
5174 }
Johannes Berg5727ef12007-12-19 02:03:34 +01005175
Johannes Berg3383b5a2012-05-10 20:14:43 +02005176 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
5177 if (flags[flag]) {
Johannes Bergeccb8e82009-05-11 21:57:56 +03005178 params->sta_flags_set |= (1<<flag);
Johannes Berg5727ef12007-12-19 02:03:34 +01005179
Johannes Berg3383b5a2012-05-10 20:14:43 +02005180 /* no longer support new API additions in old API */
5181 if (flag > NL80211_STA_FLAG_MAX_OLD_API)
5182 return -EINVAL;
5183 }
5184 }
5185
Johannes Berg5727ef12007-12-19 02:03:34 +01005186 return 0;
5187}
5188
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02005189bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005190{
5191 struct nlattr *rate;
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03005192 u32 bitrate;
5193 u16 bitrate_compat;
Matthias Kaehlckebbf67e42017-04-17 15:59:52 -07005194 enum nl80211_rate_info rate_flg;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005195
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005196 rate = nla_nest_start_noflag(msg, attr);
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005197 if (!rate)
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005198 return false;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005199
5200 /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
5201 bitrate = cfg80211_calculate_bitrate(info);
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03005202 /* report 16-bit bitrate only if we can */
5203 bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005204 if (bitrate > 0 &&
5205 nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
5206 return false;
5207 if (bitrate_compat > 0 &&
5208 nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
5209 return false;
5210
Johannes Bergb51f3be2015-01-15 16:14:02 +01005211 switch (info->bw) {
5212 case RATE_INFO_BW_5:
5213 rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
5214 break;
5215 case RATE_INFO_BW_10:
5216 rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
5217 break;
5218 default:
5219 WARN_ON(1);
Miaohe Lin7b506ff2020-08-22 04:23:23 -04005220 fallthrough;
Johannes Bergb51f3be2015-01-15 16:14:02 +01005221 case RATE_INFO_BW_20:
5222 rate_flg = 0;
5223 break;
5224 case RATE_INFO_BW_40:
5225 rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
5226 break;
5227 case RATE_INFO_BW_80:
5228 rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
5229 break;
5230 case RATE_INFO_BW_160:
5231 rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
5232 break;
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03005233 case RATE_INFO_BW_HE_RU:
5234 rate_flg = 0;
5235 WARN_ON(!(info->flags & RATE_INFO_FLAGS_HE_MCS));
Johannes Bergb51f3be2015-01-15 16:14:02 +01005236 }
5237
5238 if (rate_flg && nla_put_flag(msg, rate_flg))
5239 return false;
5240
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005241 if (info->flags & RATE_INFO_FLAGS_MCS) {
5242 if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
5243 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005244 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
5245 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
5246 return false;
5247 } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
5248 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
5249 return false;
5250 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
5251 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005252 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
5253 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
5254 return false;
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03005255 } else if (info->flags & RATE_INFO_FLAGS_HE_MCS) {
5256 if (nla_put_u8(msg, NL80211_RATE_INFO_HE_MCS, info->mcs))
5257 return false;
5258 if (nla_put_u8(msg, NL80211_RATE_INFO_HE_NSS, info->nss))
5259 return false;
5260 if (nla_put_u8(msg, NL80211_RATE_INFO_HE_GI, info->he_gi))
5261 return false;
5262 if (nla_put_u8(msg, NL80211_RATE_INFO_HE_DCM, info->he_dcm))
5263 return false;
5264 if (info->bw == RATE_INFO_BW_HE_RU &&
5265 nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
5266 info->he_ru_alloc))
5267 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005268 }
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005269
5270 nla_nest_end(msg, rate);
5271 return true;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005272}
5273
Felix Fietkau119363c2013-04-22 16:29:30 +02005274static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
5275 int id)
5276{
5277 void *attr;
5278 int i = 0;
5279
5280 if (!mask)
5281 return true;
5282
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005283 attr = nla_nest_start_noflag(msg, id);
Felix Fietkau119363c2013-04-22 16:29:30 +02005284 if (!attr)
5285 return false;
5286
5287 for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
5288 if (!(mask & BIT(i)))
5289 continue;
5290
5291 if (nla_put_u8(msg, i, signal[i]))
5292 return false;
5293 }
5294
5295 nla_nest_end(msg, attr);
5296
5297 return true;
5298}
5299
Johannes Bergcf5ead82014-11-14 17:14:00 +01005300static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
5301 u32 seq, int flags,
John W. Linville66266b32012-03-15 13:25:41 -04005302 struct cfg80211_registered_device *rdev,
5303 struct net_device *dev,
Johannes Berg98b62182009-12-23 13:15:44 +01005304 const u8 *mac_addr, struct station_info *sinfo)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005305{
5306 void *hdr;
Paul Stewartf4263c92011-03-31 09:25:41 -07005307 struct nlattr *sinfoattr, *bss_param;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005308
Johannes Bergcf5ead82014-11-14 17:14:00 +01005309 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Andy Strohmanf77bf482019-05-24 23:27:29 -07005310 if (!hdr) {
5311 cfg80211_sinfo_release_content(sinfo);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005312 return -1;
Andy Strohmanf77bf482019-05-24 23:27:29 -07005313 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005314
David S. Miller9360ffd2012-03-29 04:41:26 -04005315 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5316 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
5317 nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
5318 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02005319
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005320 sinfoattr = nla_nest_start_noflag(msg, NL80211_ATTR_STA_INFO);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005321 if (!sinfoattr)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005322 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01005323
5324#define PUT_SINFO(attr, memb, type) do { \
Johannes Bergd686b922016-04-26 09:54:11 +02005325 BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
Omer Efrat397c6572018-06-17 13:06:14 +03005326 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
Johannes Berg319090b2014-11-17 14:08:11 +01005327 nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
5328 sinfo->memb)) \
5329 goto nla_put_failure; \
5330 } while (0)
Johannes Bergd686b922016-04-26 09:54:11 +02005331#define PUT_SINFO_U64(attr, memb) do { \
Omer Efrat397c6572018-06-17 13:06:14 +03005332 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
Johannes Bergd686b922016-04-26 09:54:11 +02005333 nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
5334 sinfo->memb, NL80211_STA_INFO_PAD)) \
5335 goto nla_put_failure; \
5336 } while (0)
Johannes Berg319090b2014-11-17 14:08:11 +01005337
5338 PUT_SINFO(CONNECTED_TIME, connected_time, u32);
5339 PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
Ben Greear6c7a0032019-08-09 11:00:00 -07005340 PUT_SINFO_U64(ASSOC_AT_BOOTTIME, assoc_at);
Johannes Berg319090b2014-11-17 14:08:11 +01005341
Omer Efrat397c6572018-06-17 13:06:14 +03005342 if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES) |
5343 BIT_ULL(NL80211_STA_INFO_RX_BYTES64)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04005344 nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02005345 (u32)sinfo->rx_bytes))
5346 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01005347
Omer Efrat397c6572018-06-17 13:06:14 +03005348 if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES) |
5349 BIT_ULL(NL80211_STA_INFO_TX_BYTES64)) &&
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02005350 nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
5351 (u32)sinfo->tx_bytes))
5352 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01005353
Johannes Bergd686b922016-04-26 09:54:11 +02005354 PUT_SINFO_U64(RX_BYTES64, rx_bytes);
5355 PUT_SINFO_U64(TX_BYTES64, tx_bytes);
Johannes Berg319090b2014-11-17 14:08:11 +01005356 PUT_SINFO(LLID, llid, u16);
5357 PUT_SINFO(PLID, plid, u16);
5358 PUT_SINFO(PLINK_STATE, plink_state, u8);
Johannes Bergd686b922016-04-26 09:54:11 +02005359 PUT_SINFO_U64(RX_DURATION, rx_duration);
Toke Høiland-Jørgensen36647052018-12-18 17:02:07 -08005360 PUT_SINFO_U64(TX_DURATION, tx_duration);
5361
5362 if (wiphy_ext_feature_isset(&rdev->wiphy,
5363 NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
5364 PUT_SINFO(AIRTIME_WEIGHT, airtime_weight, u16);
Johannes Berg319090b2014-11-17 14:08:11 +01005365
John W. Linville66266b32012-03-15 13:25:41 -04005366 switch (rdev->wiphy.signal_type) {
5367 case CFG80211_SIGNAL_TYPE_MBM:
Johannes Berg319090b2014-11-17 14:08:11 +01005368 PUT_SINFO(SIGNAL, signal, u8);
5369 PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
John W. Linville66266b32012-03-15 13:25:41 -04005370 break;
5371 default:
5372 break;
5373 }
Omer Efrat397c6572018-06-17 13:06:14 +03005374 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02005375 if (!nl80211_put_signal(msg, sinfo->chains,
5376 sinfo->chain_signal,
5377 NL80211_STA_INFO_CHAIN_SIGNAL))
5378 goto nla_put_failure;
5379 }
Omer Efrat397c6572018-06-17 13:06:14 +03005380 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02005381 if (!nl80211_put_signal(msg, sinfo->chains,
5382 sinfo->chain_signal_avg,
5383 NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
5384 goto nla_put_failure;
5385 }
Omer Efrat397c6572018-06-17 13:06:14 +03005386 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005387 if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
5388 NL80211_STA_INFO_TX_BITRATE))
Henning Rogge420e7fa2008-12-11 22:04:19 +01005389 goto nla_put_failure;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005390 }
Omer Efrat397c6572018-06-17 13:06:14 +03005391 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005392 if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
5393 NL80211_STA_INFO_RX_BITRATE))
5394 goto nla_put_failure;
Henning Rogge420e7fa2008-12-11 22:04:19 +01005395 }
Johannes Berg319090b2014-11-17 14:08:11 +01005396
5397 PUT_SINFO(RX_PACKETS, rx_packets, u32);
5398 PUT_SINFO(TX_PACKETS, tx_packets, u32);
5399 PUT_SINFO(TX_RETRIES, tx_retries, u32);
5400 PUT_SINFO(TX_FAILED, tx_failed, u32);
5401 PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
Narayanraddi Mastiab606332019-02-07 12:16:05 -08005402 PUT_SINFO(AIRTIME_LINK_METRIC, airtime_link_metric, u32);
Johannes Berg319090b2014-11-17 14:08:11 +01005403 PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
5404 PUT_SINFO(LOCAL_PM, local_pm, u32);
5405 PUT_SINFO(PEER_PM, peer_pm, u32);
5406 PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
Bob Copelanddbdaee72018-10-25 15:48:53 -04005407 PUT_SINFO(CONNECTED_TO_GATE, connected_to_gate, u8);
Markus Theil1303a512020-06-11 16:02:38 +02005408 PUT_SINFO(CONNECTED_TO_AS, connected_to_as, u8);
Johannes Berg319090b2014-11-17 14:08:11 +01005409
Omer Efrat397c6572018-06-17 13:06:14 +03005410 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM)) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005411 bss_param = nla_nest_start_noflag(msg,
5412 NL80211_STA_INFO_BSS_PARAM);
Paul Stewartf4263c92011-03-31 09:25:41 -07005413 if (!bss_param)
5414 goto nla_put_failure;
5415
David S. Miller9360ffd2012-03-29 04:41:26 -04005416 if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
5417 nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
5418 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
5419 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
5420 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
5421 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
5422 nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
5423 sinfo->bss_param.dtim_period) ||
5424 nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
5425 sinfo->bss_param.beacon_interval))
5426 goto nla_put_failure;
Paul Stewartf4263c92011-03-31 09:25:41 -07005427
5428 nla_nest_end(msg, bss_param);
5429 }
Omer Efrat397c6572018-06-17 13:06:14 +03005430 if ((sinfo->filled & BIT_ULL(NL80211_STA_INFO_STA_FLAGS)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04005431 nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
5432 sizeof(struct nl80211_sta_flag_update),
5433 &sinfo->sta_flags))
5434 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01005435
Johannes Bergd686b922016-04-26 09:54:11 +02005436 PUT_SINFO_U64(T_OFFSET, t_offset);
5437 PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
5438 PUT_SINFO_U64(BEACON_RX, rx_beacon);
Johannes Berga76b1942014-11-17 14:12:22 +01005439 PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
Ankita Bajaj0d4e14a2018-09-27 18:01:57 +03005440 PUT_SINFO(RX_MPDUS, rx_mpdu_count, u32);
5441 PUT_SINFO(FCS_ERROR_COUNT, fcs_err_count, u32);
Balaji Pothunoori81d54392018-04-16 20:18:40 +05305442 if (wiphy_ext_feature_isset(&rdev->wiphy,
Balaji Pothunoori9c066022018-07-19 18:56:27 +05305443 NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT)) {
5444 PUT_SINFO(ACK_SIGNAL, ack_signal, u8);
5445 PUT_SINFO(ACK_SIGNAL_AVG, avg_ack_signal, s8);
5446 }
Johannes Berg319090b2014-11-17 14:08:11 +01005447
5448#undef PUT_SINFO
Johannes Bergd686b922016-04-26 09:54:11 +02005449#undef PUT_SINFO_U64
Johannes Berg6de39802014-12-19 12:34:00 +01005450
Arend van Spriel8689c052018-05-10 13:50:12 +02005451 if (sinfo->pertid) {
Johannes Berg6de39802014-12-19 12:34:00 +01005452 struct nlattr *tidsattr;
5453 int tid;
5454
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005455 tidsattr = nla_nest_start_noflag(msg,
5456 NL80211_STA_INFO_TID_STATS);
Johannes Berg6de39802014-12-19 12:34:00 +01005457 if (!tidsattr)
5458 goto nla_put_failure;
5459
5460 for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
5461 struct cfg80211_tid_stats *tidstats;
5462 struct nlattr *tidattr;
5463
5464 tidstats = &sinfo->pertid[tid];
5465
5466 if (!tidstats->filled)
5467 continue;
5468
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005469 tidattr = nla_nest_start_noflag(msg, tid + 1);
Johannes Berg6de39802014-12-19 12:34:00 +01005470 if (!tidattr)
5471 goto nla_put_failure;
5472
Johannes Bergd686b922016-04-26 09:54:11 +02005473#define PUT_TIDVAL_U64(attr, memb) do { \
Johannes Berg6de39802014-12-19 12:34:00 +01005474 if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
Johannes Bergd686b922016-04-26 09:54:11 +02005475 nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
5476 tidstats->memb, NL80211_TID_STATS_PAD)) \
Johannes Berg6de39802014-12-19 12:34:00 +01005477 goto nla_put_failure; \
5478 } while (0)
5479
Johannes Bergd686b922016-04-26 09:54:11 +02005480 PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
5481 PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
5482 PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
5483 PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
Johannes Berg6de39802014-12-19 12:34:00 +01005484
Johannes Bergd686b922016-04-26 09:54:11 +02005485#undef PUT_TIDVAL_U64
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02005486 if ((tidstats->filled &
5487 BIT(NL80211_TID_STATS_TXQ_STATS)) &&
5488 !nl80211_put_txq_stats(msg, &tidstats->txq_stats,
5489 NL80211_TID_STATS_TXQ_STATS))
5490 goto nla_put_failure;
5491
Johannes Berg6de39802014-12-19 12:34:00 +01005492 nla_nest_end(msg, tidattr);
5493 }
5494
5495 nla_nest_end(msg, tidsattr);
5496 }
5497
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005498 nla_nest_end(msg, sinfoattr);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005499
Johannes Berg319090b2014-11-17 14:08:11 +01005500 if (sinfo->assoc_req_ies_len &&
David S. Miller9360ffd2012-03-29 04:41:26 -04005501 nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
5502 sinfo->assoc_req_ies))
5503 goto nla_put_failure;
Jouni Malinen50d3dfb2011-08-08 12:11:52 +03005504
Johannes Berg7ea3e112018-05-18 11:40:44 +02005505 cfg80211_sinfo_release_content(sinfo);
Johannes Berg053c0952015-01-16 22:09:00 +01005506 genlmsg_end(msg, hdr);
5507 return 0;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005508
5509 nla_put_failure:
Johannes Berg7ea3e112018-05-18 11:40:44 +02005510 cfg80211_sinfo_release_content(sinfo);
Thomas Grafbc3ed282008-06-03 16:36:54 -07005511 genlmsg_cancel(msg, hdr);
5512 return -EMSGSIZE;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005513}
5514
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005515static int nl80211_dump_station(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005516 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005517{
Johannes Berg73887fd2018-05-18 09:57:55 +02005518 struct station_info sinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005519 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02005520 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005521 u8 mac_addr[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02005522 int sta_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005523 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005524
Johannes Bergea90e0d2017-03-15 14:26:04 +01005525 rtnl_lock();
Johannes Berg5297c652018-09-27 14:36:44 +02005526 err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02005527 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +01005528 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005529
Johannes Berg97990a02013-04-19 01:02:55 +02005530 if (!wdev->netdev) {
5531 err = -EINVAL;
5532 goto out_err;
5533 }
5534
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005535 if (!rdev->ops->dump_station) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005536 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005537 goto out_err;
5538 }
5539
Johannes Bergbba95fe2008-07-29 13:22:51 +02005540 while (1) {
Johannes Berg73887fd2018-05-18 09:57:55 +02005541 memset(&sinfo, 0, sizeof(sinfo));
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005542 err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
Johannes Berg73887fd2018-05-18 09:57:55 +02005543 mac_addr, &sinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02005544 if (err == -ENOENT)
5545 break;
5546 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01005547 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005548
Johannes Bergcf5ead82014-11-14 17:14:00 +01005549 if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
Eric W. Biederman15e47302012-09-07 20:12:54 +00005550 NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005551 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005552 rdev, wdev->netdev, mac_addr,
Johannes Berg73887fd2018-05-18 09:57:55 +02005553 &sinfo) < 0)
Johannes Bergbba95fe2008-07-29 13:22:51 +02005554 goto out;
5555
5556 sta_idx++;
5557 }
5558
Johannes Bergbba95fe2008-07-29 13:22:51 +02005559 out:
Johannes Berg97990a02013-04-19 01:02:55 +02005560 cb->args[2] = sta_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005561 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005562 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01005563 rtnl_unlock();
Johannes Bergbba95fe2008-07-29 13:22:51 +02005564
5565 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005566}
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005567
Johannes Berg5727ef12007-12-19 02:03:34 +01005568static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
5569{
Johannes Berg4c476992010-10-04 21:36:35 +02005570 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5571 struct net_device *dev = info->user_ptr[1];
Johannes Berg73887fd2018-05-18 09:57:55 +02005572 struct station_info sinfo;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005573 struct sk_buff *msg;
5574 u8 *mac_addr = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02005575 int err;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005576
Johannes Berg73887fd2018-05-18 09:57:55 +02005577 memset(&sinfo, 0, sizeof(sinfo));
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005578
Johannes Berg73887fd2018-05-18 09:57:55 +02005579 if (!info->attrs[NL80211_ATTR_MAC])
5580 return -EINVAL;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005581
5582 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
5583
Johannes Berg73887fd2018-05-18 09:57:55 +02005584 if (!rdev->ops->get_station)
5585 return -EOPNOTSUPP;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005586
Johannes Berg73887fd2018-05-18 09:57:55 +02005587 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005588 if (err)
Johannes Berg73887fd2018-05-18 09:57:55 +02005589 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005590
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005591 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg7ea3e112018-05-18 11:40:44 +02005592 if (!msg) {
Denis Kenziorba8f5662018-05-21 19:21:42 -05005593 cfg80211_sinfo_release_content(&sinfo);
Johannes Berg73887fd2018-05-18 09:57:55 +02005594 return -ENOMEM;
Johannes Berg7ea3e112018-05-18 11:40:44 +02005595 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005596
Johannes Bergcf5ead82014-11-14 17:14:00 +01005597 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
5598 info->snd_portid, info->snd_seq, 0,
Johannes Berg73887fd2018-05-18 09:57:55 +02005599 rdev, dev, mac_addr, &sinfo) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02005600 nlmsg_free(msg);
Johannes Berg73887fd2018-05-18 09:57:55 +02005601 return -ENOBUFS;
Johannes Berg4c476992010-10-04 21:36:35 +02005602 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005603
Johannes Berg73887fd2018-05-18 09:57:55 +02005604 return genlmsg_reply(msg, info);
Johannes Berg5727ef12007-12-19 02:03:34 +01005605}
5606
Johannes Berg77ee7c82013-02-15 00:48:33 +01005607int cfg80211_check_station_change(struct wiphy *wiphy,
5608 struct station_parameters *params,
5609 enum cfg80211_station_type statype)
5610{
Ayala Bekere4208422015-10-23 11:20:06 +03005611 if (params->listen_interval != -1 &&
5612 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01005613 return -EINVAL;
Ayala Bekere4208422015-10-23 11:20:06 +03005614
Ayala Beker17b94242016-03-17 15:41:38 +02005615 if (params->support_p2p_ps != -1 &&
5616 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
5617 return -EINVAL;
5618
Arik Nemtsovc72e1142014-07-17 17:14:29 +03005619 if (params->aid &&
Ayala Bekere4208422015-10-23 11:20:06 +03005620 !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
5621 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01005622 return -EINVAL;
5623
5624 /* When you run into this, adjust the code below for the new flag */
5625 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
5626
5627 switch (statype) {
Thomas Pederseneef941e2013-03-04 13:06:11 -08005628 case CFG80211_STA_MESH_PEER_KERNEL:
5629 case CFG80211_STA_MESH_PEER_USER:
Johannes Berg77ee7c82013-02-15 00:48:33 +01005630 /*
5631 * No ignoring the TDLS flag here -- the userspace mesh
5632 * code doesn't have the bug of including TDLS in the
5633 * mask everywhere.
5634 */
5635 if (params->sta_flags_mask &
5636 ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5637 BIT(NL80211_STA_FLAG_MFP) |
5638 BIT(NL80211_STA_FLAG_AUTHORIZED)))
5639 return -EINVAL;
5640 break;
5641 case CFG80211_STA_TDLS_PEER_SETUP:
5642 case CFG80211_STA_TDLS_PEER_ACTIVE:
5643 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
5644 return -EINVAL;
5645 /* ignore since it can't change */
5646 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
5647 break;
5648 default:
5649 /* disallow mesh-specific things */
5650 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
5651 return -EINVAL;
5652 if (params->local_pm)
5653 return -EINVAL;
5654 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
5655 return -EINVAL;
5656 }
5657
5658 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
5659 statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
5660 /* TDLS can't be set, ... */
5661 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
5662 return -EINVAL;
5663 /*
5664 * ... but don't bother the driver with it. This works around
5665 * a hostapd/wpa_supplicant issue -- it always includes the
5666 * TLDS_PEER flag in the mask even for AP mode.
5667 */
5668 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
5669 }
5670
Ayala Beker47edb112015-09-21 15:49:53 +03005671 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
5672 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01005673 /* reject other things that can't change */
5674 if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
5675 return -EINVAL;
5676 if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
5677 return -EINVAL;
5678 if (params->supported_rates)
5679 return -EINVAL;
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03005680 if (params->ext_capab || params->ht_capa || params->vht_capa ||
5681 params->he_capa)
Johannes Berg77ee7c82013-02-15 00:48:33 +01005682 return -EINVAL;
5683 }
5684
Ayala Beker47edb112015-09-21 15:49:53 +03005685 if (statype != CFG80211_STA_AP_CLIENT &&
5686 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01005687 if (params->vlan)
5688 return -EINVAL;
5689 }
5690
5691 switch (statype) {
5692 case CFG80211_STA_AP_MLME_CLIENT:
5693 /* Use this only for authorizing/unauthorizing a station */
5694 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
5695 return -EOPNOTSUPP;
5696 break;
5697 case CFG80211_STA_AP_CLIENT:
Ayala Beker47edb112015-09-21 15:49:53 +03005698 case CFG80211_STA_AP_CLIENT_UNASSOC:
Johannes Berg77ee7c82013-02-15 00:48:33 +01005699 /* accept only the listed bits */
5700 if (params->sta_flags_mask &
5701 ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
5702 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5703 BIT(NL80211_STA_FLAG_ASSOCIATED) |
5704 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
5705 BIT(NL80211_STA_FLAG_WME) |
5706 BIT(NL80211_STA_FLAG_MFP)))
5707 return -EINVAL;
5708
5709 /* but authenticated/associated only if driver handles it */
5710 if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
5711 params->sta_flags_mask &
5712 (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5713 BIT(NL80211_STA_FLAG_ASSOCIATED)))
5714 return -EINVAL;
5715 break;
5716 case CFG80211_STA_IBSS:
5717 case CFG80211_STA_AP_STA:
5718 /* reject any changes other than AUTHORIZED */
5719 if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
5720 return -EINVAL;
5721 break;
5722 case CFG80211_STA_TDLS_PEER_SETUP:
5723 /* reject any changes other than AUTHORIZED or WME */
5724 if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
5725 BIT(NL80211_STA_FLAG_WME)))
5726 return -EINVAL;
5727 /* force (at least) rates when authorizing */
5728 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
5729 !params->supported_rates)
5730 return -EINVAL;
5731 break;
5732 case CFG80211_STA_TDLS_PEER_ACTIVE:
5733 /* reject any changes */
5734 return -EINVAL;
Thomas Pederseneef941e2013-03-04 13:06:11 -08005735 case CFG80211_STA_MESH_PEER_KERNEL:
Johannes Berg77ee7c82013-02-15 00:48:33 +01005736 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
5737 return -EINVAL;
5738 break;
Thomas Pederseneef941e2013-03-04 13:06:11 -08005739 case CFG80211_STA_MESH_PEER_USER:
Chun-Yeow Yeoh42925042015-04-18 01:30:02 +08005740 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
5741 params->plink_action != NL80211_PLINK_ACTION_BLOCK)
Johannes Berg77ee7c82013-02-15 00:48:33 +01005742 return -EINVAL;
5743 break;
5744 }
5745
Beni Lev06f7c882016-07-19 19:28:56 +03005746 /*
5747 * Older kernel versions ignored this attribute entirely, so don't
5748 * reject attempts to update it but mark it as unused instead so the
5749 * driver won't look at the data.
5750 */
5751 if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
5752 statype != CFG80211_STA_TDLS_PEER_SETUP)
5753 params->opmode_notif_used = false;
5754
Johannes Berg77ee7c82013-02-15 00:48:33 +01005755 return 0;
5756}
5757EXPORT_SYMBOL(cfg80211_check_station_change);
5758
Johannes Berg5727ef12007-12-19 02:03:34 +01005759/*
Felix Fietkauc258d2d2009-11-11 17:23:31 +01005760 * Get vlan interface making sure it is running and on the right wiphy.
Johannes Berg5727ef12007-12-19 02:03:34 +01005761 */
Johannes Berg80b99892011-11-18 16:23:01 +01005762static struct net_device *get_vlan(struct genl_info *info,
5763 struct cfg80211_registered_device *rdev)
Johannes Berg5727ef12007-12-19 02:03:34 +01005764{
Johannes Berg463d0182009-07-14 00:33:35 +02005765 struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
Johannes Berg80b99892011-11-18 16:23:01 +01005766 struct net_device *v;
5767 int ret;
Johannes Berg5727ef12007-12-19 02:03:34 +01005768
Johannes Berg80b99892011-11-18 16:23:01 +01005769 if (!vlanattr)
5770 return NULL;
5771
5772 v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
5773 if (!v)
5774 return ERR_PTR(-ENODEV);
5775
5776 if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
5777 ret = -EINVAL;
5778 goto error;
Johannes Berg5727ef12007-12-19 02:03:34 +01005779 }
Johannes Berg80b99892011-11-18 16:23:01 +01005780
Johannes Berg77ee7c82013-02-15 00:48:33 +01005781 if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
5782 v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
5783 v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
5784 ret = -EINVAL;
5785 goto error;
5786 }
5787
Johannes Berg80b99892011-11-18 16:23:01 +01005788 if (!netif_running(v)) {
5789 ret = -ENETDOWN;
5790 goto error;
5791 }
5792
5793 return v;
5794 error:
5795 dev_put(v);
5796 return ERR_PTR(ret);
Johannes Berg5727ef12007-12-19 02:03:34 +01005797}
5798
Johannes Berg94e860f2014-01-20 23:58:15 +01005799static const struct nla_policy
5800nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
Jouni Malinendf881292013-02-14 21:10:54 +02005801 [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
5802 [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
5803};
5804
Johannes Bergff276692013-02-15 00:09:01 +01005805static int nl80211_parse_sta_wme(struct genl_info *info,
5806 struct station_parameters *params)
Jouni Malinendf881292013-02-14 21:10:54 +02005807{
Jouni Malinendf881292013-02-14 21:10:54 +02005808 struct nlattr *tb[NL80211_STA_WME_MAX + 1];
5809 struct nlattr *nla;
5810 int err;
5811
Jouni Malinendf881292013-02-14 21:10:54 +02005812 /* parse WME attributes if present */
5813 if (!info->attrs[NL80211_ATTR_STA_WME])
5814 return 0;
5815
5816 nla = info->attrs[NL80211_ATTR_STA_WME];
Johannes Berg8cb08172019-04-26 14:07:28 +02005817 err = nla_parse_nested_deprecated(tb, NL80211_STA_WME_MAX, nla,
5818 nl80211_sta_wme_policy,
5819 info->extack);
Jouni Malinendf881292013-02-14 21:10:54 +02005820 if (err)
5821 return err;
5822
5823 if (tb[NL80211_STA_WME_UAPSD_QUEUES])
5824 params->uapsd_queues = nla_get_u8(
5825 tb[NL80211_STA_WME_UAPSD_QUEUES]);
5826 if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
5827 return -EINVAL;
5828
5829 if (tb[NL80211_STA_WME_MAX_SP])
5830 params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
5831
5832 if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
5833 return -EINVAL;
5834
5835 params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
5836
5837 return 0;
5838}
5839
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305840static int nl80211_parse_sta_channel_info(struct genl_info *info,
5841 struct station_parameters *params)
5842{
5843 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
5844 params->supported_channels =
5845 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
5846 params->supported_channels_len =
5847 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
5848 /*
5849 * Need to include at least one (first channel, number of
Johannes Bergcb9abd42020-08-05 15:47:16 +02005850 * channels) tuple for each subband (checked in policy),
5851 * and must have proper tuples for the rest of the data as well.
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305852 */
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305853 if (params->supported_channels_len % 2)
5854 return -EINVAL;
5855 }
5856
5857 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
5858 params->supported_oper_classes =
5859 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
5860 params->supported_oper_classes_len =
5861 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305862 }
5863 return 0;
5864}
5865
Johannes Bergff276692013-02-15 00:09:01 +01005866static int nl80211_set_station_tdls(struct genl_info *info,
5867 struct station_parameters *params)
5868{
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305869 int err;
Johannes Bergff276692013-02-15 00:09:01 +01005870 /* Dummy STA entry gets updated once the peer capabilities are known */
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03005871 if (info->attrs[NL80211_ATTR_PEER_AID])
5872 params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Johannes Bergff276692013-02-15 00:09:01 +01005873 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
5874 params->ht_capa =
5875 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
5876 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
5877 params->vht_capa =
5878 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03005879 if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
5880 params->he_capa =
5881 nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
5882 params->he_capa_len =
5883 nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03005884 }
Johannes Bergff276692013-02-15 00:09:01 +01005885
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305886 err = nl80211_parse_sta_channel_info(info, params);
5887 if (err)
5888 return err;
5889
Johannes Bergff276692013-02-15 00:09:01 +01005890 return nl80211_parse_sta_wme(info, params);
5891}
5892
Ashok Raj Nagarajane96d1cd2019-03-29 16:18:21 +05305893static int nl80211_parse_sta_txpower_setting(struct genl_info *info,
5894 struct station_parameters *params)
5895{
5896 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5897 int idx;
5898
5899 if (info->attrs[NL80211_ATTR_STA_TX_POWER_SETTING]) {
5900 if (!rdev->ops->set_tx_power ||
5901 !wiphy_ext_feature_isset(&rdev->wiphy,
5902 NL80211_EXT_FEATURE_STA_TX_PWR))
5903 return -EOPNOTSUPP;
5904
5905 idx = NL80211_ATTR_STA_TX_POWER_SETTING;
5906 params->txpwr.type = nla_get_u8(info->attrs[idx]);
5907
5908 if (params->txpwr.type == NL80211_TX_POWER_LIMITED) {
5909 idx = NL80211_ATTR_STA_TX_POWER;
5910
5911 if (info->attrs[idx])
5912 params->txpwr.power =
5913 nla_get_s16(info->attrs[idx]);
5914 else
5915 return -EINVAL;
5916 }
5917 params->sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER;
5918 }
5919
5920 return 0;
5921}
5922
Johannes Berg5727ef12007-12-19 02:03:34 +01005923static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
5924{
Johannes Berg4c476992010-10-04 21:36:35 +02005925 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02005926 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01005927 struct station_parameters params;
Johannes Berg77ee7c82013-02-15 00:48:33 +01005928 u8 *mac_addr;
5929 int err;
Johannes Berg5727ef12007-12-19 02:03:34 +01005930
5931 memset(&params, 0, sizeof(params));
5932
Johannes Berg77ee7c82013-02-15 00:48:33 +01005933 if (!rdev->ops->change_station)
5934 return -EOPNOTSUPP;
5935
Ayala Bekere4208422015-10-23 11:20:06 +03005936 /*
5937 * AID and listen_interval properties can be set only for unassociated
5938 * station. Include these parameters here and will check them in
5939 * cfg80211_check_station_change().
5940 */
Ayala Bekera9bc31e2015-11-26 16:26:12 +01005941 if (info->attrs[NL80211_ATTR_STA_AID])
5942 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Ayala Bekere4208422015-10-23 11:20:06 +03005943
Gurumoorthi Gnanasambandhan14f34e362019-10-31 23:46:40 +02005944 if (info->attrs[NL80211_ATTR_VLAN_ID])
5945 params.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);
5946
Ayala Bekere4208422015-10-23 11:20:06 +03005947 if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
5948 params.listen_interval =
5949 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
5950 else
5951 params.listen_interval = -1;
Johannes Berg5727ef12007-12-19 02:03:34 +01005952
Johannes Bergab0d76f2018-10-02 10:00:07 +02005953 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS])
5954 params.support_p2p_ps =
5955 nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
5956 else
Ayala Beker17b94242016-03-17 15:41:38 +02005957 params.support_p2p_ps = -1;
Ayala Beker17b94242016-03-17 15:41:38 +02005958
Johannes Berg5727ef12007-12-19 02:03:34 +01005959 if (!info->attrs[NL80211_ATTR_MAC])
5960 return -EINVAL;
5961
5962 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
5963
5964 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
5965 params.supported_rates =
5966 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5967 params.supported_rates_len =
5968 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5969 }
5970
Jouni Malinen9d62a982013-02-14 21:10:13 +02005971 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
5972 params.capability =
5973 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
5974 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
5975 }
5976
5977 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
5978 params.ext_capab =
5979 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5980 params.ext_capab_len =
5981 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5982 }
5983
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005984 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01005985 return -EINVAL;
5986
Johannes Bergab0d76f2018-10-02 10:00:07 +02005987 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005988 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01005989 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005990
Johannes Bergf8bacc22013-02-14 23:27:01 +01005991 if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
Javier Cardona9c3990a2011-05-03 16:57:11 -07005992 params.plink_state =
Johannes Bergf8bacc22013-02-14 23:27:01 +01005993 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
Johannes Bergab0d76f2018-10-02 10:00:07 +02005994 if (info->attrs[NL80211_ATTR_MESH_PEER_AID])
Masashi Honma7d27a0b2016-07-01 10:19:34 +09005995 params.peer_aid = nla_get_u16(
5996 info->attrs[NL80211_ATTR_MESH_PEER_AID]);
Johannes Bergf8bacc22013-02-14 23:27:01 +01005997 params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
5998 }
Javier Cardona9c3990a2011-05-03 16:57:11 -07005999
Johannes Bergab0d76f2018-10-02 10:00:07 +02006000 if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE])
6001 params.local_pm = nla_get_u32(
Marco Porsch3b1c5a52013-01-07 16:04:52 +01006002 info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
6003
Beni Lev06f7c882016-07-19 19:28:56 +03006004 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
6005 params.opmode_notif_used = true;
6006 params.opmode_notif =
6007 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
6008 }
6009
Rajkumar Manoharan43e64bf2020-05-28 21:34:29 +02006010 if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
6011 params.he_6ghz_capa =
6012 nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
6013
Toke Høiland-Jørgensen36647052018-12-18 17:02:07 -08006014 if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
6015 params.airtime_weight =
6016 nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
6017
6018 if (params.airtime_weight &&
6019 !wiphy_ext_feature_isset(&rdev->wiphy,
6020 NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
6021 return -EOPNOTSUPP;
6022
Ashok Raj Nagarajane96d1cd2019-03-29 16:18:21 +05306023 err = nl80211_parse_sta_txpower_setting(info, &params);
6024 if (err)
6025 return err;
6026
Johannes Berg77ee7c82013-02-15 00:48:33 +01006027 /* Include parameters for TDLS peer (will check later) */
6028 err = nl80211_set_station_tdls(info, &params);
6029 if (err)
6030 return err;
6031
6032 params.vlan = get_vlan(info, rdev);
6033 if (IS_ERR(params.vlan))
6034 return PTR_ERR(params.vlan);
6035
Johannes Berga97f4422009-06-18 17:23:43 +02006036 switch (dev->ieee80211_ptr->iftype) {
6037 case NL80211_IFTYPE_AP:
6038 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02006039 case NL80211_IFTYPE_P2P_GO:
Johannes Berg074ac8d2010-09-16 14:58:22 +02006040 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berga97f4422009-06-18 17:23:43 +02006041 case NL80211_IFTYPE_STATION:
Antonio Quartulli267335d2012-01-31 20:25:47 +01006042 case NL80211_IFTYPE_ADHOC:
Johannes Berga97f4422009-06-18 17:23:43 +02006043 case NL80211_IFTYPE_MESH_POINT:
Johannes Berga97f4422009-06-18 17:23:43 +02006044 break;
6045 default:
Johannes Berg77ee7c82013-02-15 00:48:33 +01006046 err = -EOPNOTSUPP;
6047 goto out_put_vlan;
Johannes Berg034d6552009-05-27 10:35:29 +02006048 }
6049
Johannes Berg77ee7c82013-02-15 00:48:33 +01006050 /* driver will call cfg80211_check_station_change() */
Hila Gonene35e4d22012-06-27 17:19:42 +03006051 err = rdev_change_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01006052
Johannes Berg77ee7c82013-02-15 00:48:33 +01006053 out_put_vlan:
Johannes Berg5727ef12007-12-19 02:03:34 +01006054 if (params.vlan)
6055 dev_put(params.vlan);
Johannes Berg3b858752009-03-12 09:55:09 +01006056
Johannes Berg5727ef12007-12-19 02:03:34 +01006057 return err;
6058}
6059
6060static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
6061{
Johannes Berg4c476992010-10-04 21:36:35 +02006062 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg5727ef12007-12-19 02:03:34 +01006063 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02006064 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01006065 struct station_parameters params;
6066 u8 *mac_addr = NULL;
Johannes Bergbda95eb2015-11-26 16:26:13 +01006067 u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
6068 BIT(NL80211_STA_FLAG_ASSOCIATED);
Johannes Berg5727ef12007-12-19 02:03:34 +01006069
6070 memset(&params, 0, sizeof(params));
6071
Johannes Berg984c3112013-02-14 23:43:25 +01006072 if (!rdev->ops->add_station)
6073 return -EOPNOTSUPP;
6074
Johannes Berg5727ef12007-12-19 02:03:34 +01006075 if (!info->attrs[NL80211_ATTR_MAC])
6076 return -EINVAL;
6077
Johannes Berg5727ef12007-12-19 02:03:34 +01006078 if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
6079 return -EINVAL;
6080
6081 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
6082 return -EINVAL;
6083
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03006084 if (!info->attrs[NL80211_ATTR_STA_AID] &&
6085 !info->attrs[NL80211_ATTR_PEER_AID])
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02006086 return -EINVAL;
6087
Johannes Berg5727ef12007-12-19 02:03:34 +01006088 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
6089 params.supported_rates =
6090 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
6091 params.supported_rates_len =
6092 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
6093 params.listen_interval =
6094 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
Johannes Berg51b50fb2009-05-24 16:42:30 +02006095
Gurumoorthi Gnanasambandhan14f34e362019-10-31 23:46:40 +02006096 if (info->attrs[NL80211_ATTR_VLAN_ID])
6097 params.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);
6098
Ayala Beker17b94242016-03-17 15:41:38 +02006099 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
Johannes Bergab0d76f2018-10-02 10:00:07 +02006100 params.support_p2p_ps =
6101 nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
Ayala Beker17b94242016-03-17 15:41:38 +02006102 } else {
6103 /*
6104 * if not specified, assume it's supported for P2P GO interface,
6105 * and is NOT supported for AP interface
6106 */
6107 params.support_p2p_ps =
6108 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO;
6109 }
6110
Jouni Malinen3d124ea2013-05-27 18:24:02 +03006111 if (info->attrs[NL80211_ATTR_PEER_AID])
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03006112 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Jouni Malinen3d124ea2013-05-27 18:24:02 +03006113 else
6114 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Johannes Berg51b50fb2009-05-24 16:42:30 +02006115
Jouni Malinen9d62a982013-02-14 21:10:13 +02006116 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
6117 params.capability =
6118 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
6119 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
6120 }
6121
6122 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
6123 params.ext_capab =
6124 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
6125 params.ext_capab_len =
6126 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
6127 }
6128
Jouni Malinen36aedc92008-08-25 11:58:58 +03006129 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
6130 params.ht_capa =
6131 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
Johannes Berg5727ef12007-12-19 02:03:34 +01006132
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +00006133 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
6134 params.vht_capa =
6135 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
6136
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006137 if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
6138 params.he_capa =
6139 nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
6140 params.he_capa_len =
6141 nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006142 }
6143
Rajkumar Manoharan43e64bf2020-05-28 21:34:29 +02006144 if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
6145 params.he_6ghz_capa =
6146 nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
6147
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +01006148 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
6149 params.opmode_notif_used = true;
6150 params.opmode_notif =
6151 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
6152 }
6153
Johannes Bergab0d76f2018-10-02 10:00:07 +02006154 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
Javier Cardona96b78df2011-04-07 15:08:33 -07006155 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01006156 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
Javier Cardona96b78df2011-04-07 15:08:33 -07006157
Toke Høiland-Jørgensen36647052018-12-18 17:02:07 -08006158 if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
6159 params.airtime_weight =
6160 nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
6161
6162 if (params.airtime_weight &&
6163 !wiphy_ext_feature_isset(&rdev->wiphy,
6164 NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
6165 return -EOPNOTSUPP;
6166
Ashok Raj Nagarajane96d1cd2019-03-29 16:18:21 +05306167 err = nl80211_parse_sta_txpower_setting(info, &params);
6168 if (err)
6169 return err;
6170
Sunil Duttc01fc9a2013-10-09 20:45:21 +05306171 err = nl80211_parse_sta_channel_info(info, &params);
6172 if (err)
6173 return err;
6174
Johannes Bergff276692013-02-15 00:09:01 +01006175 err = nl80211_parse_sta_wme(info, &params);
6176 if (err)
6177 return err;
Johannes Bergbdd90d52011-12-14 12:20:27 +01006178
Johannes Bergbdd3ae32012-01-02 13:30:03 +01006179 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01006180 return -EINVAL;
6181
Johannes Berg496fcc22015-03-12 08:53:27 +02006182 /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
6183 * as userspace might just pass through the capabilities from the IEs
6184 * directly, rather than enforcing this restriction and returning an
6185 * error in this case.
6186 */
6187 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
6188 params.ht_capa = NULL;
6189 params.vht_capa = NULL;
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006190
6191 /* HE requires WME */
Rajkumar Manoharan43e64bf2020-05-28 21:34:29 +02006192 if (params.he_capa_len || params.he_6ghz_capa)
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006193 return -EINVAL;
Johannes Berg496fcc22015-03-12 08:53:27 +02006194 }
6195
Rajkumar Manoharan43e64bf2020-05-28 21:34:29 +02006196 /* Ensure that HT/VHT capabilities are not set for 6 GHz HE STA */
6197 if (params.he_6ghz_capa && (params.ht_capa || params.vht_capa))
6198 return -EINVAL;
6199
Johannes Berg77ee7c82013-02-15 00:48:33 +01006200 /* When you run into this, adjust the code below for the new flag */
6201 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
6202
Johannes Bergbdd90d52011-12-14 12:20:27 +01006203 switch (dev->ieee80211_ptr->iftype) {
6204 case NL80211_IFTYPE_AP:
6205 case NL80211_IFTYPE_AP_VLAN:
6206 case NL80211_IFTYPE_P2P_GO:
Johannes Berg984c3112013-02-14 23:43:25 +01006207 /* ignore WME attributes if iface/sta is not capable */
6208 if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
6209 !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
6210 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
Eliad Pellerc75786c2011-08-23 14:37:46 +03006211
Johannes Bergbdd90d52011-12-14 12:20:27 +01006212 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03006213 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
6214 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02006215 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01006216 /* but don't bother the driver with it */
6217 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
Eliad Pellerc75786c2011-08-23 14:37:46 +03006218
Johannes Bergd582cff2012-10-26 17:53:44 +02006219 /* allow authenticated/associated only if driver handles it */
6220 if (!(rdev->wiphy.features &
6221 NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
Johannes Bergbda95eb2015-11-26 16:26:13 +01006222 params.sta_flags_mask & auth_assoc)
Johannes Bergd582cff2012-10-26 17:53:44 +02006223 return -EINVAL;
6224
Johannes Bergbda95eb2015-11-26 16:26:13 +01006225 /* Older userspace, or userspace wanting to be compatible with
6226 * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
6227 * and assoc flags in the mask, but assumes the station will be
6228 * added as associated anyway since this was the required driver
6229 * behaviour before NL80211_FEATURE_FULL_AP_CLIENT_STATE was
6230 * introduced.
6231 * In order to not bother drivers with this quirk in the API
6232 * set the flags in both the mask and set for new stations in
6233 * this case.
6234 */
6235 if (!(params.sta_flags_mask & auth_assoc)) {
6236 params.sta_flags_mask |= auth_assoc;
6237 params.sta_flags_set |= auth_assoc;
6238 }
6239
Johannes Bergbdd90d52011-12-14 12:20:27 +01006240 /* must be last in here for error handling */
6241 params.vlan = get_vlan(info, rdev);
6242 if (IS_ERR(params.vlan))
6243 return PTR_ERR(params.vlan);
6244 break;
6245 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg984c3112013-02-14 23:43:25 +01006246 /* ignore uAPSD data */
6247 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
6248
Johannes Bergd582cff2012-10-26 17:53:44 +02006249 /* associated is disallowed */
6250 if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
6251 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01006252 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03006253 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
6254 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02006255 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01006256 break;
6257 case NL80211_IFTYPE_STATION:
Johannes Berg93d08f02013-03-04 09:29:46 +01006258 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg984c3112013-02-14 23:43:25 +01006259 /* ignore uAPSD data */
6260 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
6261
Johannes Berg77ee7c82013-02-15 00:48:33 +01006262 /* these are disallowed */
6263 if (params.sta_flags_mask &
6264 (BIT(NL80211_STA_FLAG_ASSOCIATED) |
6265 BIT(NL80211_STA_FLAG_AUTHENTICATED)))
Johannes Bergd582cff2012-10-26 17:53:44 +02006266 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01006267 /* Only TDLS peers can be added */
6268 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
6269 return -EINVAL;
6270 /* Can only add if TDLS ... */
6271 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
6272 return -EOPNOTSUPP;
6273 /* ... with external setup is supported */
6274 if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
6275 return -EOPNOTSUPP;
Johannes Berg77ee7c82013-02-15 00:48:33 +01006276 /*
6277 * Older wpa_supplicant versions always mark the TDLS peer
6278 * as authorized, but it shouldn't yet be.
6279 */
6280 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
Johannes Bergbdd90d52011-12-14 12:20:27 +01006281 break;
6282 default:
6283 return -EOPNOTSUPP;
Eliad Pellerc75786c2011-08-23 14:37:46 +03006284 }
6285
Johannes Bergbdd90d52011-12-14 12:20:27 +01006286 /* be aware of params.vlan when changing code here */
Johannes Berg5727ef12007-12-19 02:03:34 +01006287
Hila Gonene35e4d22012-06-27 17:19:42 +03006288 err = rdev_add_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01006289
Johannes Berg5727ef12007-12-19 02:03:34 +01006290 if (params.vlan)
6291 dev_put(params.vlan);
Johannes Berg5727ef12007-12-19 02:03:34 +01006292 return err;
6293}
6294
6295static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
6296{
Johannes Berg4c476992010-10-04 21:36:35 +02006297 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6298 struct net_device *dev = info->user_ptr[1];
Jouni Malinen89c771e2014-10-10 20:52:40 +03006299 struct station_del_parameters params;
6300
6301 memset(&params, 0, sizeof(params));
Johannes Berg5727ef12007-12-19 02:03:34 +01006302
6303 if (info->attrs[NL80211_ATTR_MAC])
Jouni Malinen89c771e2014-10-10 20:52:40 +03006304 params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg5727ef12007-12-19 02:03:34 +01006305
Johannes Berg306b79e2020-03-20 11:38:35 +01006306 switch (dev->ieee80211_ptr->iftype) {
6307 case NL80211_IFTYPE_AP:
6308 case NL80211_IFTYPE_AP_VLAN:
6309 case NL80211_IFTYPE_MESH_POINT:
6310 case NL80211_IFTYPE_P2P_GO:
6311 /* always accept these */
6312 break;
6313 case NL80211_IFTYPE_ADHOC:
6314 /* conditionally accept */
6315 if (wiphy_ext_feature_isset(&rdev->wiphy,
6316 NL80211_EXT_FEATURE_DEL_IBSS_STA))
6317 break;
Nicolas Cavallariedafcf42020-03-05 14:57:53 +01006318 return -EINVAL;
Johannes Berg306b79e2020-03-20 11:38:35 +01006319 default:
Johannes Berg4c476992010-10-04 21:36:35 +02006320 return -EINVAL;
Johannes Berg306b79e2020-03-20 11:38:35 +01006321 }
Johannes Berge80cf852009-05-11 14:43:13 +02006322
Johannes Berg4c476992010-10-04 21:36:35 +02006323 if (!rdev->ops->del_station)
6324 return -EOPNOTSUPP;
Johannes Berg5727ef12007-12-19 02:03:34 +01006325
Jouni Malinen98856862014-10-20 13:20:45 +03006326 if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
6327 params.subtype =
6328 nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
6329 if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
6330 params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
6331 return -EINVAL;
6332 } else {
6333 /* Default to Deauthentication frame */
6334 params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
6335 }
6336
6337 if (info->attrs[NL80211_ATTR_REASON_CODE]) {
6338 params.reason_code =
6339 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
6340 if (params.reason_code == 0)
6341 return -EINVAL; /* 0 is reserved */
6342 } else {
6343 /* Default to reason code 2 */
6344 params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
6345 }
6346
Jouni Malinen89c771e2014-10-10 20:52:40 +03006347 return rdev_del_station(rdev, dev, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01006348}
6349
Eric W. Biederman15e47302012-09-07 20:12:54 +00006350static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006351 int flags, struct net_device *dev,
6352 u8 *dst, u8 *next_hop,
6353 struct mpath_info *pinfo)
6354{
6355 void *hdr;
6356 struct nlattr *pinfoattr;
6357
Henning Rogge1ef4c852014-11-04 16:14:58 +01006358 hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006359 if (!hdr)
6360 return -1;
6361
David S. Miller9360ffd2012-03-29 04:41:26 -04006362 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
6363 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
6364 nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
6365 nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
6366 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02006367
Michal Kubecekae0be8d2019-04-26 11:13:06 +02006368 pinfoattr = nla_nest_start_noflag(msg, NL80211_ATTR_MPATH_INFO);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006369 if (!pinfoattr)
6370 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04006371 if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
6372 nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
6373 pinfo->frame_qlen))
6374 goto nla_put_failure;
6375 if (((pinfo->filled & MPATH_INFO_SN) &&
6376 nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
6377 ((pinfo->filled & MPATH_INFO_METRIC) &&
6378 nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
6379 pinfo->metric)) ||
6380 ((pinfo->filled & MPATH_INFO_EXPTIME) &&
6381 nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
6382 pinfo->exptime)) ||
6383 ((pinfo->filled & MPATH_INFO_FLAGS) &&
6384 nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
6385 pinfo->flags)) ||
6386 ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
6387 nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
6388 pinfo->discovery_timeout)) ||
6389 ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
6390 nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
Julan Hsucc241632019-01-15 15:28:42 -08006391 pinfo->discovery_retries)) ||
6392 ((pinfo->filled & MPATH_INFO_HOP_COUNT) &&
6393 nla_put_u8(msg, NL80211_MPATH_INFO_HOP_COUNT,
Julan Hsu540bbcb2019-01-15 15:28:43 -08006394 pinfo->hop_count)) ||
6395 ((pinfo->filled & MPATH_INFO_PATH_CHANGE) &&
6396 nla_put_u32(msg, NL80211_MPATH_INFO_PATH_CHANGE,
6397 pinfo->path_change_count)))
David S. Miller9360ffd2012-03-29 04:41:26 -04006398 goto nla_put_failure;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006399
6400 nla_nest_end(msg, pinfoattr);
6401
Johannes Berg053c0952015-01-16 22:09:00 +01006402 genlmsg_end(msg, hdr);
6403 return 0;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006404
6405 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07006406 genlmsg_cancel(msg, hdr);
6407 return -EMSGSIZE;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006408}
6409
6410static int nl80211_dump_mpath(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02006411 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006412{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006413 struct mpath_info pinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08006414 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02006415 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006416 u8 dst[ETH_ALEN];
6417 u8 next_hop[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02006418 int path_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006419 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006420
Johannes Bergea90e0d2017-03-15 14:26:04 +01006421 rtnl_lock();
Johannes Berg5297c652018-09-27 14:36:44 +02006422 err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02006423 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +01006424 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02006425
Zhao, Gang1b8ec872014-04-21 12:53:02 +08006426 if (!rdev->ops->dump_mpath) {
Jouni Malineneec60b02009-03-20 21:21:19 +02006427 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02006428 goto out_err;
6429 }
6430
Johannes Berg97990a02013-04-19 01:02:55 +02006431 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
Jouni Malineneec60b02009-03-20 21:21:19 +02006432 err = -EOPNOTSUPP;
Roel Kluin0448b5f2009-08-22 21:15:49 +02006433 goto out_err;
Jouni Malineneec60b02009-03-20 21:21:19 +02006434 }
6435
Johannes Bergbba95fe2008-07-29 13:22:51 +02006436 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08006437 err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
Johannes Berg97990a02013-04-19 01:02:55 +02006438 next_hop, &pinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02006439 if (err == -ENOENT)
6440 break;
6441 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01006442 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02006443
Eric W. Biederman15e47302012-09-07 20:12:54 +00006444 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02006445 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg97990a02013-04-19 01:02:55 +02006446 wdev->netdev, dst, next_hop,
Johannes Bergbba95fe2008-07-29 13:22:51 +02006447 &pinfo) < 0)
6448 goto out;
6449
6450 path_idx++;
6451 }
6452
Johannes Bergbba95fe2008-07-29 13:22:51 +02006453 out:
Johannes Berg97990a02013-04-19 01:02:55 +02006454 cb->args[2] = path_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02006455 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02006456 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01006457 rtnl_unlock();
Johannes Bergbba95fe2008-07-29 13:22:51 +02006458 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006459}
6460
6461static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
6462{
Johannes Berg4c476992010-10-04 21:36:35 +02006463 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006464 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02006465 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006466 struct mpath_info pinfo;
6467 struct sk_buff *msg;
6468 u8 *dst = NULL;
6469 u8 next_hop[ETH_ALEN];
6470
6471 memset(&pinfo, 0, sizeof(pinfo));
6472
6473 if (!info->attrs[NL80211_ATTR_MAC])
6474 return -EINVAL;
6475
6476 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
6477
Johannes Berg4c476992010-10-04 21:36:35 +02006478 if (!rdev->ops->get_mpath)
6479 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01006480
Johannes Berg4c476992010-10-04 21:36:35 +02006481 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
6482 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02006483
Hila Gonene35e4d22012-06-27 17:19:42 +03006484 err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006485 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02006486 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006487
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07006488 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006489 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02006490 return -ENOMEM;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006491
Eric W. Biederman15e47302012-09-07 20:12:54 +00006492 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg4c476992010-10-04 21:36:35 +02006493 dev, dst, next_hop, &pinfo) < 0) {
6494 nlmsg_free(msg);
6495 return -ENOBUFS;
6496 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006497
Johannes Berg4c476992010-10-04 21:36:35 +02006498 return genlmsg_reply(msg, info);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006499}
6500
6501static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
6502{
Johannes Berg4c476992010-10-04 21:36:35 +02006503 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6504 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006505 u8 *dst = NULL;
6506 u8 *next_hop = NULL;
6507
6508 if (!info->attrs[NL80211_ATTR_MAC])
6509 return -EINVAL;
6510
6511 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
6512 return -EINVAL;
6513
6514 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
6515 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
6516
Johannes Berg4c476992010-10-04 21:36:35 +02006517 if (!rdev->ops->change_mpath)
6518 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01006519
Johannes Berg4c476992010-10-04 21:36:35 +02006520 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
6521 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006522
Hila Gonene35e4d22012-06-27 17:19:42 +03006523 return rdev_change_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006524}
Johannes Berg4c476992010-10-04 21:36:35 +02006525
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006526static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
6527{
Johannes Berg4c476992010-10-04 21:36:35 +02006528 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6529 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006530 u8 *dst = NULL;
6531 u8 *next_hop = NULL;
6532
6533 if (!info->attrs[NL80211_ATTR_MAC])
6534 return -EINVAL;
6535
6536 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
6537 return -EINVAL;
6538
6539 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
6540 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
6541
Johannes Berg4c476992010-10-04 21:36:35 +02006542 if (!rdev->ops->add_mpath)
6543 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01006544
Johannes Berg4c476992010-10-04 21:36:35 +02006545 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
6546 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006547
Hila Gonene35e4d22012-06-27 17:19:42 +03006548 return rdev_add_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006549}
6550
6551static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
6552{
Johannes Berg4c476992010-10-04 21:36:35 +02006553 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6554 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006555 u8 *dst = NULL;
6556
6557 if (info->attrs[NL80211_ATTR_MAC])
6558 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
6559
Johannes Berg4c476992010-10-04 21:36:35 +02006560 if (!rdev->ops->del_mpath)
6561 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01006562
Miaoqing Panb5014262019-09-26 16:16:50 +08006563 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
6564 return -EOPNOTSUPP;
6565
Hila Gonene35e4d22012-06-27 17:19:42 +03006566 return rdev_del_mpath(rdev, dev, dst);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006567}
6568
Henning Rogge66be7d22014-09-12 08:58:49 +02006569static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
6570{
6571 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6572 int err;
6573 struct net_device *dev = info->user_ptr[1];
6574 struct mpath_info pinfo;
6575 struct sk_buff *msg;
6576 u8 *dst = NULL;
6577 u8 mpp[ETH_ALEN];
6578
6579 memset(&pinfo, 0, sizeof(pinfo));
6580
6581 if (!info->attrs[NL80211_ATTR_MAC])
6582 return -EINVAL;
6583
6584 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
6585
6586 if (!rdev->ops->get_mpp)
6587 return -EOPNOTSUPP;
6588
6589 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
6590 return -EOPNOTSUPP;
6591
6592 err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
6593 if (err)
6594 return err;
6595
6596 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6597 if (!msg)
6598 return -ENOMEM;
6599
6600 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
6601 dev, dst, mpp, &pinfo) < 0) {
6602 nlmsg_free(msg);
6603 return -ENOBUFS;
6604 }
6605
6606 return genlmsg_reply(msg, info);
6607}
6608
6609static int nl80211_dump_mpp(struct sk_buff *skb,
6610 struct netlink_callback *cb)
6611{
6612 struct mpath_info pinfo;
6613 struct cfg80211_registered_device *rdev;
6614 struct wireless_dev *wdev;
6615 u8 dst[ETH_ALEN];
6616 u8 mpp[ETH_ALEN];
6617 int path_idx = cb->args[2];
6618 int err;
6619
Johannes Bergea90e0d2017-03-15 14:26:04 +01006620 rtnl_lock();
Johannes Berg5297c652018-09-27 14:36:44 +02006621 err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
Henning Rogge66be7d22014-09-12 08:58:49 +02006622 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +01006623 goto out_err;
Henning Rogge66be7d22014-09-12 08:58:49 +02006624
6625 if (!rdev->ops->dump_mpp) {
6626 err = -EOPNOTSUPP;
6627 goto out_err;
6628 }
6629
6630 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
6631 err = -EOPNOTSUPP;
6632 goto out_err;
6633 }
6634
6635 while (1) {
6636 err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
6637 mpp, &pinfo);
6638 if (err == -ENOENT)
6639 break;
6640 if (err)
6641 goto out_err;
6642
6643 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
6644 cb->nlh->nlmsg_seq, NLM_F_MULTI,
6645 wdev->netdev, dst, mpp,
6646 &pinfo) < 0)
6647 goto out;
6648
6649 path_idx++;
6650 }
6651
6652 out:
6653 cb->args[2] = path_idx;
6654 err = skb->len;
6655 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01006656 rtnl_unlock();
Henning Rogge66be7d22014-09-12 08:58:49 +02006657 return err;
6658}
6659
Jouni Malinen9f1ba902008-08-07 20:07:01 +03006660static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
6661{
Johannes Berg4c476992010-10-04 21:36:35 +02006662 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6663 struct net_device *dev = info->user_ptr[1];
Simon Wunderlichc56589e2013-11-21 18:19:49 +01006664 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03006665 struct bss_parameters params;
Simon Wunderlichc56589e2013-11-21 18:19:49 +01006666 int err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03006667
6668 memset(&params, 0, sizeof(params));
6669 /* default to not changing parameters */
6670 params.use_cts_prot = -1;
6671 params.use_short_preamble = -1;
6672 params.use_short_slot_time = -1;
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02006673 params.ap_isolate = -1;
Helmut Schaa50b12f52010-11-19 12:40:25 +01006674 params.ht_opmode = -1;
Johannes Berg53cabad2012-11-14 15:17:28 +01006675 params.p2p_ctwindow = -1;
6676 params.p2p_opp_ps = -1;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03006677
6678 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
6679 params.use_cts_prot =
6680 nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
6681 if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
6682 params.use_short_preamble =
6683 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
6684 if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
6685 params.use_short_slot_time =
6686 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
Jouni Malinen90c97a02008-10-30 16:59:22 +02006687 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
6688 params.basic_rates =
6689 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
6690 params.basic_rates_len =
6691 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
6692 }
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02006693 if (info->attrs[NL80211_ATTR_AP_ISOLATE])
6694 params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
Helmut Schaa50b12f52010-11-19 12:40:25 +01006695 if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
6696 params.ht_opmode =
6697 nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
Jouni Malinen9f1ba902008-08-07 20:07:01 +03006698
Johannes Berg53cabad2012-11-14 15:17:28 +01006699 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
6700 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
6701 return -EINVAL;
6702 params.p2p_ctwindow =
Johannes Bergab0d76f2018-10-02 10:00:07 +02006703 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
Johannes Berg53cabad2012-11-14 15:17:28 +01006704 if (params.p2p_ctwindow != 0 &&
6705 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
6706 return -EINVAL;
6707 }
6708
6709 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
6710 u8 tmp;
6711
6712 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
6713 return -EINVAL;
6714 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
Johannes Berg53cabad2012-11-14 15:17:28 +01006715 params.p2p_opp_ps = tmp;
6716 if (params.p2p_opp_ps &&
6717 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
6718 return -EINVAL;
6719 }
6720
Johannes Berg4c476992010-10-04 21:36:35 +02006721 if (!rdev->ops->change_bss)
6722 return -EOPNOTSUPP;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03006723
Johannes Berg074ac8d2010-09-16 14:58:22 +02006724 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Johannes Berg4c476992010-10-04 21:36:35 +02006725 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
6726 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02006727
Simon Wunderlichc56589e2013-11-21 18:19:49 +01006728 wdev_lock(wdev);
6729 err = rdev_change_bss(rdev, dev, &params);
6730 wdev_unlock(wdev);
6731
6732 return err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03006733}
6734
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006735static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
6736{
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006737 char *data = NULL;
Ilan peer05050752015-03-04 00:32:06 -05006738 bool is_indoor;
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07006739 enum nl80211_user_reg_hint_type user_reg_hint_type;
Ilan peer05050752015-03-04 00:32:06 -05006740 u32 owner_nlportid;
6741
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05006742 /*
6743 * You should only get this when cfg80211 hasn't yet initialized
6744 * completely when built-in to the kernel right between the time
6745 * window between nl80211_init() and regulatory_init(), if that is
6746 * even possible.
6747 */
Johannes Berg458f4f92012-12-06 15:47:38 +01006748 if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
Luis R. Rodriguezfe33eb32009-02-21 00:04:30 -05006749 return -EINPROGRESS;
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05006750
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07006751 if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
6752 user_reg_hint_type =
6753 nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
6754 else
6755 user_reg_hint_type = NL80211_USER_REG_HINT_USER;
6756
6757 switch (user_reg_hint_type) {
6758 case NL80211_USER_REG_HINT_USER:
6759 case NL80211_USER_REG_HINT_CELL_BASE:
Ilan Peer52616f22014-02-25 16:26:00 +02006760 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
6761 return -EINVAL;
6762
6763 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
6764 return regulatory_hint_user(data, user_reg_hint_type);
6765 case NL80211_USER_REG_HINT_INDOOR:
Ilan peer05050752015-03-04 00:32:06 -05006766 if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
6767 owner_nlportid = info->snd_portid;
6768 is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
6769 } else {
6770 owner_nlportid = 0;
6771 is_indoor = true;
6772 }
6773
6774 return regulatory_hint_indoor(is_indoor, owner_nlportid);
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07006775 default:
6776 return -EINVAL;
6777 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006778}
6779
Johannes Berg1ea4ff3e92017-09-13 16:07:22 +02006780static int nl80211_reload_regdb(struct sk_buff *skb, struct genl_info *info)
6781{
6782 return reg_reload_regdb();
6783}
6784
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006785static int nl80211_get_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01006786 struct genl_info *info)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006787{
Johannes Berg4c476992010-10-04 21:36:35 +02006788 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02006789 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01006790 struct wireless_dev *wdev = dev->ieee80211_ptr;
6791 struct mesh_config cur_params;
6792 int err = 0;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006793 void *hdr;
6794 struct nlattr *pinfoattr;
6795 struct sk_buff *msg;
6796
Johannes Berg29cbe682010-12-03 09:20:44 +01006797 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
6798 return -EOPNOTSUPP;
6799
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006800 if (!rdev->ops->get_mesh_config)
Johannes Berg4c476992010-10-04 21:36:35 +02006801 return -EOPNOTSUPP;
Jouni Malinenf3f92582009-03-20 17:57:36 +02006802
Johannes Berg29cbe682010-12-03 09:20:44 +01006803 wdev_lock(wdev);
6804 /* If not connected, get default parameters */
6805 if (!wdev->mesh_id_len)
6806 memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
6807 else
Hila Gonene35e4d22012-06-27 17:19:42 +03006808 err = rdev_get_mesh_config(rdev, dev, &cur_params);
Johannes Berg29cbe682010-12-03 09:20:44 +01006809 wdev_unlock(wdev);
6810
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006811 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02006812 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006813
6814 /* Draw up a netlink message to send back */
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07006815 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02006816 if (!msg)
6817 return -ENOMEM;
Eric W. Biederman15e47302012-09-07 20:12:54 +00006818 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006819 NL80211_CMD_GET_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006820 if (!hdr)
Julia Lawallefe1cf02011-01-28 15:17:11 +01006821 goto out;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02006822 pinfoattr = nla_nest_start_noflag(msg, NL80211_ATTR_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006823 if (!pinfoattr)
6824 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04006825 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
6826 nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
6827 cur_params.dot11MeshRetryTimeout) ||
6828 nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
6829 cur_params.dot11MeshConfirmTimeout) ||
6830 nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
6831 cur_params.dot11MeshHoldingTimeout) ||
6832 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
6833 cur_params.dot11MeshMaxPeerLinks) ||
6834 nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
6835 cur_params.dot11MeshMaxRetries) ||
6836 nla_put_u8(msg, NL80211_MESHCONF_TTL,
6837 cur_params.dot11MeshTTL) ||
6838 nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
6839 cur_params.element_ttl) ||
6840 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
6841 cur_params.auto_open_plinks) ||
John W. Linville7eab0f62012-04-12 14:25:14 -04006842 nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
6843 cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04006844 nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
6845 cur_params.dot11MeshHWMPmaxPREQretries) ||
6846 nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
6847 cur_params.path_refresh_time) ||
6848 nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
6849 cur_params.min_discovery_timeout) ||
6850 nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
6851 cur_params.dot11MeshHWMPactivePathTimeout) ||
6852 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
6853 cur_params.dot11MeshHWMPpreqMinInterval) ||
6854 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
6855 cur_params.dot11MeshHWMPperrMinInterval) ||
6856 nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
6857 cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
6858 nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
6859 cur_params.dot11MeshHWMPRootMode) ||
6860 nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
6861 cur_params.dot11MeshHWMPRannInterval) ||
6862 nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
6863 cur_params.dot11MeshGateAnnouncementProtocol) ||
6864 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
6865 cur_params.dot11MeshForwarding) ||
Masashi Honma335d5342017-03-16 10:57:17 +09006866 nla_put_s32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
Ashok Nagarajan70c33ea2012-04-30 14:20:32 -07006867 cur_params.rssi_threshold) ||
6868 nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08006869 cur_params.ht_opmode) ||
6870 nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
6871 cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
6872 nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08006873 cur_params.dot11MeshHWMProotInterval) ||
6874 nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Marco Porsch3b1c5a52013-01-07 16:04:52 +01006875 cur_params.dot11MeshHWMPconfirmationInterval) ||
6876 nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
6877 cur_params.power_mode) ||
6878 nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07006879 cur_params.dot11MeshAwakeWindowDuration) ||
6880 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
Bob Copeland01d66fb2018-10-25 17:36:34 -04006881 cur_params.plink_timeout) ||
6882 nla_put_u8(msg, NL80211_MESHCONF_CONNECTED_TO_GATE,
Linus Lüssinge3718a62020-06-17 09:30:33 +02006883 cur_params.dot11MeshConnectedToMeshGate) ||
6884 nla_put_u8(msg, NL80211_MESHCONF_NOLEARN,
Markus Theil184eebe2020-06-11 16:02:37 +02006885 cur_params.dot11MeshNolearn) ||
6886 nla_put_u8(msg, NL80211_MESHCONF_CONNECTED_TO_AS,
6887 cur_params.dot11MeshConnectedToAuthServer))
David S. Miller9360ffd2012-03-29 04:41:26 -04006888 goto nla_put_failure;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006889 nla_nest_end(msg, pinfoattr);
6890 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02006891 return genlmsg_reply(msg, info);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006892
Johannes Berg3b858752009-03-12 09:55:09 +01006893 nla_put_failure:
Julia Lawallefe1cf02011-01-28 15:17:11 +01006894 out:
Yuri Ershovd080e272010-06-29 15:08:07 +04006895 nlmsg_free(msg);
Johannes Berg4c476992010-10-04 21:36:35 +02006896 return -ENOBUFS;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006897}
6898
Johannes Bergab0d76f2018-10-02 10:00:07 +02006899static const struct nla_policy
6900nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
6901 [NL80211_MESHCONF_RETRY_TIMEOUT] =
6902 NLA_POLICY_RANGE(NLA_U16, 1, 255),
6903 [NL80211_MESHCONF_CONFIRM_TIMEOUT] =
6904 NLA_POLICY_RANGE(NLA_U16, 1, 255),
6905 [NL80211_MESHCONF_HOLDING_TIMEOUT] =
6906 NLA_POLICY_RANGE(NLA_U16, 1, 255),
6907 [NL80211_MESHCONF_MAX_PEER_LINKS] =
6908 NLA_POLICY_RANGE(NLA_U16, 0, 255),
6909 [NL80211_MESHCONF_MAX_RETRIES] = NLA_POLICY_MAX(NLA_U8, 16),
6910 [NL80211_MESHCONF_TTL] = NLA_POLICY_MIN(NLA_U8, 1),
6911 [NL80211_MESHCONF_ELEMENT_TTL] = NLA_POLICY_MIN(NLA_U8, 1),
6912 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = NLA_POLICY_MAX(NLA_U8, 1),
6913 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] =
6914 NLA_POLICY_RANGE(NLA_U32, 1, 255),
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006915 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
6916 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
Johannes Bergab0d76f2018-10-02 10:00:07 +02006917 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = NLA_POLICY_MIN(NLA_U16, 1),
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006918 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
Johannes Bergab0d76f2018-10-02 10:00:07 +02006919 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] =
6920 NLA_POLICY_MIN(NLA_U16, 1),
6921 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] =
6922 NLA_POLICY_MIN(NLA_U16, 1),
6923 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] =
6924 NLA_POLICY_MIN(NLA_U16, 1),
6925 [NL80211_MESHCONF_HWMP_ROOTMODE] = NLA_POLICY_MAX(NLA_U8, 4),
6926 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] =
6927 NLA_POLICY_MIN(NLA_U16, 1),
6928 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = NLA_POLICY_MAX(NLA_U8, 1),
6929 [NL80211_MESHCONF_FORWARDING] = NLA_POLICY_MAX(NLA_U8, 1),
6930 [NL80211_MESHCONF_RSSI_THRESHOLD] =
6931 NLA_POLICY_RANGE(NLA_S32, -255, 0),
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006932 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08006933 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
Johannes Bergab0d76f2018-10-02 10:00:07 +02006934 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] =
6935 NLA_POLICY_MIN(NLA_U16, 1),
6936 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] =
6937 NLA_POLICY_MIN(NLA_U16, 1),
6938 [NL80211_MESHCONF_POWER_MODE] =
6939 NLA_POLICY_RANGE(NLA_U32,
6940 NL80211_MESH_POWER_ACTIVE,
6941 NL80211_MESH_POWER_MAX),
Marco Porsch3b1c5a52013-01-07 16:04:52 +01006942 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
Colleen Twitty8e7c0532013-06-03 09:53:39 -07006943 [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
Bob Copeland01d66fb2018-10-25 17:36:34 -04006944 [NL80211_MESHCONF_CONNECTED_TO_GATE] = NLA_POLICY_RANGE(NLA_U8, 0, 1),
Linus Lüssinge3718a62020-06-17 09:30:33 +02006945 [NL80211_MESHCONF_NOLEARN] = NLA_POLICY_RANGE(NLA_U8, 0, 1),
Markus Theil184eebe2020-06-11 16:02:37 +02006946 [NL80211_MESHCONF_CONNECTED_TO_AS] = NLA_POLICY_RANGE(NLA_U8, 0, 1),
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006947};
6948
Javier Cardonac80d5452010-12-16 17:37:49 -08006949static const struct nla_policy
6950 nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
Javier Cardonad299a1f2012-03-31 11:31:33 -07006951 [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
Javier Cardonac80d5452010-12-16 17:37:49 -08006952 [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
6953 [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
Javier Cardona15d5dda2011-04-07 15:08:28 -07006954 [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
Colleen Twitty6e16d902013-05-08 11:45:59 -07006955 [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 },
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006956 [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
Johannes Berg3d7af872018-10-02 10:00:08 +02006957 [NL80211_MESH_SETUP_IE] =
6958 NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
6959 IEEE80211_MAX_DATA_LEN),
Javier Cardonab130e5c2011-05-03 16:57:07 -07006960 [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
Javier Cardonac80d5452010-12-16 17:37:49 -08006961};
6962
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006963static int nl80211_parse_mesh_config(struct genl_info *info,
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006964 struct mesh_config *cfg,
6965 u32 *mask_out)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006966{
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006967 struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006968 u32 mask = 0;
Masashi Honma97572352016-08-03 10:07:44 +09006969 u16 ht_opmode;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006970
Johannes Bergab0d76f2018-10-02 10:00:07 +02006971#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, mask, attr, fn) \
6972do { \
6973 if (tb[attr]) { \
6974 cfg->param = fn(tb[attr]); \
6975 mask |= BIT((attr) - 1); \
6976 } \
Marco Porschea54fba2013-01-07 16:04:48 +01006977} while (0)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006978
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006979 if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006980 return -EINVAL;
Johannes Berg8cb08172019-04-26 14:07:28 +02006981 if (nla_parse_nested_deprecated(tb, NL80211_MESHCONF_ATTR_MAX, info->attrs[NL80211_ATTR_MESH_CONFIG], nl80211_meshconf_params_policy, info->extack))
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006982 return -EINVAL;
6983
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006984 /* This makes sure that there aren't more than 32 mesh config
6985 * parameters (otherwise our bitfield scheme would not work.) */
6986 BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
6987
6988 /* Fill in the params struct */
Johannes Bergab0d76f2018-10-02 10:00:07 +02006989 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, mask,
6990 NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16);
6991 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, mask,
6992 NL80211_MESHCONF_CONFIRM_TIMEOUT,
6993 nla_get_u16);
6994 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, mask,
6995 NL80211_MESHCONF_HOLDING_TIMEOUT,
6996 nla_get_u16);
6997 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, mask,
6998 NL80211_MESHCONF_MAX_PEER_LINKS,
6999 nla_get_u16);
7000 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, mask,
7001 NL80211_MESHCONF_MAX_RETRIES, nla_get_u8);
7002 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, mask,
7003 NL80211_MESHCONF_TTL, nla_get_u8);
7004 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, mask,
7005 NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8);
7006 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, mask,
7007 NL80211_MESHCONF_AUTO_OPEN_PLINKS,
7008 nla_get_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01007009 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007010 mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08007011 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007012 nla_get_u32);
7013 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, mask,
7014 NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
7015 nla_get_u8);
7016 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, mask,
7017 NL80211_MESHCONF_PATH_REFRESH_TIME,
7018 nla_get_u32);
7019 if (mask & BIT(NL80211_MESHCONF_PATH_REFRESH_TIME) &&
7020 (cfg->path_refresh_time < 1 || cfg->path_refresh_time > 65535))
7021 return -EINVAL;
7022 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, mask,
7023 NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
7024 nla_get_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01007025 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007026 mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08007027 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007028 nla_get_u32);
7029 if (mask & BIT(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT) &&
7030 (cfg->dot11MeshHWMPactivePathTimeout < 1 ||
7031 cfg->dot11MeshHWMPactivePathTimeout > 65535))
7032 return -EINVAL;
7033 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, mask,
Marco Porschea54fba2013-01-07 16:04:48 +01007034 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007035 nla_get_u16);
7036 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, mask,
Marco Porschea54fba2013-01-07 16:04:48 +01007037 NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007038 nla_get_u16);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007039 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007040 dot11MeshHWMPnetDiameterTraversalTime, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08007041 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007042 nla_get_u16);
7043 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask,
7044 NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8);
7045 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask,
7046 NL80211_MESHCONF_HWMP_RANN_INTERVAL,
7047 nla_get_u16);
7048 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshGateAnnouncementProtocol,
Marco Porschea54fba2013-01-07 16:04:48 +01007049 mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007050 nla_get_u8);
7051 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, mask,
7052 NL80211_MESHCONF_FORWARDING, nla_get_u8);
7053 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, mask,
7054 NL80211_MESHCONF_RSSI_THRESHOLD,
7055 nla_get_s32);
Bob Copeland01d66fb2018-10-25 17:36:34 -04007056 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConnectedToMeshGate, mask,
7057 NL80211_MESHCONF_CONNECTED_TO_GATE,
7058 nla_get_u8);
Markus Theil184eebe2020-06-11 16:02:37 +02007059 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConnectedToAuthServer, mask,
7060 NL80211_MESHCONF_CONNECTED_TO_AS,
7061 nla_get_u8);
Masashi Honma97572352016-08-03 10:07:44 +09007062 /*
7063 * Check HT operation mode based on
Bob Copeland188f60a2018-06-24 21:10:49 -04007064 * IEEE 802.11-2016 9.4.2.57 HT Operation element.
Masashi Honma97572352016-08-03 10:07:44 +09007065 */
7066 if (tb[NL80211_MESHCONF_HT_OPMODE]) {
7067 ht_opmode = nla_get_u16(tb[NL80211_MESHCONF_HT_OPMODE]);
7068
7069 if (ht_opmode & ~(IEEE80211_HT_OP_MODE_PROTECTION |
7070 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
7071 IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
7072 return -EINVAL;
7073
Bob Copeland188f60a2018-06-24 21:10:49 -04007074 /* NON_HT_STA bit is reserved, but some programs set it */
7075 ht_opmode &= ~IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT;
Masashi Honma97572352016-08-03 10:07:44 +09007076
Masashi Honma97572352016-08-03 10:07:44 +09007077 cfg->ht_opmode = ht_opmode;
Masashi Honmafd551ba2017-01-26 08:56:13 +09007078 mask |= (1 << (NL80211_MESHCONF_HT_OPMODE - 1));
Masashi Honma97572352016-08-03 10:07:44 +09007079 }
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08007080 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007081 dot11MeshHWMPactivePathToRootTimeout, mask,
7082 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
7083 nla_get_u32);
7084 if (mask & BIT(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT) &&
7085 (cfg->dot11MeshHWMPactivePathToRootTimeout < 1 ||
7086 cfg->dot11MeshHWMPactivePathToRootTimeout > 65535))
7087 return -EINVAL;
7088 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, mask,
7089 NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
7090 nla_get_u16);
7091 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPconfirmationInterval,
7092 mask,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08007093 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007094 nla_get_u16);
7095 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode, mask,
7096 NL80211_MESHCONF_POWER_MODE, nla_get_u32);
7097 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, mask,
7098 NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
7099 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, mask,
7100 NL80211_MESHCONF_PLINK_TIMEOUT, nla_get_u32);
Linus Lüssinge3718a62020-06-17 09:30:33 +02007101 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNolearn, mask,
7102 NL80211_MESHCONF_NOLEARN, nla_get_u8);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007103 if (mask_out)
7104 *mask_out = mask;
Javier Cardonac80d5452010-12-16 17:37:49 -08007105
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007106 return 0;
7107
7108#undef FILL_IN_MESH_PARAM_IF_SET
7109}
7110
Javier Cardonac80d5452010-12-16 17:37:49 -08007111static int nl80211_parse_mesh_setup(struct genl_info *info,
7112 struct mesh_setup *setup)
7113{
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08007114 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Javier Cardonac80d5452010-12-16 17:37:49 -08007115 struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
7116
7117 if (!info->attrs[NL80211_ATTR_MESH_SETUP])
7118 return -EINVAL;
Johannes Berg8cb08172019-04-26 14:07:28 +02007119 if (nla_parse_nested_deprecated(tb, NL80211_MESH_SETUP_ATTR_MAX, info->attrs[NL80211_ATTR_MESH_SETUP], nl80211_mesh_setup_params_policy, info->extack))
Javier Cardonac80d5452010-12-16 17:37:49 -08007120 return -EINVAL;
7121
Javier Cardonad299a1f2012-03-31 11:31:33 -07007122 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
7123 setup->sync_method =
7124 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
7125 IEEE80211_SYNC_METHOD_VENDOR :
7126 IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
7127
Javier Cardonac80d5452010-12-16 17:37:49 -08007128 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
7129 setup->path_sel_proto =
7130 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
7131 IEEE80211_PATH_PROTOCOL_VENDOR :
7132 IEEE80211_PATH_PROTOCOL_HWMP;
7133
7134 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
7135 setup->path_metric =
7136 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
7137 IEEE80211_PATH_METRIC_VENDOR :
7138 IEEE80211_PATH_METRIC_AIRTIME;
7139
Javier Cardona581a8b02011-04-07 15:08:27 -07007140 if (tb[NL80211_MESH_SETUP_IE]) {
Javier Cardonac80d5452010-12-16 17:37:49 -08007141 struct nlattr *ieattr =
Javier Cardona581a8b02011-04-07 15:08:27 -07007142 tb[NL80211_MESH_SETUP_IE];
Javier Cardona581a8b02011-04-07 15:08:27 -07007143 setup->ie = nla_data(ieattr);
7144 setup->ie_len = nla_len(ieattr);
Javier Cardonac80d5452010-12-16 17:37:49 -08007145 }
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08007146 if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
7147 !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
7148 return -EINVAL;
7149 setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
Javier Cardonab130e5c2011-05-03 16:57:07 -07007150 setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
7151 setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08007152 if (setup->is_secure)
7153 setup->user_mpm = true;
Javier Cardonac80d5452010-12-16 17:37:49 -08007154
Colleen Twitty6e16d902013-05-08 11:45:59 -07007155 if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) {
7156 if (!setup->user_mpm)
7157 return -EINVAL;
7158 setup->auth_id =
7159 nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]);
7160 }
7161
Javier Cardonac80d5452010-12-16 17:37:49 -08007162 return 0;
7163}
7164
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007165static int nl80211_update_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01007166 struct genl_info *info)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007167{
7168 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7169 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01007170 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007171 struct mesh_config cfg;
7172 u32 mask;
7173 int err;
7174
Johannes Berg29cbe682010-12-03 09:20:44 +01007175 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
7176 return -EOPNOTSUPP;
7177
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007178 if (!rdev->ops->update_mesh_config)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007179 return -EOPNOTSUPP;
7180
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007181 err = nl80211_parse_mesh_config(info, &cfg, &mask);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007182 if (err)
7183 return err;
7184
Johannes Berg29cbe682010-12-03 09:20:44 +01007185 wdev_lock(wdev);
7186 if (!wdev->mesh_id_len)
7187 err = -ENOLINK;
7188
7189 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03007190 err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01007191
7192 wdev_unlock(wdev);
7193
7194 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007195}
7196
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007197static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
7198 struct sk_buff *msg)
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007199{
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007200 struct nlattr *nl_reg_rules;
7201 unsigned int i;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007202
Johannes Berg458f4f92012-12-06 15:47:38 +01007203 if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
7204 (regdom->dfs_region &&
7205 nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007206 goto nla_put_failure;
Johannes Berg458f4f92012-12-06 15:47:38 +01007207
Michal Kubecekae0be8d2019-04-26 11:13:06 +02007208 nl_reg_rules = nla_nest_start_noflag(msg, NL80211_ATTR_REG_RULES);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007209 if (!nl_reg_rules)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007210 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007211
Johannes Berg458f4f92012-12-06 15:47:38 +01007212 for (i = 0; i < regdom->n_reg_rules; i++) {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007213 struct nlattr *nl_reg_rule;
7214 const struct ieee80211_reg_rule *reg_rule;
7215 const struct ieee80211_freq_range *freq_range;
7216 const struct ieee80211_power_rule *power_rule;
Janusz Dziedzic97524822014-01-30 09:52:20 +01007217 unsigned int max_bandwidth_khz;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007218
Johannes Berg458f4f92012-12-06 15:47:38 +01007219 reg_rule = &regdom->reg_rules[i];
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007220 freq_range = &reg_rule->freq_range;
7221 power_rule = &reg_rule->power_rule;
7222
Michal Kubecekae0be8d2019-04-26 11:13:06 +02007223 nl_reg_rule = nla_nest_start_noflag(msg, i);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007224 if (!nl_reg_rule)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007225 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007226
Janusz Dziedzic97524822014-01-30 09:52:20 +01007227 max_bandwidth_khz = freq_range->max_bandwidth_khz;
7228 if (!max_bandwidth_khz)
7229 max_bandwidth_khz = reg_get_max_bandwidth(regdom,
7230 reg_rule);
7231
David S. Miller9360ffd2012-03-29 04:41:26 -04007232 if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
7233 reg_rule->flags) ||
7234 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
7235 freq_range->start_freq_khz) ||
7236 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
7237 freq_range->end_freq_khz) ||
7238 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
Janusz Dziedzic97524822014-01-30 09:52:20 +01007239 max_bandwidth_khz) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04007240 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
7241 power_rule->max_antenna_gain) ||
7242 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
Janusz Dziedzic089027e2014-02-21 19:46:12 +01007243 power_rule->max_eirp) ||
7244 nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
7245 reg_rule->dfs_cac_ms))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007246 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007247
7248 nla_nest_end(msg, nl_reg_rule);
7249 }
7250
7251 nla_nest_end(msg, nl_reg_rules);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007252 return 0;
7253
7254nla_put_failure:
7255 return -EMSGSIZE;
7256}
7257
7258static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
7259{
7260 const struct ieee80211_regdomain *regdom = NULL;
7261 struct cfg80211_registered_device *rdev;
7262 struct wiphy *wiphy = NULL;
7263 struct sk_buff *msg;
7264 void *hdr;
7265
7266 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7267 if (!msg)
7268 return -ENOBUFS;
7269
7270 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
7271 NL80211_CMD_GET_REG);
7272 if (!hdr)
7273 goto put_failure;
7274
7275 if (info->attrs[NL80211_ATTR_WIPHY]) {
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02007276 bool self_managed;
7277
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007278 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
7279 if (IS_ERR(rdev)) {
7280 nlmsg_free(msg);
7281 return PTR_ERR(rdev);
7282 }
7283
7284 wiphy = &rdev->wiphy;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02007285 self_managed = wiphy->regulatory_flags &
7286 REGULATORY_WIPHY_SELF_MANAGED;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007287 regdom = get_wiphy_regdom(wiphy);
7288
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02007289 /* a self-managed-reg device must have a private regdom */
7290 if (WARN_ON(!regdom && self_managed)) {
7291 nlmsg_free(msg);
7292 return -EINVAL;
7293 }
7294
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007295 if (regdom &&
7296 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
7297 goto nla_put_failure;
7298 }
7299
7300 if (!wiphy && reg_last_request_cell_base() &&
7301 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
7302 NL80211_USER_REG_HINT_CELL_BASE))
7303 goto nla_put_failure;
7304
7305 rcu_read_lock();
7306
7307 if (!regdom)
7308 regdom = rcu_dereference(cfg80211_regdomain);
7309
7310 if (nl80211_put_regdom(regdom, msg))
7311 goto nla_put_failure_rcu;
7312
7313 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007314
7315 genlmsg_end(msg, hdr);
Johannes Berg5fe231e2013-05-08 21:45:15 +02007316 return genlmsg_reply(msg, info);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007317
Johannes Berg458f4f92012-12-06 15:47:38 +01007318nla_put_failure_rcu:
7319 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007320nla_put_failure:
Julia Lawallefe1cf02011-01-28 15:17:11 +01007321put_failure:
Yuri Ershovd080e272010-06-29 15:08:07 +04007322 nlmsg_free(msg);
Johannes Berg5fe231e2013-05-08 21:45:15 +02007323 return -EMSGSIZE;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007324}
7325
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007326static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
7327 u32 seq, int flags, struct wiphy *wiphy,
7328 const struct ieee80211_regdomain *regdom)
7329{
7330 void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
7331 NL80211_CMD_GET_REG);
7332
7333 if (!hdr)
7334 return -1;
7335
Michal Kubecek0a833c22017-11-15 13:09:32 +01007336 genl_dump_check_consistent(cb, hdr);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007337
7338 if (nl80211_put_regdom(regdom, msg))
7339 goto nla_put_failure;
7340
7341 if (!wiphy && reg_last_request_cell_base() &&
7342 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
7343 NL80211_USER_REG_HINT_CELL_BASE))
7344 goto nla_put_failure;
7345
7346 if (wiphy &&
7347 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
7348 goto nla_put_failure;
7349
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02007350 if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
7351 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
7352 goto nla_put_failure;
7353
Johannes Berg053c0952015-01-16 22:09:00 +01007354 genlmsg_end(msg, hdr);
7355 return 0;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007356
7357nla_put_failure:
7358 genlmsg_cancel(msg, hdr);
7359 return -EMSGSIZE;
7360}
7361
7362static int nl80211_get_reg_dump(struct sk_buff *skb,
7363 struct netlink_callback *cb)
7364{
7365 const struct ieee80211_regdomain *regdom = NULL;
7366 struct cfg80211_registered_device *rdev;
7367 int err, reg_idx, start = cb->args[2];
7368
7369 rtnl_lock();
7370
7371 if (cfg80211_regdomain && start == 0) {
7372 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
7373 NLM_F_MULTI, NULL,
7374 rtnl_dereference(cfg80211_regdomain));
7375 if (err < 0)
7376 goto out_err;
7377 }
7378
7379 /* the global regdom is idx 0 */
7380 reg_idx = 1;
7381 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
7382 regdom = get_wiphy_regdom(&rdev->wiphy);
7383 if (!regdom)
7384 continue;
7385
7386 if (++reg_idx <= start)
7387 continue;
7388
7389 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
7390 NLM_F_MULTI, &rdev->wiphy, regdom);
7391 if (err < 0) {
7392 reg_idx--;
7393 break;
7394 }
7395 }
7396
7397 cb->args[2] = reg_idx;
7398 err = skb->len;
7399out_err:
7400 rtnl_unlock();
7401 return err;
7402}
7403
Johannes Bergb6863032015-10-15 09:25:18 +02007404#ifdef CONFIG_CFG80211_CRDA_SUPPORT
7405static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
7406 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
7407 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
7408 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
7409 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
7410 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
7411 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
7412 [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
7413};
7414
7415static int parse_reg_rule(struct nlattr *tb[],
7416 struct ieee80211_reg_rule *reg_rule)
7417{
7418 struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
7419 struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
7420
7421 if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
7422 return -EINVAL;
7423 if (!tb[NL80211_ATTR_FREQ_RANGE_START])
7424 return -EINVAL;
7425 if (!tb[NL80211_ATTR_FREQ_RANGE_END])
7426 return -EINVAL;
7427 if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
7428 return -EINVAL;
7429 if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
7430 return -EINVAL;
7431
7432 reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
7433
7434 freq_range->start_freq_khz =
7435 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
7436 freq_range->end_freq_khz =
7437 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
7438 freq_range->max_bandwidth_khz =
7439 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
7440
7441 power_rule->max_eirp =
7442 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
7443
7444 if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
7445 power_rule->max_antenna_gain =
7446 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
7447
7448 if (tb[NL80211_ATTR_DFS_CAC_TIME])
7449 reg_rule->dfs_cac_ms =
7450 nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
7451
7452 return 0;
7453}
7454
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007455static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
7456{
7457 struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
7458 struct nlattr *nl_reg_rule;
Johannes Bergea372c52014-11-28 14:54:31 +01007459 char *alpha2;
7460 int rem_reg_rules, r;
Gustavo A. R. Silva391d1322019-04-03 10:37:44 -05007461 u32 num_rules = 0, rule_idx = 0;
Luis R. Rodriguez4c7d3982013-11-13 18:54:02 +01007462 enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
Johannes Bergea372c52014-11-28 14:54:31 +01007463 struct ieee80211_regdomain *rd;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007464
7465 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
7466 return -EINVAL;
7467
7468 if (!info->attrs[NL80211_ATTR_REG_RULES])
7469 return -EINVAL;
7470
7471 alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
7472
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07007473 if (info->attrs[NL80211_ATTR_DFS_REGION])
7474 dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
7475
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007476 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01007477 rem_reg_rules) {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007478 num_rules++;
7479 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
Luis R. Rodriguez4776c6e2009-05-13 17:04:39 -04007480 return -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007481 }
7482
Luis R. Rodrigueze4387682013-11-05 09:18:01 -08007483 if (!reg_is_valid_request(alpha2))
7484 return -EINVAL;
7485
Gustavo A. R. Silva391d1322019-04-03 10:37:44 -05007486 rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL);
Johannes Berg6913b492012-12-04 00:48:59 +01007487 if (!rd)
7488 return -ENOMEM;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007489
7490 rd->n_reg_rules = num_rules;
7491 rd->alpha2[0] = alpha2[0];
7492 rd->alpha2[1] = alpha2[1];
7493
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07007494 /*
7495 * Disable DFS master mode if the DFS region was
7496 * not supported or known on this kernel.
7497 */
7498 if (reg_supported_dfs_region(dfs_region))
7499 rd->dfs_region = dfs_region;
7500
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007501 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01007502 rem_reg_rules) {
Johannes Berg8cb08172019-04-26 14:07:28 +02007503 r = nla_parse_nested_deprecated(tb, NL80211_REG_RULE_ATTR_MAX,
7504 nl_reg_rule, reg_rule_policy,
7505 info->extack);
Johannes Bergae811e22014-01-24 10:17:47 +01007506 if (r)
7507 goto bad_reg;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007508 r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
7509 if (r)
7510 goto bad_reg;
7511
7512 rule_idx++;
7513
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04007514 if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
7515 r = -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007516 goto bad_reg;
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04007517 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007518 }
7519
Johannes Berg06627992016-06-09 10:40:09 +02007520 /* set_regdom takes ownership of rd */
7521 return set_regdom(rd, REGD_SOURCE_CRDA);
Johannes Bergd2372b32008-10-24 20:32:20 +02007522 bad_reg:
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007523 kfree(rd);
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04007524 return r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007525}
Johannes Bergb6863032015-10-15 09:25:18 +02007526#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007527
Johannes Berg83f5e2c2009-06-17 17:41:49 +02007528static int validate_scan_freqs(struct nlattr *freqs)
7529{
7530 struct nlattr *attr1, *attr2;
7531 int n_channels = 0, tmp1, tmp2;
7532
Srinivas Dasarid7f13f72017-07-07 01:43:42 +03007533 nla_for_each_nested(attr1, freqs, tmp1)
7534 if (nla_len(attr1) != sizeof(u32))
7535 return 0;
7536
Johannes Berg83f5e2c2009-06-17 17:41:49 +02007537 nla_for_each_nested(attr1, freqs, tmp1) {
7538 n_channels++;
7539 /*
7540 * Some hardware has a limited channel list for
7541 * scanning, and it is pretty much nonsensical
7542 * to scan for a channel twice, so disallow that
7543 * and don't require drivers to check that the
7544 * channel list they get isn't longer than what
7545 * they can scan, as long as they can scan all
7546 * the channels they registered at once.
7547 */
7548 nla_for_each_nested(attr2, freqs, tmp2)
7549 if (attr1 != attr2 &&
7550 nla_get_u32(attr1) == nla_get_u32(attr2))
7551 return 0;
7552 }
7553
7554 return n_channels;
7555}
7556
Johannes Berg57fbcce2016-04-12 15:56:15 +02007557static bool is_band_valid(struct wiphy *wiphy, enum nl80211_band b)
Arend van Spriel38de03d2016-03-02 20:37:18 +01007558{
Johannes Berg57fbcce2016-04-12 15:56:15 +02007559 return b < NUM_NL80211_BANDS && wiphy->bands[b];
Arend van Spriel38de03d2016-03-02 20:37:18 +01007560}
7561
7562static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
7563 struct cfg80211_bss_selection *bss_select)
7564{
7565 struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
7566 struct nlattr *nest;
7567 int err;
7568 bool found = false;
7569 int i;
7570
7571 /* only process one nested attribute */
7572 nest = nla_data(nla);
7573 if (!nla_ok(nest, nla_len(nest)))
7574 return -EINVAL;
7575
Johannes Berg8cb08172019-04-26 14:07:28 +02007576 err = nla_parse_nested_deprecated(attr, NL80211_BSS_SELECT_ATTR_MAX,
7577 nest, nl80211_bss_select_policy,
7578 NULL);
Arend van Spriel38de03d2016-03-02 20:37:18 +01007579 if (err)
7580 return err;
7581
7582 /* only one attribute may be given */
7583 for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
7584 if (attr[i]) {
7585 if (found)
7586 return -EINVAL;
7587 found = true;
7588 }
7589 }
7590
7591 bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
7592
7593 if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
7594 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
7595
7596 if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
7597 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
7598 bss_select->param.band_pref =
7599 nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
7600 if (!is_band_valid(wiphy, bss_select->param.band_pref))
7601 return -EINVAL;
7602 }
7603
7604 if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
7605 struct nl80211_bss_select_rssi_adjust *adj_param;
7606
7607 adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
7608 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
7609 bss_select->param.adjust.band = adj_param->band;
7610 bss_select->param.adjust.delta = adj_param->delta;
7611 if (!is_band_valid(wiphy, bss_select->param.adjust.band))
7612 return -EINVAL;
7613 }
7614
7615 /* user-space did not provide behaviour attribute */
7616 if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
7617 return -EINVAL;
7618
7619 if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
7620 return -EINVAL;
7621
7622 return 0;
7623}
7624
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02007625int nl80211_parse_random_mac(struct nlattr **attrs,
7626 u8 *mac_addr, u8 *mac_addr_mask)
Johannes Bergad2b26a2014-06-12 21:39:05 +02007627{
7628 int i;
7629
7630 if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
Joe Perchesd2beae12015-03-02 19:54:58 -08007631 eth_zero_addr(mac_addr);
7632 eth_zero_addr(mac_addr_mask);
Johannes Bergad2b26a2014-06-12 21:39:05 +02007633 mac_addr[0] = 0x2;
7634 mac_addr_mask[0] = 0x3;
7635
7636 return 0;
7637 }
7638
7639 /* need both or none */
7640 if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
7641 return -EINVAL;
7642
7643 memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
7644 memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
7645
7646 /* don't allow or configure an mcast address */
7647 if (!is_multicast_ether_addr(mac_addr_mask) ||
7648 is_multicast_ether_addr(mac_addr))
7649 return -EINVAL;
7650
7651 /*
7652 * allow users to pass a MAC address that has bits set outside
7653 * of the mask, but don't bother drivers with having to deal
7654 * with such bits
7655 */
7656 for (i = 0; i < ETH_ALEN; i++)
7657 mac_addr[i] &= mac_addr_mask[i];
7658
7659 return 0;
7660}
7661
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05307662static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
7663{
7664 ASSERT_WDEV_LOCK(wdev);
7665
7666 if (!cfg80211_beaconing_iface_active(wdev))
7667 return true;
7668
7669 if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
7670 return true;
7671
7672 return regulatory_pre_cac_allowed(wdev->wiphy);
7673}
7674
Johannes Bergdb0a4ad2018-05-28 15:47:37 +02007675static bool nl80211_check_scan_feat(struct wiphy *wiphy, u32 flags, u32 flag,
7676 enum nl80211_ext_feature_index feat)
7677{
7678 if (!(flags & flag))
7679 return true;
7680 if (wiphy_ext_feature_isset(wiphy, feat))
7681 return true;
7682 return false;
7683}
7684
Roee Zamir2d23d072017-08-06 11:38:22 +03007685static int
7686nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
7687 void *request, struct nlattr **attrs,
7688 bool is_sched_scan)
7689{
7690 u8 *mac_addr, *mac_addr_mask;
7691 u32 *flags;
7692 enum nl80211_feature_flags randomness_flag;
7693
7694 if (!attrs[NL80211_ATTR_SCAN_FLAGS])
7695 return 0;
7696
7697 if (is_sched_scan) {
7698 struct cfg80211_sched_scan_request *req = request;
7699
7700 randomness_flag = wdev ?
7701 NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR :
7702 NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7703 flags = &req->flags;
7704 mac_addr = req->mac_addr;
7705 mac_addr_mask = req->mac_addr_mask;
7706 } else {
7707 struct cfg80211_scan_request *req = request;
7708
7709 randomness_flag = NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
7710 flags = &req->flags;
7711 mac_addr = req->mac_addr;
7712 mac_addr_mask = req->mac_addr_mask;
7713 }
7714
7715 *flags = nla_get_u32(attrs[NL80211_ATTR_SCAN_FLAGS]);
7716
Sunil Dutt5037a002018-01-25 17:13:37 +02007717 if (((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
7718 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
Johannes Bergdb0a4ad2018-05-28 15:47:37 +02007719 !nl80211_check_scan_feat(wiphy, *flags,
7720 NL80211_SCAN_FLAG_LOW_SPAN,
7721 NL80211_EXT_FEATURE_LOW_SPAN_SCAN) ||
7722 !nl80211_check_scan_feat(wiphy, *flags,
7723 NL80211_SCAN_FLAG_LOW_POWER,
7724 NL80211_EXT_FEATURE_LOW_POWER_SCAN) ||
7725 !nl80211_check_scan_feat(wiphy, *flags,
7726 NL80211_SCAN_FLAG_HIGH_ACCURACY,
7727 NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN) ||
7728 !nl80211_check_scan_feat(wiphy, *flags,
7729 NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME,
7730 NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME) ||
7731 !nl80211_check_scan_feat(wiphy, *flags,
7732 NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP,
7733 NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP) ||
7734 !nl80211_check_scan_feat(wiphy, *flags,
7735 NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
7736 NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) ||
7737 !nl80211_check_scan_feat(wiphy, *flags,
7738 NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE,
Johannes Berg2e076f12018-05-28 15:47:40 +02007739 NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE) ||
7740 !nl80211_check_scan_feat(wiphy, *flags,
7741 NL80211_SCAN_FLAG_RANDOM_SN,
7742 NL80211_EXT_FEATURE_SCAN_RANDOM_SN) ||
7743 !nl80211_check_scan_feat(wiphy, *flags,
7744 NL80211_SCAN_FLAG_MIN_PREQ_CONTENT,
7745 NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT))
Roee Zamir2d23d072017-08-06 11:38:22 +03007746 return -EOPNOTSUPP;
7747
7748 if (*flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
7749 int err;
7750
7751 if (!(wiphy->features & randomness_flag) ||
7752 (wdev && wdev->current_bss))
7753 return -EOPNOTSUPP;
7754
7755 err = nl80211_parse_random_mac(attrs, mac_addr, mac_addr_mask);
7756 if (err)
7757 return err;
7758 }
7759
Roee Zamir2d23d072017-08-06 11:38:22 +03007760 return 0;
7761}
7762
Johannes Berg2a519312009-02-10 21:25:55 +01007763static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
7764{
Johannes Berg4c476992010-10-04 21:36:35 +02007765 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfd014282012-06-18 19:17:03 +02007766 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2a519312009-02-10 21:25:55 +01007767 struct cfg80211_scan_request *request;
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07007768 struct nlattr *scan_freqs = NULL;
7769 bool scan_freqs_khz = false;
Johannes Berg2a519312009-02-10 21:25:55 +01007770 struct nlattr *attr;
7771 struct wiphy *wiphy;
Johannes Berg83f5e2c2009-06-17 17:41:49 +02007772 int err, tmp, n_ssids = 0, n_channels, i;
Jouni Malinen70692ad2009-02-16 19:39:13 +02007773 size_t ie_len;
Johannes Berg2a519312009-02-10 21:25:55 +01007774
Johannes Berg79c97e92009-07-07 03:56:12 +02007775 wiphy = &rdev->wiphy;
Johannes Berg2a519312009-02-10 21:25:55 +01007776
Ayala Bekercb3b7d82016-09-20 17:31:13 +03007777 if (wdev->iftype == NL80211_IFTYPE_NAN)
7778 return -EOPNOTSUPP;
7779
Johannes Berg4c476992010-10-04 21:36:35 +02007780 if (!rdev->ops->scan)
7781 return -EOPNOTSUPP;
Johannes Berg2a519312009-02-10 21:25:55 +01007782
Christophe JAILLET83286852020-07-12 19:35:39 +02007783 if (rdev->scan_req || rdev->scan_msg)
7784 return -EBUSY;
Johannes Berg2a519312009-02-10 21:25:55 +01007785
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07007786 if (info->attrs[NL80211_ATTR_SCAN_FREQ_KHZ]) {
7787 if (!wiphy_ext_feature_isset(wiphy,
7788 NL80211_EXT_FEATURE_SCAN_FREQ_KHZ))
7789 return -EOPNOTSUPP;
7790 scan_freqs = info->attrs[NL80211_ATTR_SCAN_FREQ_KHZ];
7791 scan_freqs_khz = true;
7792 } else if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES])
7793 scan_freqs = info->attrs[NL80211_ATTR_SCAN_FREQUENCIES];
7794
7795 if (scan_freqs) {
7796 n_channels = validate_scan_freqs(scan_freqs);
Christophe JAILLET83286852020-07-12 19:35:39 +02007797 if (!n_channels)
7798 return -EINVAL;
Johannes Berg2a519312009-02-10 21:25:55 +01007799 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02007800 n_channels = ieee80211_get_num_supported_channels(wiphy);
Johannes Berg2a519312009-02-10 21:25:55 +01007801 }
7802
7803 if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
7804 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
7805 n_ssids++;
7806
Christophe JAILLET83286852020-07-12 19:35:39 +02007807 if (n_ssids > wiphy->max_scan_ssids)
7808 return -EINVAL;
Johannes Berg2a519312009-02-10 21:25:55 +01007809
Jouni Malinen70692ad2009-02-16 19:39:13 +02007810 if (info->attrs[NL80211_ATTR_IE])
7811 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
7812 else
7813 ie_len = 0;
7814
Christophe JAILLET83286852020-07-12 19:35:39 +02007815 if (ie_len > wiphy->max_scan_ie_len)
7816 return -EINVAL;
Johannes Berg18a83652009-03-31 12:12:05 +02007817
Johannes Berg2a519312009-02-10 21:25:55 +01007818 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007819 + sizeof(*request->ssids) * n_ssids
7820 + sizeof(*request->channels) * n_channels
Jouni Malinen70692ad2009-02-16 19:39:13 +02007821 + ie_len, GFP_KERNEL);
Christophe JAILLET83286852020-07-12 19:35:39 +02007822 if (!request)
7823 return -ENOMEM;
Johannes Berg2a519312009-02-10 21:25:55 +01007824
Johannes Berg2a519312009-02-10 21:25:55 +01007825 if (n_ssids)
Johannes Berg5ba63532009-08-07 17:54:07 +02007826 request->ssids = (void *)&request->channels[n_channels];
Johannes Berg2a519312009-02-10 21:25:55 +01007827 request->n_ssids = n_ssids;
Jouni Malinen70692ad2009-02-16 19:39:13 +02007828 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01007829 if (n_ssids)
Jouni Malinen70692ad2009-02-16 19:39:13 +02007830 request->ie = (void *)(request->ssids + n_ssids);
7831 else
7832 request->ie = (void *)(request->channels + n_channels);
7833 }
Johannes Berg2a519312009-02-10 21:25:55 +01007834
Johannes Berg584991d2009-11-02 13:32:03 +01007835 i = 0;
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07007836 if (scan_freqs) {
Johannes Berg2a519312009-02-10 21:25:55 +01007837 /* user specified, bail out if channel not found */
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07007838 nla_for_each_nested(attr, scan_freqs, tmp) {
Johannes Berg584991d2009-11-02 13:32:03 +01007839 struct ieee80211_channel *chan;
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07007840 int freq = nla_get_u32(attr);
Johannes Berg584991d2009-11-02 13:32:03 +01007841
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07007842 if (!scan_freqs_khz)
7843 freq = MHZ_TO_KHZ(freq);
Johannes Berg584991d2009-11-02 13:32:03 +01007844
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07007845 chan = ieee80211_get_channel_khz(wiphy, freq);
Johannes Berg584991d2009-11-02 13:32:03 +01007846 if (!chan) {
Johannes Berg2a519312009-02-10 21:25:55 +01007847 err = -EINVAL;
7848 goto out_free;
7849 }
Johannes Berg584991d2009-11-02 13:32:03 +01007850
7851 /* ignore disabled channels */
7852 if (chan->flags & IEEE80211_CHAN_DISABLED)
7853 continue;
7854
7855 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01007856 i++;
7857 }
7858 } else {
Johannes Berg57fbcce2016-04-12 15:56:15 +02007859 enum nl80211_band band;
Johannes Berg34850ab2011-07-18 18:08:35 +02007860
Johannes Berg2a519312009-02-10 21:25:55 +01007861 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02007862 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Johannes Berg2a519312009-02-10 21:25:55 +01007863 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007864
Johannes Berg2a519312009-02-10 21:25:55 +01007865 if (!wiphy->bands[band])
7866 continue;
7867 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
Johannes Berg584991d2009-11-02 13:32:03 +01007868 struct ieee80211_channel *chan;
7869
7870 chan = &wiphy->bands[band]->channels[j];
7871
7872 if (chan->flags & IEEE80211_CHAN_DISABLED)
7873 continue;
7874
7875 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01007876 i++;
7877 }
7878 }
7879 }
7880
Johannes Berg584991d2009-11-02 13:32:03 +01007881 if (!i) {
7882 err = -EINVAL;
7883 goto out_free;
7884 }
7885
7886 request->n_channels = i;
7887
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05307888 wdev_lock(wdev);
7889 if (!cfg80211_off_channel_oper_allowed(wdev)) {
7890 struct ieee80211_channel *chan;
7891
7892 if (request->n_channels != 1) {
7893 wdev_unlock(wdev);
7894 err = -EBUSY;
7895 goto out_free;
7896 }
7897
7898 chan = request->channels[0];
7899 if (chan->center_freq != wdev->chandef.chan->center_freq) {
7900 wdev_unlock(wdev);
7901 err = -EBUSY;
7902 goto out_free;
7903 }
7904 }
7905 wdev_unlock(wdev);
7906
Johannes Berg2a519312009-02-10 21:25:55 +01007907 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01007908 if (n_ssids) {
Johannes Berg2a519312009-02-10 21:25:55 +01007909 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03007910 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Johannes Berg2a519312009-02-10 21:25:55 +01007911 err = -EINVAL;
7912 goto out_free;
7913 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03007914 request->ssids[i].ssid_len = nla_len(attr);
Johannes Berg2a519312009-02-10 21:25:55 +01007915 memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
Johannes Berg2a519312009-02-10 21:25:55 +01007916 i++;
7917 }
7918 }
7919
Jouni Malinen70692ad2009-02-16 19:39:13 +02007920 if (info->attrs[NL80211_ATTR_IE]) {
7921 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Johannes Bergde95a54b2009-04-01 11:58:36 +02007922 memcpy((void *)request->ie,
7923 nla_data(info->attrs[NL80211_ATTR_IE]),
Jouni Malinen70692ad2009-02-16 19:39:13 +02007924 request->ie_len);
7925 }
7926
Johannes Berg57fbcce2016-04-12 15:56:15 +02007927 for (i = 0; i < NUM_NL80211_BANDS; i++)
Johannes Berga401d2b2011-07-20 00:52:16 +02007928 if (wiphy->bands[i])
7929 request->rates[i] =
7930 (1 << wiphy->bands[i]->n_bitrates) - 1;
Johannes Berg34850ab2011-07-18 18:08:35 +02007931
7932 if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
7933 nla_for_each_nested(attr,
7934 info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
7935 tmp) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02007936 enum nl80211_band band = nla_type(attr);
Johannes Berg34850ab2011-07-18 18:08:35 +02007937
Johannes Berg57fbcce2016-04-12 15:56:15 +02007938 if (band < 0 || band >= NUM_NL80211_BANDS) {
Johannes Berg34850ab2011-07-18 18:08:35 +02007939 err = -EINVAL;
7940 goto out_free;
7941 }
Felix Fietkau1b09cd82013-11-20 19:40:41 +01007942
7943 if (!wiphy->bands[band])
7944 continue;
7945
Johannes Berg34850ab2011-07-18 18:08:35 +02007946 err = ieee80211_get_ratemask(wiphy->bands[band],
7947 nla_data(attr),
7948 nla_len(attr),
7949 &request->rates[band]);
7950 if (err)
7951 goto out_free;
7952 }
7953 }
7954
Avraham Stern1d762502016-07-05 17:10:13 +03007955 if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
7956 if (!wiphy_ext_feature_isset(wiphy,
7957 NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
7958 err = -EOPNOTSUPP;
7959 goto out_free;
7960 }
7961
7962 request->duration =
7963 nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
7964 request->duration_mandatory =
7965 nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
7966 }
7967
Roee Zamir2d23d072017-08-06 11:38:22 +03007968 err = nl80211_check_scan_flags(wiphy, wdev, request, info->attrs,
7969 false);
7970 if (err)
7971 goto out_free;
Sam Lefflered4737712012-10-11 21:03:31 -07007972
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05307973 request->no_cck =
7974 nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
7975
Vamsi Krishna2fa436b2016-12-02 23:59:08 +02007976 /* Initial implementation used NL80211_ATTR_MAC to set the specific
7977 * BSSID to scan for. This was problematic because that same attribute
7978 * was already used for another purpose (local random MAC address). The
7979 * NL80211_ATTR_BSSID attribute was added to fix this. For backwards
7980 * compatibility with older userspace components, also use the
7981 * NL80211_ATTR_MAC value here if it can be determined to be used for
7982 * the specific BSSID use case instead of the random MAC address
7983 * (NL80211_ATTR_SCAN_FLAGS is used to enable random MAC address use).
7984 */
7985 if (info->attrs[NL80211_ATTR_BSSID])
7986 memcpy(request->bssid,
7987 nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
7988 else if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
7989 info->attrs[NL80211_ATTR_MAC])
Jouni Malinen818965d2016-02-26 22:12:47 +02007990 memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
7991 ETH_ALEN);
7992 else
7993 eth_broadcast_addr(request->bssid);
7994
Johannes Bergfd014282012-06-18 19:17:03 +02007995 request->wdev = wdev;
Johannes Berg79c97e92009-07-07 03:56:12 +02007996 request->wiphy = &rdev->wiphy;
Sam Leffler15d60302012-10-11 21:03:34 -07007997 request->scan_start = jiffies;
Johannes Berg2a519312009-02-10 21:25:55 +01007998
Johannes Berg79c97e92009-07-07 03:56:12 +02007999 rdev->scan_req = request;
Hila Gonene35e4d22012-06-27 17:19:42 +03008000 err = rdev_scan(rdev, request);
Johannes Berg2a519312009-02-10 21:25:55 +01008001
Christophe JAILLET504776b2020-07-12 19:35:51 +02008002 if (err)
8003 goto out_free;
8004
8005 nl80211_send_scan_start(rdev, wdev);
8006 if (wdev->netdev)
8007 dev_hold(wdev->netdev);
8008
8009 return 0;
8010
Johannes Berg2a519312009-02-10 21:25:55 +01008011 out_free:
Christophe JAILLET504776b2020-07-12 19:35:51 +02008012 rdev->scan_req = NULL;
8013 kfree(request);
Johannes Berg3b858752009-03-12 09:55:09 +01008014
Johannes Berg2a519312009-02-10 21:25:55 +01008015 return err;
8016}
8017
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +05308018static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
8019{
8020 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8021 struct wireless_dev *wdev = info->user_ptr[1];
8022
8023 if (!rdev->ops->abort_scan)
8024 return -EOPNOTSUPP;
8025
8026 if (rdev->scan_msg)
8027 return 0;
8028
8029 if (!rdev->scan_req)
8030 return -ENOENT;
8031
8032 rdev_abort_scan(rdev, wdev);
8033 return 0;
8034}
8035
Avraham Stern3b06d272015-10-12 09:51:34 +03008036static int
8037nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
8038 struct cfg80211_sched_scan_request *request,
8039 struct nlattr **attrs)
8040{
8041 int tmp, err, i = 0;
8042 struct nlattr *attr;
8043
8044 if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
8045 u32 interval;
8046
8047 /*
8048 * If scan plans are not specified,
Arend Van Spriel5a88de52016-11-17 09:02:40 +00008049 * %NL80211_ATTR_SCHED_SCAN_INTERVAL will be specified. In this
Avraham Stern3b06d272015-10-12 09:51:34 +03008050 * case one scan plan will be set with the specified scan
8051 * interval and infinite number of iterations.
8052 */
Avraham Stern3b06d272015-10-12 09:51:34 +03008053 interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
8054 if (!interval)
8055 return -EINVAL;
8056
8057 request->scan_plans[0].interval =
8058 DIV_ROUND_UP(interval, MSEC_PER_SEC);
8059 if (!request->scan_plans[0].interval)
8060 return -EINVAL;
8061
8062 if (request->scan_plans[0].interval >
8063 wiphy->max_sched_scan_plan_interval)
8064 request->scan_plans[0].interval =
8065 wiphy->max_sched_scan_plan_interval;
8066
8067 return 0;
8068 }
8069
8070 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
8071 struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
8072
8073 if (WARN_ON(i >= n_plans))
8074 return -EINVAL;
8075
Johannes Berg8cb08172019-04-26 14:07:28 +02008076 err = nla_parse_nested_deprecated(plan,
8077 NL80211_SCHED_SCAN_PLAN_MAX,
8078 attr, nl80211_plan_policy,
8079 NULL);
Avraham Stern3b06d272015-10-12 09:51:34 +03008080 if (err)
8081 return err;
8082
8083 if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
8084 return -EINVAL;
8085
8086 request->scan_plans[i].interval =
8087 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
8088 if (!request->scan_plans[i].interval ||
8089 request->scan_plans[i].interval >
8090 wiphy->max_sched_scan_plan_interval)
8091 return -EINVAL;
8092
8093 if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
8094 request->scan_plans[i].iterations =
8095 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
8096 if (!request->scan_plans[i].iterations ||
8097 (request->scan_plans[i].iterations >
8098 wiphy->max_sched_scan_plan_iterations))
8099 return -EINVAL;
8100 } else if (i < n_plans - 1) {
8101 /*
8102 * All scan plans but the last one must specify
8103 * a finite number of iterations
8104 */
8105 return -EINVAL;
8106 }
8107
8108 i++;
8109 }
8110
8111 /*
8112 * The last scan plan must not specify the number of
8113 * iterations, it is supposed to run infinitely
8114 */
8115 if (request->scan_plans[n_plans - 1].iterations)
8116 return -EINVAL;
8117
8118 return 0;
8119}
8120
vamsi krishna1e1b11b2019-02-01 18:34:51 +05308121static int
8122nl80211_parse_sched_scan_per_band_rssi(struct wiphy *wiphy,
8123 struct cfg80211_match_set *match_sets,
8124 struct nlattr *tb_band_rssi,
8125 s32 rssi_thold)
8126{
8127 struct nlattr *attr;
8128 int i, tmp, ret = 0;
8129
8130 if (!wiphy_ext_feature_isset(wiphy,
8131 NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD)) {
8132 if (tb_band_rssi)
8133 ret = -EOPNOTSUPP;
8134 else
8135 for (i = 0; i < NUM_NL80211_BANDS; i++)
8136 match_sets->per_band_rssi_thold[i] =
8137 NL80211_SCAN_RSSI_THOLD_OFF;
8138 return ret;
8139 }
8140
8141 for (i = 0; i < NUM_NL80211_BANDS; i++)
8142 match_sets->per_band_rssi_thold[i] = rssi_thold;
8143
8144 nla_for_each_nested(attr, tb_band_rssi, tmp) {
8145 enum nl80211_band band = nla_type(attr);
8146
8147 if (band < 0 || band >= NUM_NL80211_BANDS)
8148 return -EINVAL;
8149
8150 match_sets->per_band_rssi_thold[band] = nla_get_s32(attr);
8151 }
8152
8153 return 0;
8154}
8155
Luciano Coelho256da022014-11-10 16:13:46 +02008156static struct cfg80211_sched_scan_request *
Johannes Bergad2b26a2014-06-12 21:39:05 +02008157nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00008158 struct nlattr **attrs, int max_match_sets)
Luciano Coelho807f8a82011-05-11 17:09:35 +03008159{
8160 struct cfg80211_sched_scan_request *request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008161 struct nlattr *attr;
Avraham Stern3b06d272015-10-12 09:51:34 +03008162 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
Johannes Berg57fbcce2016-04-12 15:56:15 +02008163 enum nl80211_band band;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008164 size_t ie_len;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008165 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
Johannes Bergea73cbc2014-01-24 10:53:53 +01008166 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008167
Luciano Coelho256da022014-11-10 16:13:46 +02008168 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03008169 n_channels = validate_scan_freqs(
Luciano Coelho256da022014-11-10 16:13:46 +02008170 attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008171 if (!n_channels)
Luciano Coelho256da022014-11-10 16:13:46 +02008172 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008173 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02008174 n_channels = ieee80211_get_num_supported_channels(wiphy);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008175 }
8176
Luciano Coelho256da022014-11-10 16:13:46 +02008177 if (attrs[NL80211_ATTR_SCAN_SSIDS])
8178 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03008179 tmp)
8180 n_ssids++;
8181
Luciano Coelho93b6aa62011-07-13 14:57:28 +03008182 if (n_ssids > wiphy->max_sched_scan_ssids)
Luciano Coelho256da022014-11-10 16:13:46 +02008183 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008184
Johannes Bergea73cbc2014-01-24 10:53:53 +01008185 /*
8186 * First, count the number of 'real' matchsets. Due to an issue with
8187 * the old implementation, matchsets containing only the RSSI attribute
8188 * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
8189 * RSSI for all matchsets, rather than their own matchset for reporting
8190 * all APs with a strong RSSI. This is needed to be compatible with
8191 * older userspace that treated a matchset with only the RSSI as the
8192 * global RSSI for all other matchsets - if there are other matchsets.
8193 */
Luciano Coelho256da022014-11-10 16:13:46 +02008194 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008195 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02008196 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Johannes Bergea73cbc2014-01-24 10:53:53 +01008197 tmp) {
8198 struct nlattr *rssi;
8199
Johannes Berg8cb08172019-04-26 14:07:28 +02008200 err = nla_parse_nested_deprecated(tb,
8201 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
8202 attr,
8203 nl80211_match_policy,
8204 NULL);
Johannes Bergea73cbc2014-01-24 10:53:53 +01008205 if (err)
Luciano Coelho256da022014-11-10 16:13:46 +02008206 return ERR_PTR(err);
Arend Van Spriel3007e352017-04-21 13:05:01 +01008207
8208 /* SSID and BSSID are mutually exclusive */
8209 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] &&
8210 tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID])
8211 return ERR_PTR(-EINVAL);
8212
Johannes Bergea73cbc2014-01-24 10:53:53 +01008213 /* add other standalone attributes here */
Arend Van Spriel3007e352017-04-21 13:05:01 +01008214 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] ||
8215 tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID]) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01008216 n_match_sets++;
8217 continue;
8218 }
8219 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
8220 if (rssi)
8221 default_match_rssi = nla_get_s32(rssi);
8222 }
8223 }
8224
8225 /* However, if there's no other matchset, add the RSSI one */
8226 if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
8227 n_match_sets = 1;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008228
Arend Van Sprielaad1e812017-01-27 12:27:44 +00008229 if (n_match_sets > max_match_sets)
Luciano Coelho256da022014-11-10 16:13:46 +02008230 return ERR_PTR(-EINVAL);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008231
Luciano Coelho256da022014-11-10 16:13:46 +02008232 if (attrs[NL80211_ATTR_IE])
8233 ie_len = nla_len(attrs[NL80211_ATTR_IE]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008234 else
8235 ie_len = 0;
8236
Luciano Coelho5a865ba2011-07-13 14:57:29 +03008237 if (ie_len > wiphy->max_sched_scan_ie_len)
Luciano Coelho256da022014-11-10 16:13:46 +02008238 return ERR_PTR(-EINVAL);
Luciano Coelhoc10841c2011-06-30 08:32:41 +03008239
Avraham Stern3b06d272015-10-12 09:51:34 +03008240 if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
8241 /*
8242 * NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
8243 * each scan plan already specifies its own interval
8244 */
8245 if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
8246 return ERR_PTR(-EINVAL);
8247
8248 nla_for_each_nested(attr,
8249 attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
8250 n_plans++;
8251 } else {
8252 /*
8253 * The scan interval attribute is kept for backward
8254 * compatibility. If no scan plans are specified and sched scan
8255 * interval is specified, one scan plan will be set with this
8256 * scan interval and infinite number of iterations.
8257 */
8258 if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
8259 return ERR_PTR(-EINVAL);
8260
8261 n_plans = 1;
8262 }
8263
8264 if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
8265 return ERR_PTR(-EINVAL);
8266
vamsi krishnabf95ecd2017-01-13 01:12:20 +02008267 if (!wiphy_ext_feature_isset(
8268 wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
8269 (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
8270 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
8271 return ERR_PTR(-EINVAL);
8272
Luciano Coelho807f8a82011-05-11 17:09:35 +03008273 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03008274 + sizeof(*request->ssids) * n_ssids
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008275 + sizeof(*request->match_sets) * n_match_sets
Avraham Stern3b06d272015-10-12 09:51:34 +03008276 + sizeof(*request->scan_plans) * n_plans
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03008277 + sizeof(*request->channels) * n_channels
Luciano Coelho807f8a82011-05-11 17:09:35 +03008278 + ie_len, GFP_KERNEL);
Luciano Coelho256da022014-11-10 16:13:46 +02008279 if (!request)
8280 return ERR_PTR(-ENOMEM);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008281
8282 if (n_ssids)
8283 request->ssids = (void *)&request->channels[n_channels];
8284 request->n_ssids = n_ssids;
8285 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01008286 if (n_ssids)
Luciano Coelho807f8a82011-05-11 17:09:35 +03008287 request->ie = (void *)(request->ssids + n_ssids);
8288 else
8289 request->ie = (void *)(request->channels + n_channels);
8290 }
8291
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008292 if (n_match_sets) {
8293 if (request->ie)
8294 request->match_sets = (void *)(request->ie + ie_len);
Johannes Berg13874e42015-01-23 11:25:20 +01008295 else if (n_ssids)
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008296 request->match_sets =
8297 (void *)(request->ssids + n_ssids);
8298 else
8299 request->match_sets =
8300 (void *)(request->channels + n_channels);
8301 }
8302 request->n_match_sets = n_match_sets;
8303
Avraham Stern3b06d272015-10-12 09:51:34 +03008304 if (n_match_sets)
8305 request->scan_plans = (void *)(request->match_sets +
8306 n_match_sets);
8307 else if (request->ie)
8308 request->scan_plans = (void *)(request->ie + ie_len);
8309 else if (n_ssids)
8310 request->scan_plans = (void *)(request->ssids + n_ssids);
8311 else
8312 request->scan_plans = (void *)(request->channels + n_channels);
8313
8314 request->n_scan_plans = n_plans;
8315
Luciano Coelho807f8a82011-05-11 17:09:35 +03008316 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02008317 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03008318 /* user specified, bail out if channel not found */
8319 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02008320 attrs[NL80211_ATTR_SCAN_FREQUENCIES],
Luciano Coelho807f8a82011-05-11 17:09:35 +03008321 tmp) {
8322 struct ieee80211_channel *chan;
8323
8324 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
8325
8326 if (!chan) {
8327 err = -EINVAL;
8328 goto out_free;
8329 }
8330
8331 /* ignore disabled channels */
8332 if (chan->flags & IEEE80211_CHAN_DISABLED)
8333 continue;
8334
8335 request->channels[i] = chan;
8336 i++;
8337 }
8338 } else {
8339 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02008340 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03008341 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07008342
Luciano Coelho807f8a82011-05-11 17:09:35 +03008343 if (!wiphy->bands[band])
8344 continue;
8345 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
8346 struct ieee80211_channel *chan;
8347
8348 chan = &wiphy->bands[band]->channels[j];
8349
8350 if (chan->flags & IEEE80211_CHAN_DISABLED)
8351 continue;
8352
8353 request->channels[i] = chan;
8354 i++;
8355 }
8356 }
8357 }
8358
8359 if (!i) {
8360 err = -EINVAL;
8361 goto out_free;
8362 }
8363
8364 request->n_channels = i;
8365
8366 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01008367 if (n_ssids) {
Luciano Coelho256da022014-11-10 16:13:46 +02008368 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03008369 tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03008370 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03008371 err = -EINVAL;
8372 goto out_free;
8373 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03008374 request->ssids[i].ssid_len = nla_len(attr);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008375 memcpy(request->ssids[i].ssid, nla_data(attr),
8376 nla_len(attr));
Luciano Coelho807f8a82011-05-11 17:09:35 +03008377 i++;
8378 }
8379 }
8380
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008381 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02008382 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008383 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02008384 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008385 tmp) {
Arend Van Spriel3007e352017-04-21 13:05:01 +01008386 struct nlattr *ssid, *bssid, *rssi;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008387
Johannes Berg8cb08172019-04-26 14:07:28 +02008388 err = nla_parse_nested_deprecated(tb,
8389 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
8390 attr,
8391 nl80211_match_policy,
8392 NULL);
Johannes Bergae811e22014-01-24 10:17:47 +01008393 if (err)
8394 goto out_free;
Johannes Berg4a4ab0d2012-06-13 11:17:11 +02008395 ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
Arend Van Spriel3007e352017-04-21 13:05:01 +01008396 bssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID];
Johannes Bergd39f3b42019-04-08 13:40:47 +02008397
8398 if (!ssid && !bssid) {
8399 i++;
8400 continue;
8401 }
8402
8403 if (WARN_ON(i >= n_match_sets)) {
8404 /* this indicates a programming error,
8405 * the loop above should have verified
8406 * things properly
8407 */
8408 err = -EINVAL;
8409 goto out_free;
8410 }
8411
8412 if (ssid) {
Johannes Bergd39f3b42019-04-08 13:40:47 +02008413 memcpy(request->match_sets[i].ssid.ssid,
8414 nla_data(ssid), nla_len(ssid));
8415 request->match_sets[i].ssid.ssid_len =
8416 nla_len(ssid);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008417 }
Johannes Bergcb9abd42020-08-05 15:47:16 +02008418 if (bssid)
Johannes Bergd39f3b42019-04-08 13:40:47 +02008419 memcpy(request->match_sets[i].bssid,
8420 nla_data(bssid), ETH_ALEN);
Johannes Bergd39f3b42019-04-08 13:40:47 +02008421
8422 /* special attribute - old implementation w/a */
8423 request->match_sets[i].rssi_thold = default_match_rssi;
8424 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
8425 if (rssi)
8426 request->match_sets[i].rssi_thold =
8427 nla_get_s32(rssi);
vamsi krishna1e1b11b2019-02-01 18:34:51 +05308428
8429 /* Parse per band RSSI attribute */
8430 err = nl80211_parse_sched_scan_per_band_rssi(wiphy,
8431 &request->match_sets[i],
8432 tb[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI],
8433 request->match_sets[i].rssi_thold);
8434 if (err)
8435 goto out_free;
8436
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008437 i++;
8438 }
Johannes Bergea73cbc2014-01-24 10:53:53 +01008439
8440 /* there was no other matchset, so the RSSI one is alone */
Luciano Coelhof89f46c2014-12-01 11:32:09 +02008441 if (i == 0 && n_match_sets)
Johannes Bergea73cbc2014-01-24 10:53:53 +01008442 request->match_sets[0].rssi_thold = default_match_rssi;
8443
8444 request->min_rssi_thold = INT_MAX;
8445 for (i = 0; i < n_match_sets; i++)
8446 request->min_rssi_thold =
8447 min(request->match_sets[i].rssi_thold,
8448 request->min_rssi_thold);
8449 } else {
8450 request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008451 }
8452
Johannes Berg9900e482014-02-04 21:01:25 +01008453 if (ie_len) {
8454 request->ie_len = ie_len;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008455 memcpy((void *)request->ie,
Luciano Coelho256da022014-11-10 16:13:46 +02008456 nla_data(attrs[NL80211_ATTR_IE]),
Luciano Coelho807f8a82011-05-11 17:09:35 +03008457 request->ie_len);
8458 }
8459
Roee Zamir2d23d072017-08-06 11:38:22 +03008460 err = nl80211_check_scan_flags(wiphy, wdev, request, attrs, true);
8461 if (err)
8462 goto out_free;
Sam Lefflered4737712012-10-11 21:03:31 -07008463
Luciano Coelho9c748932015-01-16 16:04:09 +02008464 if (attrs[NL80211_ATTR_SCHED_SCAN_DELAY])
8465 request->delay =
8466 nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
8467
vamsi krishnabf95ecd2017-01-13 01:12:20 +02008468 if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
8469 request->relative_rssi = nla_get_s8(
8470 attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
8471 request->relative_rssi_set = true;
8472 }
8473
8474 if (request->relative_rssi_set &&
8475 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
8476 struct nl80211_bss_select_rssi_adjust *rssi_adjust;
8477
8478 rssi_adjust = nla_data(
8479 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
8480 request->rssi_adjust.band = rssi_adjust->band;
8481 request->rssi_adjust.delta = rssi_adjust->delta;
8482 if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
8483 err = -EINVAL;
8484 goto out_free;
8485 }
8486 }
8487
Avraham Stern3b06d272015-10-12 09:51:34 +03008488 err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
8489 if (err)
8490 goto out_free;
8491
Sam Leffler15d60302012-10-11 21:03:34 -07008492 request->scan_start = jiffies;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008493
Luciano Coelho256da022014-11-10 16:13:46 +02008494 return request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008495
8496out_free:
8497 kfree(request);
Luciano Coelho256da022014-11-10 16:13:46 +02008498 return ERR_PTR(err);
8499}
8500
8501static int nl80211_start_sched_scan(struct sk_buff *skb,
8502 struct genl_info *info)
8503{
8504 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8505 struct net_device *dev = info->user_ptr[1];
Johannes Bergad2b26a2014-06-12 21:39:05 +02008506 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02008507 struct cfg80211_sched_scan_request *sched_scan_req;
Arend Van Sprielca986ad2017-04-21 13:05:00 +01008508 bool want_multi;
Luciano Coelho256da022014-11-10 16:13:46 +02008509 int err;
8510
Arend Van Sprielca986ad2017-04-21 13:05:00 +01008511 if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_start)
Luciano Coelho256da022014-11-10 16:13:46 +02008512 return -EOPNOTSUPP;
8513
Arend Van Sprielca986ad2017-04-21 13:05:00 +01008514 want_multi = info->attrs[NL80211_ATTR_SCHED_SCAN_MULTI];
8515 err = cfg80211_sched_scan_req_possible(rdev, want_multi);
8516 if (err)
8517 return err;
Luciano Coelho256da022014-11-10 16:13:46 +02008518
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02008519 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00008520 info->attrs,
8521 rdev->wiphy.max_match_sets);
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02008522
8523 err = PTR_ERR_OR_ZERO(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02008524 if (err)
8525 goto out_err;
8526
Arend Van Sprielca986ad2017-04-21 13:05:00 +01008527 /* leave request id zero for legacy request
8528 * or if driver does not support multi-scheduled scan
8529 */
Denis Kenzior2fd351a2019-10-08 11:43:50 -05008530 if (want_multi && rdev->wiphy.max_sched_scan_reqs > 1)
8531 sched_scan_req->reqid = cfg80211_assign_cookie(rdev);
Arend Van Sprielca986ad2017-04-21 13:05:00 +01008532
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02008533 err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02008534 if (err)
8535 goto out_free;
8536
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02008537 sched_scan_req->dev = dev;
8538 sched_scan_req->wiphy = &rdev->wiphy;
8539
Jukka Rissanen93a1e862014-12-15 13:25:39 +02008540 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
8541 sched_scan_req->owner_nlportid = info->snd_portid;
8542
Arend Van Sprielca986ad2017-04-21 13:05:00 +01008543 cfg80211_add_sched_scan_req(rdev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02008544
Arend Van Spriel96b08fd2017-04-13 13:06:27 +01008545 nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN);
Luciano Coelho256da022014-11-10 16:13:46 +02008546 return 0;
8547
8548out_free:
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02008549 kfree(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02008550out_err:
Luciano Coelho807f8a82011-05-11 17:09:35 +03008551 return err;
8552}
8553
8554static int nl80211_stop_sched_scan(struct sk_buff *skb,
8555 struct genl_info *info)
8556{
Arend Van Sprielca986ad2017-04-21 13:05:00 +01008557 struct cfg80211_sched_scan_request *req;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008558 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Arend Van Sprielca986ad2017-04-21 13:05:00 +01008559 u64 cookie;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008560
Arend Van Sprielca986ad2017-04-21 13:05:00 +01008561 if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_stop)
Luciano Coelho807f8a82011-05-11 17:09:35 +03008562 return -EOPNOTSUPP;
8563
Arend Van Sprielca986ad2017-04-21 13:05:00 +01008564 if (info->attrs[NL80211_ATTR_COOKIE]) {
8565 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
8566 return __cfg80211_stop_sched_scan(rdev, cookie, false);
8567 }
8568
8569 req = list_first_or_null_rcu(&rdev->sched_scan_req_list,
8570 struct cfg80211_sched_scan_request,
8571 list);
8572 if (!req || req->reqid ||
8573 (req->owner_nlportid &&
8574 req->owner_nlportid != info->snd_portid))
8575 return -ENOENT;
8576
8577 return cfg80211_stop_sched_scan_req(rdev, req, false);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008578}
8579
Simon Wunderlich04f39042013-02-08 18:16:19 +01008580static int nl80211_start_radar_detection(struct sk_buff *skb,
8581 struct genl_info *info)
8582{
8583 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8584 struct net_device *dev = info->user_ptr[1];
8585 struct wireless_dev *wdev = dev->ieee80211_ptr;
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03008586 struct wiphy *wiphy = wdev->wiphy;
Simon Wunderlich04f39042013-02-08 18:16:19 +01008587 struct cfg80211_chan_def chandef;
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01008588 enum nl80211_dfs_regions dfs_region;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01008589 unsigned int cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01008590 int err;
8591
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03008592 dfs_region = reg_get_dfs_region(wiphy);
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01008593 if (dfs_region == NL80211_DFS_UNSET)
8594 return -EINVAL;
8595
Simon Wunderlich04f39042013-02-08 18:16:19 +01008596 err = nl80211_parse_chandef(rdev, info, &chandef);
8597 if (err)
8598 return err;
8599
Simon Wunderlichff311bc2013-09-03 19:43:18 +02008600 if (netif_carrier_ok(dev))
8601 return -EBUSY;
8602
Simon Wunderlich04f39042013-02-08 18:16:19 +01008603 if (wdev->cac_started)
8604 return -EBUSY;
8605
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03008606 err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
Simon Wunderlich04f39042013-02-08 18:16:19 +01008607 if (err < 0)
8608 return err;
8609
8610 if (err == 0)
8611 return -EINVAL;
8612
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03008613 if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
Simon Wunderlich04f39042013-02-08 18:16:19 +01008614 return -EINVAL;
8615
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03008616 /* CAC start is offloaded to HW and can't be started manually */
8617 if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))
8618 return -EOPNOTSUPP;
8619
Simon Wunderlich04f39042013-02-08 18:16:19 +01008620 if (!rdev->ops->start_radar_detection)
8621 return -EOPNOTSUPP;
8622
Janusz Dziedzic31559f32014-02-21 19:46:13 +01008623 cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
8624 if (WARN_ON(!cac_time_ms))
8625 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
8626
Ilan Peera1056b1b2015-10-22 22:27:46 +03008627 err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
Simon Wunderlich04f39042013-02-08 18:16:19 +01008628 if (!err) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01008629 wdev->chandef = chandef;
Simon Wunderlich04f39042013-02-08 18:16:19 +01008630 wdev->cac_started = true;
8631 wdev->cac_start_time = jiffies;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01008632 wdev->cac_time_ms = cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01008633 }
Simon Wunderlich04f39042013-02-08 18:16:19 +01008634 return err;
8635}
8636
Sriram R30c63112018-12-04 17:46:52 +05308637static int nl80211_notify_radar_detection(struct sk_buff *skb,
8638 struct genl_info *info)
8639{
8640 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8641 struct net_device *dev = info->user_ptr[1];
8642 struct wireless_dev *wdev = dev->ieee80211_ptr;
8643 struct wiphy *wiphy = wdev->wiphy;
8644 struct cfg80211_chan_def chandef;
8645 enum nl80211_dfs_regions dfs_region;
8646 int err;
8647
8648 dfs_region = reg_get_dfs_region(wiphy);
8649 if (dfs_region == NL80211_DFS_UNSET) {
8650 GENL_SET_ERR_MSG(info,
8651 "DFS Region is not set. Unexpected Radar indication");
8652 return -EINVAL;
8653 }
8654
8655 err = nl80211_parse_chandef(rdev, info, &chandef);
8656 if (err) {
8657 GENL_SET_ERR_MSG(info, "Unable to extract chandef info");
8658 return err;
8659 }
8660
8661 err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
8662 if (err < 0) {
8663 GENL_SET_ERR_MSG(info, "chandef is invalid");
8664 return err;
8665 }
8666
8667 if (err == 0) {
8668 GENL_SET_ERR_MSG(info,
8669 "Unexpected Radar indication for chandef/iftype");
8670 return -EINVAL;
8671 }
8672
8673 /* Do not process this notification if radar is already detected
8674 * by kernel on this channel, and return success.
8675 */
8676 if (chandef.chan->dfs_state == NL80211_DFS_UNAVAILABLE)
8677 return 0;
8678
8679 cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_UNAVAILABLE);
8680
8681 cfg80211_sched_dfs_chan_update(rdev);
8682
Luca Coelhoa680fe42019-04-17 09:34:40 +03008683 rdev->radar_chandef = chandef;
Sriram R30c63112018-12-04 17:46:52 +05308684
8685 /* Propagate this notification to other radios as well */
8686 queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
8687
8688 return 0;
8689}
8690
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008691static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
8692{
8693 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8694 struct net_device *dev = info->user_ptr[1];
8695 struct wireless_dev *wdev = dev->ieee80211_ptr;
8696 struct cfg80211_csa_settings params;
8697 /* csa_attrs is defined static to avoid waste of stack size - this
8698 * function is called under RTNL lock, so this should not be a problem.
8699 */
8700 static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008701 int err;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02008702 bool need_new_beacon = false;
Benjamin Berg8d9de162017-05-16 11:23:12 +02008703 bool need_handle_dfs_flag = true;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03008704 int len, i;
Luciano Coelho252e07c2014-10-08 09:48:34 +03008705 u32 cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008706
8707 if (!rdev->ops->channel_switch ||
8708 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
8709 return -EOPNOTSUPP;
8710
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02008711 switch (dev->ieee80211_ptr->iftype) {
8712 case NL80211_IFTYPE_AP:
8713 case NL80211_IFTYPE_P2P_GO:
8714 need_new_beacon = true;
Benjamin Berg8d9de162017-05-16 11:23:12 +02008715 /* For all modes except AP the handle_dfs flag needs to be
8716 * supplied to tell the kernel that userspace will handle radar
8717 * events when they happen. Otherwise a switch to a channel
8718 * requiring DFS will be rejected.
8719 */
8720 need_handle_dfs_flag = false;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02008721
8722 /* useless if AP is not running */
8723 if (!wdev->beacon_interval)
Johannes Berg1ff79df2014-01-22 10:05:27 +01008724 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02008725 break;
8726 case NL80211_IFTYPE_ADHOC:
Johannes Berg1ff79df2014-01-22 10:05:27 +01008727 if (!wdev->ssid_len)
8728 return -ENOTCONN;
8729 break;
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07008730 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg1ff79df2014-01-22 10:05:27 +01008731 if (!wdev->mesh_id_len)
8732 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02008733 break;
8734 default:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008735 return -EOPNOTSUPP;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02008736 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008737
8738 memset(&params, 0, sizeof(params));
Johannes Bergc177db22018-10-30 09:17:44 +01008739 params.beacon_csa.ftm_responder = -1;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008740
8741 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
8742 !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
8743 return -EINVAL;
8744
8745 /* only important for AP, IBSS and mesh create IEs internally */
Andrei Otcheretianskid0a361a2013-10-17 10:52:17 +02008746 if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008747 return -EINVAL;
8748
Luciano Coelho252e07c2014-10-08 09:48:34 +03008749 /* Even though the attribute is u32, the specification says
8750 * u8, so let's make sure we don't overflow.
8751 */
8752 cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
8753 if (cs_count > 255)
8754 return -EINVAL;
8755
8756 params.count = cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008757
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02008758 if (!need_new_beacon)
8759 goto skip_beacons;
8760
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07008761 err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_after);
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008762 if (err)
8763 return err;
8764
Johannes Berg8cb08172019-04-26 14:07:28 +02008765 err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX,
8766 info->attrs[NL80211_ATTR_CSA_IES],
8767 nl80211_policy, info->extack);
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008768 if (err)
8769 return err;
8770
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07008771 err = nl80211_parse_beacon(rdev, csa_attrs, &params.beacon_csa);
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008772 if (err)
8773 return err;
8774
8775 if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
8776 return -EINVAL;
8777
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03008778 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
8779 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008780 return -EINVAL;
8781
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03008782 params.n_counter_offsets_beacon = len / sizeof(u16);
8783 if (rdev->wiphy.max_num_csa_counters &&
8784 (params.n_counter_offsets_beacon >
8785 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008786 return -EINVAL;
8787
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03008788 params.counter_offsets_beacon =
8789 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
8790
8791 /* sanity checks - counters should fit and be the same */
8792 for (i = 0; i < params.n_counter_offsets_beacon; i++) {
8793 u16 offset = params.counter_offsets_beacon[i];
8794
8795 if (offset >= params.beacon_csa.tail_len)
8796 return -EINVAL;
8797
8798 if (params.beacon_csa.tail[offset] != params.count)
8799 return -EINVAL;
8800 }
8801
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008802 if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03008803 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
8804 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008805 return -EINVAL;
8806
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03008807 params.n_counter_offsets_presp = len / sizeof(u16);
8808 if (rdev->wiphy.max_num_csa_counters &&
Johannes Bergad5987b2016-09-13 15:53:55 +02008809 (params.n_counter_offsets_presp >
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03008810 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008811 return -EINVAL;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03008812
8813 params.counter_offsets_presp =
8814 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
8815
8816 /* sanity checks - counters should fit and be the same */
8817 for (i = 0; i < params.n_counter_offsets_presp; i++) {
8818 u16 offset = params.counter_offsets_presp[i];
8819
8820 if (offset >= params.beacon_csa.probe_resp_len)
8821 return -EINVAL;
8822
8823 if (params.beacon_csa.probe_resp[offset] !=
8824 params.count)
8825 return -EINVAL;
8826 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008827 }
8828
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02008829skip_beacons:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008830 err = nl80211_parse_chandef(rdev, info, &params.chandef);
8831 if (err)
8832 return err;
8833
Arik Nemtsov923b3522015-07-08 15:41:44 +03008834 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
8835 wdev->iftype))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008836 return -EINVAL;
8837
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02008838 err = cfg80211_chandef_dfs_required(wdev->wiphy,
8839 &params.chandef,
8840 wdev->iftype);
8841 if (err < 0)
8842 return err;
8843
Benjamin Berg8d9de162017-05-16 11:23:12 +02008844 if (err > 0) {
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02008845 params.radar_required = true;
Benjamin Berg8d9de162017-05-16 11:23:12 +02008846 if (need_handle_dfs_flag &&
8847 !nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) {
8848 return -EINVAL;
8849 }
8850 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008851
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008852 if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
8853 params.block_tx = true;
8854
Simon Wunderlichc56589e2013-11-21 18:19:49 +01008855 wdev_lock(wdev);
8856 err = rdev_channel_switch(rdev, dev, &params);
8857 wdev_unlock(wdev);
8858
8859 return err;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02008860}
8861
Johannes Berg9720bb32011-06-21 09:45:33 +02008862static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
8863 u32 seq, int flags,
Johannes Berg2a519312009-02-10 21:25:55 +01008864 struct cfg80211_registered_device *rdev,
Johannes Berg48ab9052009-07-10 18:42:31 +02008865 struct wireless_dev *wdev,
8866 struct cfg80211_internal_bss *intbss)
Johannes Berg2a519312009-02-10 21:25:55 +01008867{
Johannes Berg48ab9052009-07-10 18:42:31 +02008868 struct cfg80211_bss *res = &intbss->pub;
Johannes Berg9caf0362012-11-29 01:25:20 +01008869 const struct cfg80211_bss_ies *ies;
Johannes Berg2a519312009-02-10 21:25:55 +01008870 void *hdr;
8871 struct nlattr *bss;
Johannes Berg48ab9052009-07-10 18:42:31 +02008872
8873 ASSERT_WDEV_LOCK(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01008874
Eric W. Biederman15e47302012-09-07 20:12:54 +00008875 hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
Johannes Berg2a519312009-02-10 21:25:55 +01008876 NL80211_CMD_NEW_SCAN_RESULTS);
8877 if (!hdr)
8878 return -1;
8879
Michal Kubecek0a833c22017-11-15 13:09:32 +01008880 genl_dump_check_consistent(cb, hdr);
Johannes Berg9720bb32011-06-21 09:45:33 +02008881
Johannes Berg97990a02013-04-19 01:02:55 +02008882 if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
8883 goto nla_put_failure;
8884 if (wdev->netdev &&
David S. Miller9360ffd2012-03-29 04:41:26 -04008885 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
8886 goto nla_put_failure;
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008887 if (nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
8888 NL80211_ATTR_PAD))
Johannes Berg97990a02013-04-19 01:02:55 +02008889 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01008890
Michal Kubecekae0be8d2019-04-26 11:13:06 +02008891 bss = nla_nest_start_noflag(msg, NL80211_ATTR_BSS);
Johannes Berg2a519312009-02-10 21:25:55 +01008892 if (!bss)
8893 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04008894 if ((!is_zero_ether_addr(res->bssid) &&
Johannes Berg9caf0362012-11-29 01:25:20 +01008895 nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
David S. Miller9360ffd2012-03-29 04:41:26 -04008896 goto nla_put_failure;
Johannes Berg9caf0362012-11-29 01:25:20 +01008897
8898 rcu_read_lock();
Johannes Berg0e227082014-08-12 20:34:30 +02008899 /* indicate whether we have probe response data or not */
8900 if (rcu_access_pointer(res->proberesp_ies) &&
8901 nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
8902 goto fail_unlock_rcu;
8903
8904 /* this pointer prefers to be pointed to probe response data
8905 * but is always valid
8906 */
Johannes Berg9caf0362012-11-29 01:25:20 +01008907 ies = rcu_dereference(res->ies);
Johannes Berg8cef2c92013-02-05 16:54:31 +01008908 if (ies) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008909 if (nla_put_u64_64bit(msg, NL80211_BSS_TSF, ies->tsf,
8910 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01008911 goto fail_unlock_rcu;
Johannes Berg8cef2c92013-02-05 16:54:31 +01008912 if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
8913 ies->len, ies->data))
8914 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01008915 }
Johannes Berg0e227082014-08-12 20:34:30 +02008916
8917 /* and this pointer is always (unless driver didn't know) beacon data */
Johannes Berg9caf0362012-11-29 01:25:20 +01008918 ies = rcu_dereference(res->beacon_ies);
Johannes Berg0e227082014-08-12 20:34:30 +02008919 if (ies && ies->from_beacon) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008920 if (nla_put_u64_64bit(msg, NL80211_BSS_BEACON_TSF, ies->tsf,
8921 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01008922 goto fail_unlock_rcu;
8923 if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
8924 ies->len, ies->data))
8925 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01008926 }
8927 rcu_read_unlock();
8928
David S. Miller9360ffd2012-03-29 04:41:26 -04008929 if (res->beacon_interval &&
8930 nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
8931 goto nla_put_failure;
8932 if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
8933 nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
Thomas Pedersen942ba882020-04-30 10:25:51 -07008934 nla_put_u32(msg, NL80211_BSS_FREQUENCY_OFFSET,
8935 res->channel->freq_offset) ||
Simon Wunderlichdcd6eac2013-07-08 16:55:49 +02008936 nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04008937 nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
8938 jiffies_to_msecs(jiffies - intbss->ts)))
8939 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01008940
Avraham Stern1d762502016-07-05 17:10:13 +03008941 if (intbss->parent_tsf &&
8942 (nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
8943 intbss->parent_tsf, NL80211_BSS_PAD) ||
8944 nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
8945 intbss->parent_bssid)))
8946 goto nla_put_failure;
8947
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02008948 if (intbss->ts_boottime &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008949 nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
8950 intbss->ts_boottime, NL80211_BSS_PAD))
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02008951 goto nla_put_failure;
8952
Sunil Dutt983dafa2017-12-13 19:51:36 +02008953 if (!nl80211_put_signal(msg, intbss->pub.chains,
8954 intbss->pub.chain_signal,
8955 NL80211_BSS_CHAIN_SIGNAL))
8956 goto nla_put_failure;
8957
Johannes Berg77965c972009-02-18 18:45:06 +01008958 switch (rdev->wiphy.signal_type) {
Johannes Berg2a519312009-02-10 21:25:55 +01008959 case CFG80211_SIGNAL_TYPE_MBM:
David S. Miller9360ffd2012-03-29 04:41:26 -04008960 if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
8961 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01008962 break;
8963 case CFG80211_SIGNAL_TYPE_UNSPEC:
David S. Miller9360ffd2012-03-29 04:41:26 -04008964 if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
8965 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01008966 break;
8967 default:
8968 break;
8969 }
8970
Johannes Berg48ab9052009-07-10 18:42:31 +02008971 switch (wdev->iftype) {
Johannes Berg074ac8d2010-09-16 14:58:22 +02008972 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg48ab9052009-07-10 18:42:31 +02008973 case NL80211_IFTYPE_STATION:
David S. Miller9360ffd2012-03-29 04:41:26 -04008974 if (intbss == wdev->current_bss &&
8975 nla_put_u32(msg, NL80211_BSS_STATUS,
8976 NL80211_BSS_STATUS_ASSOCIATED))
8977 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02008978 break;
8979 case NL80211_IFTYPE_ADHOC:
David S. Miller9360ffd2012-03-29 04:41:26 -04008980 if (intbss == wdev->current_bss &&
8981 nla_put_u32(msg, NL80211_BSS_STATUS,
8982 NL80211_BSS_STATUS_IBSS_JOINED))
8983 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02008984 break;
8985 default:
8986 break;
8987 }
8988
Johannes Berg2a519312009-02-10 21:25:55 +01008989 nla_nest_end(msg, bss);
8990
Johannes Berg053c0952015-01-16 22:09:00 +01008991 genlmsg_end(msg, hdr);
8992 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +01008993
Johannes Berg8cef2c92013-02-05 16:54:31 +01008994 fail_unlock_rcu:
8995 rcu_read_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01008996 nla_put_failure:
8997 genlmsg_cancel(msg, hdr);
8998 return -EMSGSIZE;
8999}
9000
Johannes Berg97990a02013-04-19 01:02:55 +02009001static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
Johannes Berg2a519312009-02-10 21:25:55 +01009002{
Johannes Berg48ab9052009-07-10 18:42:31 +02009003 struct cfg80211_registered_device *rdev;
Johannes Berg2a519312009-02-10 21:25:55 +01009004 struct cfg80211_internal_bss *scan;
Johannes Berg48ab9052009-07-10 18:42:31 +02009005 struct wireless_dev *wdev;
Johannes Berg97990a02013-04-19 01:02:55 +02009006 int start = cb->args[2], idx = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01009007 int err;
9008
Johannes Bergea90e0d2017-03-15 14:26:04 +01009009 rtnl_lock();
Johannes Berg5297c652018-09-27 14:36:44 +02009010 err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
Johannes Bergea90e0d2017-03-15 14:26:04 +01009011 if (err) {
9012 rtnl_unlock();
Johannes Berg67748892010-10-04 21:14:06 +02009013 return err;
Johannes Bergea90e0d2017-03-15 14:26:04 +01009014 }
Johannes Berg2a519312009-02-10 21:25:55 +01009015
Johannes Berg48ab9052009-07-10 18:42:31 +02009016 wdev_lock(wdev);
9017 spin_lock_bh(&rdev->bss_lock);
Denis Kenziord1e23c92018-05-21 10:31:13 -05009018
9019 /*
9020 * dump_scan will be called multiple times to break up the scan results
9021 * into multiple messages. It is unlikely that any more bss-es will be
9022 * expired after the first call, so only call only call this on the
9023 * first dump_scan invocation.
9024 */
9025 if (start == 0)
9026 cfg80211_bss_expire(rdev);
Johannes Berg48ab9052009-07-10 18:42:31 +02009027
Johannes Berg9720bb32011-06-21 09:45:33 +02009028 cb->seq = rdev->bss_generation;
9029
Johannes Berg48ab9052009-07-10 18:42:31 +02009030 list_for_each_entry(scan, &rdev->bss_list, list) {
Johannes Berg2a519312009-02-10 21:25:55 +01009031 if (++idx <= start)
9032 continue;
Johannes Berg9720bb32011-06-21 09:45:33 +02009033 if (nl80211_send_bss(skb, cb,
Johannes Berg2a519312009-02-10 21:25:55 +01009034 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg48ab9052009-07-10 18:42:31 +02009035 rdev, wdev, scan) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +01009036 idx--;
Johannes Berg67748892010-10-04 21:14:06 +02009037 break;
Johannes Berg2a519312009-02-10 21:25:55 +01009038 }
9039 }
9040
Johannes Berg48ab9052009-07-10 18:42:31 +02009041 spin_unlock_bh(&rdev->bss_lock);
9042 wdev_unlock(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01009043
Johannes Berg97990a02013-04-19 01:02:55 +02009044 cb->args[2] = idx;
Johannes Bergea90e0d2017-03-15 14:26:04 +01009045 rtnl_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01009046
Johannes Berg67748892010-10-04 21:14:06 +02009047 return skb->len;
Johannes Berg2a519312009-02-10 21:25:55 +01009048}
9049
Eric W. Biederman15e47302012-09-07 20:12:54 +00009050static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg11f78ac2014-11-14 16:43:50 +01009051 int flags, struct net_device *dev,
9052 bool allow_radio_stats,
9053 struct survey_info *survey)
Holger Schurig61fa7132009-11-11 12:25:40 +01009054{
9055 void *hdr;
9056 struct nlattr *infoattr;
9057
Johannes Berg11f78ac2014-11-14 16:43:50 +01009058 /* skip radio stats if userspace didn't request them */
9059 if (!survey->channel && !allow_radio_stats)
9060 return 0;
9061
Eric W. Biederman15e47302012-09-07 20:12:54 +00009062 hdr = nl80211hdr_put(msg, portid, seq, flags,
Holger Schurig61fa7132009-11-11 12:25:40 +01009063 NL80211_CMD_NEW_SURVEY_RESULTS);
9064 if (!hdr)
9065 return -ENOMEM;
9066
David S. Miller9360ffd2012-03-29 04:41:26 -04009067 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
9068 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01009069
Michal Kubecekae0be8d2019-04-26 11:13:06 +02009070 infoattr = nla_nest_start_noflag(msg, NL80211_ATTR_SURVEY_INFO);
Holger Schurig61fa7132009-11-11 12:25:40 +01009071 if (!infoattr)
9072 goto nla_put_failure;
9073
Johannes Berg11f78ac2014-11-14 16:43:50 +01009074 if (survey->channel &&
9075 nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
David S. Miller9360ffd2012-03-29 04:41:26 -04009076 survey->channel->center_freq))
9077 goto nla_put_failure;
9078
9079 if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
9080 nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
9081 goto nla_put_failure;
9082 if ((survey->filled & SURVEY_INFO_IN_USE) &&
9083 nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
9084 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01009085 if ((survey->filled & SURVEY_INFO_TIME) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009086 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME,
9087 survey->time, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009088 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01009089 if ((survey->filled & SURVEY_INFO_TIME_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009090 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BUSY,
9091 survey->time_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009092 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01009093 if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009094 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
9095 survey->time_ext_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009096 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01009097 if ((survey->filled & SURVEY_INFO_TIME_RX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009098 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_RX,
9099 survey->time_rx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009100 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01009101 if ((survey->filled & SURVEY_INFO_TIME_TX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009102 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_TX,
9103 survey->time_tx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009104 goto nla_put_failure;
Johannes Berg052536a2014-11-14 16:44:11 +01009105 if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009106 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_SCAN,
9107 survey->time_scan, NL80211_SURVEY_INFO_PAD))
Johannes Berg052536a2014-11-14 16:44:11 +01009108 goto nla_put_failure;
Felix Fietkauc8cd6e72019-08-28 12:20:42 +02009109 if ((survey->filled & SURVEY_INFO_TIME_BSS_RX) &&
9110 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BSS_RX,
9111 survey->time_bss_rx, NL80211_SURVEY_INFO_PAD))
9112 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01009113
9114 nla_nest_end(msg, infoattr);
9115
Johannes Berg053c0952015-01-16 22:09:00 +01009116 genlmsg_end(msg, hdr);
9117 return 0;
Holger Schurig61fa7132009-11-11 12:25:40 +01009118
9119 nla_put_failure:
9120 genlmsg_cancel(msg, hdr);
9121 return -EMSGSIZE;
9122}
9123
Johannes Berg11f78ac2014-11-14 16:43:50 +01009124static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
Holger Schurig61fa7132009-11-11 12:25:40 +01009125{
Johannes Berg50508d92019-07-29 16:31:09 +02009126 struct nlattr **attrbuf;
Holger Schurig61fa7132009-11-11 12:25:40 +01009127 struct survey_info survey;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08009128 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02009129 struct wireless_dev *wdev;
9130 int survey_idx = cb->args[2];
Holger Schurig61fa7132009-11-11 12:25:40 +01009131 int res;
Johannes Berg11f78ac2014-11-14 16:43:50 +01009132 bool radio_stats;
Holger Schurig61fa7132009-11-11 12:25:40 +01009133
Johannes Berg50508d92019-07-29 16:31:09 +02009134 attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
9135 if (!attrbuf)
9136 return -ENOMEM;
9137
Johannes Bergea90e0d2017-03-15 14:26:04 +01009138 rtnl_lock();
Johannes Berg5297c652018-09-27 14:36:44 +02009139 res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02009140 if (res)
Johannes Bergea90e0d2017-03-15 14:26:04 +01009141 goto out_err;
Holger Schurig61fa7132009-11-11 12:25:40 +01009142
Johannes Berg11f78ac2014-11-14 16:43:50 +01009143 /* prepare_wdev_dump parsed the attributes */
Johannes Bergc90c39d2016-10-24 14:40:01 +02009144 radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
Johannes Berg11f78ac2014-11-14 16:43:50 +01009145
Johannes Berg97990a02013-04-19 01:02:55 +02009146 if (!wdev->netdev) {
9147 res = -EINVAL;
9148 goto out_err;
9149 }
9150
Zhao, Gang1b8ec872014-04-21 12:53:02 +08009151 if (!rdev->ops->dump_survey) {
Holger Schurig61fa7132009-11-11 12:25:40 +01009152 res = -EOPNOTSUPP;
9153 goto out_err;
9154 }
9155
9156 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08009157 res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
Holger Schurig61fa7132009-11-11 12:25:40 +01009158 if (res == -ENOENT)
9159 break;
9160 if (res)
9161 goto out_err;
9162
Johannes Berg11f78ac2014-11-14 16:43:50 +01009163 /* don't send disabled channels, but do send non-channel data */
9164 if (survey.channel &&
9165 survey.channel->flags & IEEE80211_CHAN_DISABLED) {
Luis R. Rodriguez180cdc72011-05-27 07:24:02 -07009166 survey_idx++;
9167 continue;
9168 }
9169
Holger Schurig61fa7132009-11-11 12:25:40 +01009170 if (nl80211_send_survey(skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00009171 NETLINK_CB(cb->skb).portid,
Holger Schurig61fa7132009-11-11 12:25:40 +01009172 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg11f78ac2014-11-14 16:43:50 +01009173 wdev->netdev, radio_stats, &survey) < 0)
Holger Schurig61fa7132009-11-11 12:25:40 +01009174 goto out;
9175 survey_idx++;
9176 }
9177
9178 out:
Johannes Berg97990a02013-04-19 01:02:55 +02009179 cb->args[2] = survey_idx;
Holger Schurig61fa7132009-11-11 12:25:40 +01009180 res = skb->len;
9181 out_err:
Johannes Berg50508d92019-07-29 16:31:09 +02009182 kfree(attrbuf);
Johannes Bergea90e0d2017-03-15 14:26:04 +01009183 rtnl_unlock();
Holger Schurig61fa7132009-11-11 12:25:40 +01009184 return res;
9185}
9186
Samuel Ortizb23aa672009-07-01 21:26:54 +02009187static bool nl80211_valid_wpa_versions(u32 wpa_versions)
9188{
9189 return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
Chung-Hsien Hsucc3e14c2019-05-09 09:49:05 +00009190 NL80211_WPA_VERSION_2 |
9191 NL80211_WPA_VERSION_3));
Samuel Ortizb23aa672009-07-01 21:26:54 +02009192}
9193
Jouni Malinen636a5d32009-03-19 13:39:22 +02009194static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
9195{
Johannes Berg4c476992010-10-04 21:36:35 +02009196 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9197 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02009198 struct ieee80211_channel *chan;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03009199 const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
9200 int err, ssid_len, ie_len = 0, auth_data_len = 0;
Johannes Berg19957bb2009-07-02 17:20:43 +02009201 enum nl80211_auth_type auth_type;
Johannes Bergfffd0932009-07-08 14:22:54 +02009202 struct key_parse key;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03009203 bool local_state_change;
Thomas Pedersen942ba882020-04-30 10:25:51 -07009204 u32 freq;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009205
Johannes Bergf4a11bb2009-03-27 12:40:28 +01009206 if (!info->attrs[NL80211_ATTR_MAC])
9207 return -EINVAL;
9208
Jouni Malinen17780922009-03-27 20:52:47 +02009209 if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
9210 return -EINVAL;
9211
Johannes Berg19957bb2009-07-02 17:20:43 +02009212 if (!info->attrs[NL80211_ATTR_SSID])
9213 return -EINVAL;
9214
9215 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
9216 return -EINVAL;
9217
Johannes Bergfffd0932009-07-08 14:22:54 +02009218 err = nl80211_parse_key(info, &key);
9219 if (err)
9220 return err;
9221
9222 if (key.idx >= 0) {
Johannes Berge31b8212010-10-05 19:39:30 +02009223 if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
9224 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02009225 if (!key.p.key || !key.p.key_len)
9226 return -EINVAL;
9227 if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
9228 key.p.key_len != WLAN_KEY_LEN_WEP40) &&
9229 (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
9230 key.p.key_len != WLAN_KEY_LEN_WEP104))
9231 return -EINVAL;
Johannes Bergb6b55552016-09-13 16:25:58 +02009232 if (key.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +02009233 return -EINVAL;
9234 } else {
9235 key.p.key_len = 0;
9236 key.p.key = NULL;
9237 }
9238
Johannes Bergafea0b72010-08-10 09:46:42 +02009239 if (key.idx >= 0) {
9240 int i;
9241 bool ok = false;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07009242
Johannes Bergafea0b72010-08-10 09:46:42 +02009243 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
9244 if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
9245 ok = true;
9246 break;
9247 }
9248 }
Johannes Berg4c476992010-10-04 21:36:35 +02009249 if (!ok)
9250 return -EINVAL;
Johannes Bergafea0b72010-08-10 09:46:42 +02009251 }
9252
Johannes Berg4c476992010-10-04 21:36:35 +02009253 if (!rdev->ops->auth)
9254 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009255
Johannes Berg074ac8d2010-09-16 14:58:22 +02009256 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009257 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9258 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02009259
Johannes Berg19957bb2009-07-02 17:20:43 +02009260 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Thomas Pedersen942ba882020-04-30 10:25:51 -07009261 freq = MHZ_TO_KHZ(nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
9262 if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
9263 freq +=
9264 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
9265
9266 chan = nl80211_get_valid_chan(&rdev->wiphy, freq);
Jouni Malinen664834d2014-01-15 00:01:44 +02009267 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02009268 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009269
Johannes Berg19957bb2009-07-02 17:20:43 +02009270 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9271 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9272
9273 if (info->attrs[NL80211_ATTR_IE]) {
9274 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9275 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9276 }
9277
9278 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03009279 if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
Johannes Berg4c476992010-10-04 21:36:35 +02009280 return -EINVAL;
Johannes Berg19957bb2009-07-02 17:20:43 +02009281
Jouni Malinen63181062016-10-27 00:42:02 +03009282 if ((auth_type == NL80211_AUTHTYPE_SAE ||
9283 auth_type == NL80211_AUTHTYPE_FILS_SK ||
9284 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
9285 auth_type == NL80211_AUTHTYPE_FILS_PK) &&
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03009286 !info->attrs[NL80211_ATTR_AUTH_DATA])
Jouni Malinene39e5b52012-09-30 19:29:39 +03009287 return -EINVAL;
9288
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03009289 if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
Jouni Malinen63181062016-10-27 00:42:02 +03009290 if (auth_type != NL80211_AUTHTYPE_SAE &&
9291 auth_type != NL80211_AUTHTYPE_FILS_SK &&
9292 auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
9293 auth_type != NL80211_AUTHTYPE_FILS_PK)
Jouni Malinene39e5b52012-09-30 19:29:39 +03009294 return -EINVAL;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03009295 auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
9296 auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03009297 }
9298
Jouni Malinend5cdfac2010-04-04 09:37:19 +03009299 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
9300
Johannes Berg95de8172012-01-20 13:55:25 +01009301 /*
9302 * Since we no longer track auth state, ignore
9303 * requests to only change local state.
9304 */
9305 if (local_state_change)
9306 return 0;
9307
Johannes Berg91bf9b22013-05-15 17:44:01 +02009308 wdev_lock(dev->ieee80211_ptr);
9309 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
9310 ssid, ssid_len, ie, ie_len,
9311 key.p.key, key.p.key_len, key.idx,
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03009312 auth_data, auth_data_len);
Johannes Berg91bf9b22013-05-15 17:44:01 +02009313 wdev_unlock(dev->ieee80211_ptr);
9314 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009315}
9316
Denis Kenzior64bf3d42018-03-26 12:52:43 -05009317static int validate_pae_over_nl80211(struct cfg80211_registered_device *rdev,
9318 struct genl_info *info)
9319{
9320 if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
9321 GENL_SET_ERR_MSG(info, "SOCKET_OWNER not set");
9322 return -EINVAL;
9323 }
9324
9325 if (!rdev->ops->tx_control_port ||
9326 !wiphy_ext_feature_isset(&rdev->wiphy,
9327 NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
9328 return -EOPNOTSUPP;
9329
9330 return 0;
9331}
9332
Johannes Bergc0692b82010-08-27 14:26:53 +03009333static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
9334 struct genl_info *info,
Johannes Berg3dc27d22009-07-02 21:36:37 +02009335 struct cfg80211_crypto_settings *settings,
9336 int cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02009337{
Johannes Bergc0b2bbd2009-07-25 16:54:36 +02009338 memset(settings, 0, sizeof(*settings));
9339
Samuel Ortizb23aa672009-07-01 21:26:54 +02009340 settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
9341
Johannes Bergc0692b82010-08-27 14:26:53 +03009342 if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
9343 u16 proto;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07009344
Johannes Bergc0692b82010-08-27 14:26:53 +03009345 proto = nla_get_u16(
9346 info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
9347 settings->control_port_ethertype = cpu_to_be16(proto);
9348 if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
9349 proto != ETH_P_PAE)
9350 return -EINVAL;
9351 if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
9352 settings->control_port_no_encrypt = true;
9353 } else
9354 settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
9355
Denis Kenzior64bf3d42018-03-26 12:52:43 -05009356 if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
9357 int r = validate_pae_over_nl80211(rdev, info);
9358
9359 if (r < 0)
9360 return r;
9361
9362 settings->control_port_over_nl80211 = true;
Markus Theil7f3f96c2020-03-12 10:10:54 +01009363
9364 if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_PREAUTH])
9365 settings->control_port_no_preauth = true;
Denis Kenzior64bf3d42018-03-26 12:52:43 -05009366 }
9367
Samuel Ortizb23aa672009-07-01 21:26:54 +02009368 if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
9369 void *data;
9370 int len, i;
9371
9372 data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
9373 len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
9374 settings->n_ciphers_pairwise = len / sizeof(u32);
9375
9376 if (len % sizeof(u32))
9377 return -EINVAL;
9378
Johannes Berg3dc27d22009-07-02 21:36:37 +02009379 if (settings->n_ciphers_pairwise > cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02009380 return -EINVAL;
9381
9382 memcpy(settings->ciphers_pairwise, data, len);
9383
9384 for (i = 0; i < settings->n_ciphers_pairwise; i++)
Jouni Malinen38ba3c52011-09-21 18:14:56 +03009385 if (!cfg80211_supported_cipher_suite(
9386 &rdev->wiphy,
Samuel Ortizb23aa672009-07-01 21:26:54 +02009387 settings->ciphers_pairwise[i]))
9388 return -EINVAL;
9389 }
9390
9391 if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
9392 settings->cipher_group =
9393 nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
Jouni Malinen38ba3c52011-09-21 18:14:56 +03009394 if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
9395 settings->cipher_group))
Samuel Ortizb23aa672009-07-01 21:26:54 +02009396 return -EINVAL;
9397 }
9398
9399 if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
9400 settings->wpa_versions =
9401 nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
9402 if (!nl80211_valid_wpa_versions(settings->wpa_versions))
9403 return -EINVAL;
9404 }
9405
9406 if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
9407 void *data;
Jouni Malinen6d302402011-09-21 18:11:33 +03009408 int len;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009409
9410 data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
9411 len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
9412 settings->n_akm_suites = len / sizeof(u32);
9413
9414 if (len % sizeof(u32))
9415 return -EINVAL;
9416
Jouni Malinen1b9ca022011-09-21 16:13:07 +03009417 if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
9418 return -EINVAL;
9419
Samuel Ortizb23aa672009-07-01 21:26:54 +02009420 memcpy(settings->akm_suites, data, len);
Samuel Ortizb23aa672009-07-01 21:26:54 +02009421 }
9422
Eliad Peller91b5ab62017-06-09 13:08:42 +01009423 if (info->attrs[NL80211_ATTR_PMK]) {
9424 if (nla_len(info->attrs[NL80211_ATTR_PMK]) != WLAN_PMK_LEN)
9425 return -EINVAL;
9426 if (!wiphy_ext_feature_isset(&rdev->wiphy,
Chung-Hsien Hsuf9662272020-06-23 08:49:35 -05009427 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK) &&
9428 !wiphy_ext_feature_isset(&rdev->wiphy,
9429 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK))
Eliad Peller91b5ab62017-06-09 13:08:42 +01009430 return -EINVAL;
9431 settings->psk = nla_data(info->attrs[NL80211_ATTR_PMK]);
9432 }
9433
Chung-Hsien Hsu26f70442019-05-09 09:49:06 +00009434 if (info->attrs[NL80211_ATTR_SAE_PASSWORD]) {
9435 if (!wiphy_ext_feature_isset(&rdev->wiphy,
9436 NL80211_EXT_FEATURE_SAE_OFFLOAD))
9437 return -EINVAL;
9438 settings->sae_pwd =
9439 nla_data(info->attrs[NL80211_ATTR_SAE_PASSWORD]);
9440 settings->sae_pwd_len =
9441 nla_len(info->attrs[NL80211_ATTR_SAE_PASSWORD]);
9442 }
9443
Samuel Ortizb23aa672009-07-01 21:26:54 +02009444 return 0;
9445}
9446
Jouni Malinen636a5d32009-03-19 13:39:22 +02009447static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
9448{
Johannes Berg4c476992010-10-04 21:36:35 +02009449 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9450 struct net_device *dev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02009451 struct ieee80211_channel *chan;
Johannes Bergf62fab72013-02-21 20:09:09 +01009452 struct cfg80211_assoc_request req = {};
9453 const u8 *bssid, *ssid;
9454 int err, ssid_len = 0;
Thomas Pedersen942ba882020-04-30 10:25:51 -07009455 u32 freq;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009456
Andrew Zaborowskibad29292018-05-22 02:46:02 +02009457 if (dev->ieee80211_ptr->conn_owner_nlportid &&
9458 dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
9459 return -EPERM;
9460
Johannes Bergf4a11bb2009-03-27 12:40:28 +01009461 if (!info->attrs[NL80211_ATTR_MAC] ||
Johannes Berg19957bb2009-07-02 17:20:43 +02009462 !info->attrs[NL80211_ATTR_SSID] ||
9463 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
Johannes Bergf4a11bb2009-03-27 12:40:28 +01009464 return -EINVAL;
9465
Johannes Berg4c476992010-10-04 21:36:35 +02009466 if (!rdev->ops->assoc)
9467 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009468
Johannes Berg074ac8d2010-09-16 14:58:22 +02009469 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009470 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9471 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02009472
Johannes Berg19957bb2009-07-02 17:20:43 +02009473 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02009474
Thomas Pedersen942ba882020-04-30 10:25:51 -07009475 freq = MHZ_TO_KHZ(nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
9476 if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
9477 freq +=
9478 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
9479 chan = nl80211_get_valid_chan(&rdev->wiphy, freq);
Jouni Malinen664834d2014-01-15 00:01:44 +02009480 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02009481 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009482
Johannes Berg19957bb2009-07-02 17:20:43 +02009483 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9484 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02009485
9486 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01009487 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9488 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02009489 }
9490
Jouni Malinendc6382ce2009-05-06 22:09:37 +03009491 if (info->attrs[NL80211_ATTR_USE_MFP]) {
Johannes Berg4f5dadc2009-07-07 03:56:10 +02009492 enum nl80211_mfp mfp =
Jouni Malinendc6382ce2009-05-06 22:09:37 +03009493 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Johannes Berg4f5dadc2009-07-07 03:56:10 +02009494 if (mfp == NL80211_MFP_REQUIRED)
Johannes Bergf62fab72013-02-21 20:09:09 +01009495 req.use_mfp = true;
Johannes Berg4c476992010-10-04 21:36:35 +02009496 else if (mfp != NL80211_MFP_NO)
9497 return -EINVAL;
Jouni Malinendc6382ce2009-05-06 22:09:37 +03009498 }
9499
Johannes Berg3e5d7642009-07-07 14:37:26 +02009500 if (info->attrs[NL80211_ATTR_PREV_BSSID])
Johannes Bergf62fab72013-02-21 20:09:09 +01009501 req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
Johannes Berg3e5d7642009-07-07 14:37:26 +02009502
Ben Greear7e7c8922011-11-18 11:31:59 -08009503 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01009504 req.flags |= ASSOC_REQ_DISABLE_HT;
Ben Greear7e7c8922011-11-18 11:31:59 -08009505
9506 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01009507 memcpy(&req.ht_capa_mask,
9508 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
9509 sizeof(req.ht_capa_mask));
Ben Greear7e7c8922011-11-18 11:31:59 -08009510
9511 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01009512 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Ben Greear7e7c8922011-11-18 11:31:59 -08009513 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01009514 memcpy(&req.ht_capa,
9515 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
9516 sizeof(req.ht_capa));
Ben Greear7e7c8922011-11-18 11:31:59 -08009517 }
9518
Johannes Bergee2aca32013-02-21 17:36:01 +01009519 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01009520 req.flags |= ASSOC_REQ_DISABLE_VHT;
Johannes Bergee2aca32013-02-21 17:36:01 +01009521
9522 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01009523 memcpy(&req.vht_capa_mask,
9524 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
9525 sizeof(req.vht_capa_mask));
Johannes Bergee2aca32013-02-21 17:36:01 +01009526
9527 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01009528 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergee2aca32013-02-21 17:36:01 +01009529 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01009530 memcpy(&req.vht_capa,
9531 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
9532 sizeof(req.vht_capa));
Johannes Bergee2aca32013-02-21 17:36:01 +01009533 }
9534
Assaf Kraussbab5ab72014-09-03 15:25:01 +03009535 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02009536 if (!((rdev->wiphy.features &
9537 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
9538 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
9539 !wiphy_ext_feature_isset(&rdev->wiphy,
9540 NL80211_EXT_FEATURE_RRM))
Assaf Kraussbab5ab72014-09-03 15:25:01 +03009541 return -EINVAL;
9542 req.flags |= ASSOC_REQ_USE_RRM;
9543 }
9544
Jouni Malinen348bd452016-10-27 00:42:03 +03009545 if (info->attrs[NL80211_ATTR_FILS_KEK]) {
9546 req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
9547 req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
9548 if (!info->attrs[NL80211_ATTR_FILS_NONCES])
9549 return -EINVAL;
9550 req.fils_nonces =
9551 nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
9552 }
9553
Johannes Bergf62fab72013-02-21 20:09:09 +01009554 err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
Johannes Berg91bf9b22013-05-15 17:44:01 +02009555 if (!err) {
9556 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05009557
Johannes Bergf62fab72013-02-21 20:09:09 +01009558 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
9559 ssid, ssid_len, &req);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05009560
9561 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
9562 dev->ieee80211_ptr->conn_owner_nlportid =
9563 info->snd_portid;
9564 memcpy(dev->ieee80211_ptr->disconnect_bssid,
9565 bssid, ETH_ALEN);
9566 }
9567
Johannes Berg91bf9b22013-05-15 17:44:01 +02009568 wdev_unlock(dev->ieee80211_ptr);
9569 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02009570
Jouni Malinen636a5d32009-03-19 13:39:22 +02009571 return err;
9572}
9573
9574static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
9575{
Johannes Berg4c476992010-10-04 21:36:35 +02009576 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9577 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02009578 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02009579 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02009580 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03009581 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009582
Andrew Zaborowskibad29292018-05-22 02:46:02 +02009583 if (dev->ieee80211_ptr->conn_owner_nlportid &&
9584 dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
9585 return -EPERM;
9586
Johannes Bergf4a11bb2009-03-27 12:40:28 +01009587 if (!info->attrs[NL80211_ATTR_MAC])
9588 return -EINVAL;
9589
9590 if (!info->attrs[NL80211_ATTR_REASON_CODE])
9591 return -EINVAL;
9592
Johannes Berg4c476992010-10-04 21:36:35 +02009593 if (!rdev->ops->deauth)
9594 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009595
Johannes Berg074ac8d2010-09-16 14:58:22 +02009596 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009597 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9598 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02009599
Johannes Berg19957bb2009-07-02 17:20:43 +02009600 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02009601
Johannes Berg19957bb2009-07-02 17:20:43 +02009602 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
9603 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01009604 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02009605 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02009606 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02009607
9608 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02009609 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9610 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02009611 }
9612
Jouni Malinend5cdfac2010-04-04 09:37:19 +03009613 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
9614
Johannes Berg91bf9b22013-05-15 17:44:01 +02009615 wdev_lock(dev->ieee80211_ptr);
9616 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
9617 local_state_change);
9618 wdev_unlock(dev->ieee80211_ptr);
9619 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009620}
9621
9622static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
9623{
Johannes Berg4c476992010-10-04 21:36:35 +02009624 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9625 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02009626 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02009627 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02009628 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03009629 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009630
Andrew Zaborowskibad29292018-05-22 02:46:02 +02009631 if (dev->ieee80211_ptr->conn_owner_nlportid &&
9632 dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
9633 return -EPERM;
9634
Johannes Bergf4a11bb2009-03-27 12:40:28 +01009635 if (!info->attrs[NL80211_ATTR_MAC])
9636 return -EINVAL;
9637
9638 if (!info->attrs[NL80211_ATTR_REASON_CODE])
9639 return -EINVAL;
9640
Johannes Berg4c476992010-10-04 21:36:35 +02009641 if (!rdev->ops->disassoc)
9642 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009643
Johannes Berg074ac8d2010-09-16 14:58:22 +02009644 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009645 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9646 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02009647
Johannes Berg19957bb2009-07-02 17:20:43 +02009648 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02009649
Johannes Berg19957bb2009-07-02 17:20:43 +02009650 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
9651 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01009652 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02009653 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02009654 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02009655
9656 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02009657 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9658 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02009659 }
9660
Jouni Malinend5cdfac2010-04-04 09:37:19 +03009661 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
9662
Johannes Berg91bf9b22013-05-15 17:44:01 +02009663 wdev_lock(dev->ieee80211_ptr);
9664 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
9665 local_state_change);
9666 wdev_unlock(dev->ieee80211_ptr);
9667 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009668}
9669
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01009670static bool
9671nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
Johannes Berg57fbcce2016-04-12 15:56:15 +02009672 int mcast_rate[NUM_NL80211_BANDS],
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01009673 int rateval)
9674{
9675 struct wiphy *wiphy = &rdev->wiphy;
9676 bool found = false;
9677 int band, i;
9678
Johannes Berg57fbcce2016-04-12 15:56:15 +02009679 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01009680 struct ieee80211_supported_band *sband;
9681
9682 sband = wiphy->bands[band];
9683 if (!sband)
9684 continue;
9685
9686 for (i = 0; i < sband->n_bitrates; i++) {
9687 if (sband->bitrates[i].bitrate == rateval) {
9688 mcast_rate[band] = i + 1;
9689 found = true;
9690 break;
9691 }
9692 }
9693 }
9694
9695 return found;
9696}
9697
Johannes Berg04a773a2009-04-19 21:24:32 +02009698static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
9699{
Johannes Berg4c476992010-10-04 21:36:35 +02009700 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9701 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02009702 struct cfg80211_ibss_params ibss;
9703 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02009704 struct cfg80211_cached_keys *connkeys = NULL;
Johannes Berg04a773a2009-04-19 21:24:32 +02009705 int err;
9706
Johannes Berg8e30bc52009-04-22 17:45:38 +02009707 memset(&ibss, 0, sizeof(ibss));
9708
Johannes Berg683b6d32012-11-08 21:25:48 +01009709 if (!info->attrs[NL80211_ATTR_SSID] ||
Johannes Berg04a773a2009-04-19 21:24:32 +02009710 !nla_len(info->attrs[NL80211_ATTR_SSID]))
9711 return -EINVAL;
9712
Johannes Berg8e30bc52009-04-22 17:45:38 +02009713 ibss.beacon_interval = 100;
9714
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309715 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
Johannes Berg8e30bc52009-04-22 17:45:38 +02009716 ibss.beacon_interval =
9717 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309718
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05309719 err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
9720 ibss.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309721 if (err)
9722 return err;
Johannes Berg8e30bc52009-04-22 17:45:38 +02009723
Johannes Berg4c476992010-10-04 21:36:35 +02009724 if (!rdev->ops->join_ibss)
9725 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02009726
Johannes Berg4c476992010-10-04 21:36:35 +02009727 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
9728 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02009729
Johannes Berg79c97e92009-07-07 03:56:12 +02009730 wiphy = &rdev->wiphy;
Johannes Berg04a773a2009-04-19 21:24:32 +02009731
Johannes Berg39193492011-09-16 13:45:25 +02009732 if (info->attrs[NL80211_ATTR_MAC]) {
Johannes Berg04a773a2009-04-19 21:24:32 +02009733 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg39193492011-09-16 13:45:25 +02009734
9735 if (!is_valid_ether_addr(ibss.bssid))
9736 return -EINVAL;
9737 }
Johannes Berg04a773a2009-04-19 21:24:32 +02009738 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9739 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9740
9741 if (info->attrs[NL80211_ATTR_IE]) {
9742 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9743 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9744 }
9745
Johannes Berg683b6d32012-11-08 21:25:48 +01009746 err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
9747 if (err)
9748 return err;
Alexander Simon54858ee5b2011-11-30 16:56:32 +01009749
Ilan Peer174e0cd2014-02-23 09:13:01 +02009750 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
9751 NL80211_IFTYPE_ADHOC))
Alexander Simon54858ee5b2011-11-30 16:56:32 +01009752 return -EINVAL;
9753
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02009754 switch (ibss.chandef.width) {
Simon Wunderlichbf372642013-07-08 16:55:58 +02009755 case NL80211_CHAN_WIDTH_5:
9756 case NL80211_CHAN_WIDTH_10:
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02009757 case NL80211_CHAN_WIDTH_20_NOHT:
9758 break;
9759 case NL80211_CHAN_WIDTH_20:
9760 case NL80211_CHAN_WIDTH_40:
Janusz.Dziedzic@tieto.comffc11992015-02-21 16:52:39 +01009761 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
9762 return -EINVAL;
9763 break;
9764 case NL80211_CHAN_WIDTH_80:
9765 case NL80211_CHAN_WIDTH_80P80:
9766 case NL80211_CHAN_WIDTH_160:
9767 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
9768 return -EINVAL;
9769 if (!wiphy_ext_feature_isset(&rdev->wiphy,
9770 NL80211_EXT_FEATURE_VHT_IBSS))
9771 return -EINVAL;
9772 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02009773 default:
Johannes Bergdb9c64c2012-11-09 14:56:41 +01009774 return -EINVAL;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02009775 }
Johannes Bergdb9c64c2012-11-09 14:56:41 +01009776
Johannes Berg04a773a2009-04-19 21:24:32 +02009777 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
Johannes Bergfffd0932009-07-08 14:22:54 +02009778 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
Johannes Berg04a773a2009-04-19 21:24:32 +02009779
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03009780 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
9781 u8 *rates =
9782 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9783 int n_rates =
9784 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9785 struct ieee80211_supported_band *sband =
Johannes Berg683b6d32012-11-08 21:25:48 +01009786 wiphy->bands[ibss.chandef.chan->band];
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03009787
Johannes Berg34850ab2011-07-18 18:08:35 +02009788 err = ieee80211_get_ratemask(sband, rates, n_rates,
9789 &ibss.basic_rates);
9790 if (err)
9791 return err;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03009792 }
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01009793
Simon Wunderlich803768f2013-06-28 10:39:58 +02009794 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
9795 memcpy(&ibss.ht_capa_mask,
9796 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
9797 sizeof(ibss.ht_capa_mask));
9798
9799 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
9800 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
9801 return -EINVAL;
9802 memcpy(&ibss.ht_capa,
9803 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
9804 sizeof(ibss.ht_capa));
9805 }
9806
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01009807 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
9808 !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
9809 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
9810 return -EINVAL;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03009811
Johannes Berg4c476992010-10-04 21:36:35 +02009812 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Sujith Manoharande7044e2012-10-18 10:19:28 +05309813 bool no_ht = false;
9814
Johannes Berg768075e2017-11-13 15:35:06 +01009815 connkeys = nl80211_parse_connkeys(rdev, info, &no_ht);
Johannes Berg4c476992010-10-04 21:36:35 +02009816 if (IS_ERR(connkeys))
9817 return PTR_ERR(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05309818
Johannes Berg3d9d1d62012-11-08 23:14:50 +01009819 if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
9820 no_ht) {
Waiman Long453431a2020-08-06 23:18:13 -07009821 kfree_sensitive(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05309822 return -EINVAL;
9823 }
Johannes Berg4c476992010-10-04 21:36:35 +02009824 }
Johannes Berg04a773a2009-04-19 21:24:32 +02009825
Antonio Quartulli267335d2012-01-31 20:25:47 +01009826 ibss.control_port =
9827 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
9828
Denis Kenziorc3bfe1f2018-03-26 12:52:48 -05009829 if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
9830 int r = validate_pae_over_nl80211(rdev, info);
9831
Johannes Bergd350a0f2018-12-15 11:03:22 +02009832 if (r < 0) {
Waiman Long453431a2020-08-06 23:18:13 -07009833 kfree_sensitive(connkeys);
Denis Kenziorc3bfe1f2018-03-26 12:52:48 -05009834 return r;
Johannes Bergd350a0f2018-12-15 11:03:22 +02009835 }
Denis Kenziorc3bfe1f2018-03-26 12:52:48 -05009836
9837 ibss.control_port_over_nl80211 = true;
9838 }
9839
Simon Wunderlich5336fa82013-10-07 18:41:05 +02009840 ibss.userspace_handles_dfs =
9841 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
9842
Denis Kenziorf8d16d32018-03-26 12:52:45 -05009843 wdev_lock(dev->ieee80211_ptr);
9844 err = __cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02009845 if (err)
Waiman Long453431a2020-08-06 23:18:13 -07009846 kfree_sensitive(connkeys);
Denis Kenziorf8d16d32018-03-26 12:52:45 -05009847 else if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
9848 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
9849 wdev_unlock(dev->ieee80211_ptr);
9850
Johannes Berg04a773a2009-04-19 21:24:32 +02009851 return err;
9852}
9853
9854static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
9855{
Johannes Berg4c476992010-10-04 21:36:35 +02009856 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9857 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02009858
Johannes Berg4c476992010-10-04 21:36:35 +02009859 if (!rdev->ops->leave_ibss)
9860 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02009861
Johannes Berg4c476992010-10-04 21:36:35 +02009862 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
9863 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02009864
Johannes Berg4c476992010-10-04 21:36:35 +02009865 return cfg80211_leave_ibss(rdev, dev, false);
Johannes Berg04a773a2009-04-19 21:24:32 +02009866}
9867
Antonio Quartullif4e583c2012-11-02 13:27:48 +01009868static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
9869{
9870 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9871 struct net_device *dev = info->user_ptr[1];
Johannes Berg57fbcce2016-04-12 15:56:15 +02009872 int mcast_rate[NUM_NL80211_BANDS];
Antonio Quartullif4e583c2012-11-02 13:27:48 +01009873 u32 nla_rate;
9874 int err;
9875
9876 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
Bertold Van den Bergh876dc932015-08-05 16:02:21 +02009877 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
9878 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
Antonio Quartullif4e583c2012-11-02 13:27:48 +01009879 return -EOPNOTSUPP;
9880
9881 if (!rdev->ops->set_mcast_rate)
9882 return -EOPNOTSUPP;
9883
9884 memset(mcast_rate, 0, sizeof(mcast_rate));
9885
9886 if (!info->attrs[NL80211_ATTR_MCAST_RATE])
9887 return -EINVAL;
9888
9889 nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
9890 if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
9891 return -EINVAL;
9892
Ilan Peera1056b1b2015-10-22 22:27:46 +03009893 err = rdev_set_mcast_rate(rdev, dev, mcast_rate);
Antonio Quartullif4e583c2012-11-02 13:27:48 +01009894
9895 return err;
9896}
9897
Johannes Bergad7e7182013-11-13 13:37:47 +01009898static struct sk_buff *
9899__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02009900 struct wireless_dev *wdev, int approxlen,
9901 u32 portid, u32 seq, enum nl80211_commands cmd,
Johannes Berg567ffc32013-12-18 14:43:31 +01009902 enum nl80211_attrs attr,
9903 const struct nl80211_vendor_cmd_info *info,
9904 gfp_t gfp)
Johannes Bergad7e7182013-11-13 13:37:47 +01009905{
9906 struct sk_buff *skb;
9907 void *hdr;
9908 struct nlattr *data;
9909
9910 skb = nlmsg_new(approxlen + 100, gfp);
9911 if (!skb)
9912 return NULL;
9913
9914 hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
9915 if (!hdr) {
9916 kfree_skb(skb);
9917 return NULL;
9918 }
9919
9920 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
9921 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01009922
9923 if (info) {
9924 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
9925 info->vendor_id))
9926 goto nla_put_failure;
9927 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
9928 info->subcmd))
9929 goto nla_put_failure;
9930 }
9931
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02009932 if (wdev) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009933 if (nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
9934 wdev_id(wdev), NL80211_ATTR_PAD))
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02009935 goto nla_put_failure;
9936 if (wdev->netdev &&
9937 nla_put_u32(skb, NL80211_ATTR_IFINDEX,
9938 wdev->netdev->ifindex))
9939 goto nla_put_failure;
9940 }
9941
Michal Kubecekae0be8d2019-04-26 11:13:06 +02009942 data = nla_nest_start_noflag(skb, attr);
Johannes Berg76e1fb42016-09-14 09:55:57 +02009943 if (!data)
9944 goto nla_put_failure;
Johannes Bergad7e7182013-11-13 13:37:47 +01009945
9946 ((void **)skb->cb)[0] = rdev;
9947 ((void **)skb->cb)[1] = hdr;
9948 ((void **)skb->cb)[2] = data;
9949
9950 return skb;
9951
9952 nla_put_failure:
9953 kfree_skb(skb);
9954 return NULL;
9955}
Antonio Quartullif4e583c2012-11-02 13:27:48 +01009956
Johannes Berge03ad6e2014-01-01 17:22:30 +01009957struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02009958 struct wireless_dev *wdev,
Johannes Berge03ad6e2014-01-01 17:22:30 +01009959 enum nl80211_commands cmd,
9960 enum nl80211_attrs attr,
Johannes Berg55c1fdf2019-02-06 13:17:19 +02009961 unsigned int portid,
Johannes Berge03ad6e2014-01-01 17:22:30 +01009962 int vendor_event_idx,
9963 int approxlen, gfp_t gfp)
9964{
Zhao, Gangf26cbf42014-04-21 12:53:03 +08009965 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berge03ad6e2014-01-01 17:22:30 +01009966 const struct nl80211_vendor_cmd_info *info;
9967
9968 switch (cmd) {
9969 case NL80211_CMD_TESTMODE:
9970 if (WARN_ON(vendor_event_idx != -1))
9971 return NULL;
9972 info = NULL;
9973 break;
9974 case NL80211_CMD_VENDOR:
9975 if (WARN_ON(vendor_event_idx < 0 ||
9976 vendor_event_idx >= wiphy->n_vendor_events))
9977 return NULL;
9978 info = &wiphy->vendor_events[vendor_event_idx];
9979 break;
9980 default:
9981 WARN_ON(1);
9982 return NULL;
9983 }
9984
Johannes Berg55c1fdf2019-02-06 13:17:19 +02009985 return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, portid, 0,
Johannes Berge03ad6e2014-01-01 17:22:30 +01009986 cmd, attr, info, gfp);
9987}
9988EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
9989
9990void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
9991{
9992 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
9993 void *hdr = ((void **)skb->cb)[1];
Johannes Berg55c1fdf2019-02-06 13:17:19 +02009994 struct nlmsghdr *nlhdr = nlmsg_hdr(skb);
Johannes Berge03ad6e2014-01-01 17:22:30 +01009995 struct nlattr *data = ((void **)skb->cb)[2];
9996 enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
9997
Johannes Bergbd8c78e2014-07-30 14:55:26 +02009998 /* clear CB data for netlink core to own from now on */
9999 memset(skb->cb, 0, sizeof(skb->cb));
10000
Johannes Berge03ad6e2014-01-01 17:22:30 +010010001 nla_nest_end(skb, data);
10002 genlmsg_end(skb, hdr);
10003
Johannes Berg55c1fdf2019-02-06 13:17:19 +020010004 if (nlhdr->nlmsg_pid) {
10005 genlmsg_unicast(wiphy_net(&rdev->wiphy), skb,
10006 nlhdr->nlmsg_pid);
10007 } else {
10008 if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
10009 mcgrp = NL80211_MCGRP_VENDOR;
Johannes Berge03ad6e2014-01-01 17:22:30 +010010010
Johannes Berg55c1fdf2019-02-06 13:17:19 +020010011 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
10012 skb, 0, mcgrp, gfp);
10013 }
Johannes Berge03ad6e2014-01-01 17:22:30 +010010014}
10015EXPORT_SYMBOL(__cfg80211_send_event_skb);
10016
Johannes Bergaff89a92009-07-01 21:26:51 +020010017#ifdef CONFIG_NL80211_TESTMODE
Johannes Bergaff89a92009-07-01 21:26:51 +020010018static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
10019{
Johannes Berg4c476992010-10-04 21:36:35 +020010020 struct cfg80211_registered_device *rdev = info->user_ptr[0];
David Spinadelfc73f112013-07-31 18:04:15 +030010021 struct wireless_dev *wdev =
10022 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
Johannes Bergaff89a92009-07-01 21:26:51 +020010023 int err;
10024
David Spinadelfc73f112013-07-31 18:04:15 +030010025 if (!rdev->ops->testmode_cmd)
10026 return -EOPNOTSUPP;
10027
10028 if (IS_ERR(wdev)) {
10029 err = PTR_ERR(wdev);
10030 if (err != -EINVAL)
10031 return err;
10032 wdev = NULL;
10033 } else if (wdev->wiphy != &rdev->wiphy) {
10034 return -EINVAL;
10035 }
10036
Johannes Bergaff89a92009-07-01 21:26:51 +020010037 if (!info->attrs[NL80211_ATTR_TESTDATA])
10038 return -EINVAL;
10039
Johannes Bergad7e7182013-11-13 13:37:47 +010010040 rdev->cur_cmd_info = info;
David Spinadelfc73f112013-07-31 18:04:15 +030010041 err = rdev_testmode_cmd(rdev, wdev,
Johannes Bergaff89a92009-07-01 21:26:51 +020010042 nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
10043 nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
Johannes Bergad7e7182013-11-13 13:37:47 +010010044 rdev->cur_cmd_info = NULL;
Johannes Bergaff89a92009-07-01 21:26:51 +020010045
Johannes Bergaff89a92009-07-01 21:26:51 +020010046 return err;
10047}
10048
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010049static int nl80211_testmode_dump(struct sk_buff *skb,
10050 struct netlink_callback *cb)
10051{
Johannes Berg00918d32011-12-13 17:22:05 +010010052 struct cfg80211_registered_device *rdev;
Johannes Berg50508d92019-07-29 16:31:09 +020010053 struct nlattr **attrbuf = NULL;
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010054 int err;
10055 long phy_idx;
10056 void *data = NULL;
10057 int data_len = 0;
10058
Johannes Berg5fe231e2013-05-08 21:45:15 +020010059 rtnl_lock();
10060
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010061 if (cb->args[0]) {
10062 /*
10063 * 0 is a valid index, but not valid for args[0],
10064 * so we need to offset by 1.
10065 */
10066 phy_idx = cb->args[0] - 1;
Luca Coelhoa4956dc2017-02-07 22:13:56 +020010067
10068 rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
10069 if (!rdev) {
10070 err = -ENOENT;
10071 goto out_err;
10072 }
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010073 } else {
Johannes Berg50508d92019-07-29 16:31:09 +020010074 attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
10075 GFP_KERNEL);
10076 if (!attrbuf) {
10077 err = -ENOMEM;
10078 goto out_err;
10079 }
Johannes Bergc90c39d2016-10-24 14:40:01 +020010080
Johannes Berg8cb08172019-04-26 14:07:28 +020010081 err = nlmsg_parse_deprecated(cb->nlh,
10082 GENL_HDRLEN + nl80211_fam.hdrsize,
10083 attrbuf, nl80211_fam.maxattr,
10084 nl80211_policy, NULL);
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010085 if (err)
Johannes Berg5fe231e2013-05-08 21:45:15 +020010086 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +010010087
Johannes Bergc90c39d2016-10-24 14:40:01 +020010088 rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg2bd7e352012-06-15 14:23:16 +020010089 if (IS_ERR(rdev)) {
Johannes Berg5fe231e2013-05-08 21:45:15 +020010090 err = PTR_ERR(rdev);
10091 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +010010092 }
Johannes Berg2bd7e352012-06-15 14:23:16 +020010093 phy_idx = rdev->wiphy_idx;
Johannes Berg2bd7e352012-06-15 14:23:16 +020010094
Johannes Bergc90c39d2016-10-24 14:40:01 +020010095 if (attrbuf[NL80211_ATTR_TESTDATA])
10096 cb->args[1] = (long)attrbuf[NL80211_ATTR_TESTDATA];
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010097 }
10098
10099 if (cb->args[1]) {
10100 data = nla_data((void *)cb->args[1]);
10101 data_len = nla_len((void *)cb->args[1]);
10102 }
10103
Johannes Berg00918d32011-12-13 17:22:05 +010010104 if (!rdev->ops->testmode_dump) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010105 err = -EOPNOTSUPP;
10106 goto out_err;
10107 }
10108
10109 while (1) {
Eric W. Biederman15e47302012-09-07 20:12:54 +000010110 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010111 cb->nlh->nlmsg_seq, NLM_F_MULTI,
10112 NL80211_CMD_TESTMODE);
10113 struct nlattr *tmdata;
10114
Dan Carpentercb35fba2013-08-14 14:50:01 +030010115 if (!hdr)
10116 break;
10117
David S. Miller9360ffd2012-03-29 04:41:26 -040010118 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010119 genlmsg_cancel(skb, hdr);
10120 break;
10121 }
10122
Michal Kubecekae0be8d2019-04-26 11:13:06 +020010123 tmdata = nla_nest_start_noflag(skb, NL80211_ATTR_TESTDATA);
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010124 if (!tmdata) {
10125 genlmsg_cancel(skb, hdr);
10126 break;
10127 }
Hila Gonene35e4d22012-06-27 17:19:42 +030010128 err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010129 nla_nest_end(skb, tmdata);
10130
10131 if (err == -ENOBUFS || err == -ENOENT) {
10132 genlmsg_cancel(skb, hdr);
10133 break;
10134 } else if (err) {
10135 genlmsg_cancel(skb, hdr);
10136 goto out_err;
10137 }
10138
10139 genlmsg_end(skb, hdr);
10140 }
10141
10142 err = skb->len;
10143 /* see above */
10144 cb->args[0] = phy_idx + 1;
10145 out_err:
Johannes Berg50508d92019-07-29 16:31:09 +020010146 kfree(attrbuf);
Johannes Berg5fe231e2013-05-08 21:45:15 +020010147 rtnl_unlock();
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010148 return err;
10149}
Johannes Bergaff89a92009-07-01 21:26:51 +020010150#endif
10151
Samuel Ortizb23aa672009-07-01 21:26:54 +020010152static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
10153{
Johannes Berg4c476992010-10-04 21:36:35 +020010154 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10155 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +020010156 struct cfg80211_connect_params connect;
10157 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +020010158 struct cfg80211_cached_keys *connkeys = NULL;
Thomas Pedersen942ba882020-04-30 10:25:51 -070010159 u32 freq = 0;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010160 int err;
10161
10162 memset(&connect, 0, sizeof(connect));
10163
Samuel Ortizb23aa672009-07-01 21:26:54 +020010164 if (!info->attrs[NL80211_ATTR_SSID] ||
10165 !nla_len(info->attrs[NL80211_ATTR_SSID]))
10166 return -EINVAL;
10167
10168 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
10169 connect.auth_type =
10170 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +030010171 if (!nl80211_valid_auth_type(rdev, connect.auth_type,
10172 NL80211_CMD_CONNECT))
Samuel Ortizb23aa672009-07-01 21:26:54 +020010173 return -EINVAL;
10174 } else
10175 connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
10176
10177 connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
10178
Avraham Stern3a00df52017-06-09 13:08:43 +010010179 if (info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS] &&
10180 !wiphy_ext_feature_isset(&rdev->wiphy,
10181 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
10182 return -EINVAL;
10183 connect.want_1x = info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS];
10184
Johannes Bergc0692b82010-08-27 14:26:53 +030010185 err = nl80211_crypto_settings(rdev, info, &connect.crypto,
Johannes Berg3dc27d22009-07-02 21:36:37 +020010186 NL80211_MAX_NR_CIPHER_SUITES);
Samuel Ortizb23aa672009-07-01 21:26:54 +020010187 if (err)
10188 return err;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010189
Johannes Berg074ac8d2010-09-16 14:58:22 +020010190 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020010191 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
10192 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010193
Johannes Berg79c97e92009-07-07 03:56:12 +020010194 wiphy = &rdev->wiphy;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010195
Bala Shanmugam4486ea92012-03-07 17:27:12 +053010196 connect.bg_scan_period = -1;
10197 if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
10198 (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
10199 connect.bg_scan_period =
10200 nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
10201 }
10202
Samuel Ortizb23aa672009-07-01 21:26:54 +020010203 if (info->attrs[NL80211_ATTR_MAC])
10204 connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen1df4a512014-01-15 00:00:47 +020010205 else if (info->attrs[NL80211_ATTR_MAC_HINT])
10206 connect.bssid_hint =
10207 nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
Samuel Ortizb23aa672009-07-01 21:26:54 +020010208 connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
10209 connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
10210
10211 if (info->attrs[NL80211_ATTR_IE]) {
10212 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
10213 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
10214 }
10215
Jouni Malinencee00a92013-01-15 17:15:57 +020010216 if (info->attrs[NL80211_ATTR_USE_MFP]) {
10217 connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Emmanuel Grumbach65026002017-08-18 15:31:41 +030010218 if (connect.mfp == NL80211_MFP_OPTIONAL &&
10219 !wiphy_ext_feature_isset(&rdev->wiphy,
10220 NL80211_EXT_FEATURE_MFP_OPTIONAL))
10221 return -EOPNOTSUPP;
Jouni Malinencee00a92013-01-15 17:15:57 +020010222 } else {
10223 connect.mfp = NL80211_MFP_NO;
10224 }
10225
Jouni Malinenba6fbac2016-03-29 13:53:27 +030010226 if (info->attrs[NL80211_ATTR_PREV_BSSID])
10227 connect.prev_bssid =
10228 nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
10229
Thomas Pedersen942ba882020-04-30 10:25:51 -070010230 if (info->attrs[NL80211_ATTR_WIPHY_FREQ])
10231 freq = MHZ_TO_KHZ(nla_get_u32(
10232 info->attrs[NL80211_ATTR_WIPHY_FREQ]));
10233 if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
10234 freq +=
10235 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
10236
10237 if (freq) {
10238 connect.channel = nl80211_get_valid_chan(wiphy, freq);
Jouni Malinen664834d2014-01-15 00:01:44 +020010239 if (!connect.channel)
Johannes Berg4c476992010-10-04 21:36:35 +020010240 return -EINVAL;
Jouni Malinen1df4a512014-01-15 00:00:47 +020010241 } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
Thomas Pedersen942ba882020-04-30 10:25:51 -070010242 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
10243 freq = MHZ_TO_KHZ(freq);
10244 connect.channel_hint = nl80211_get_valid_chan(wiphy, freq);
Jouni Malinen664834d2014-01-15 00:01:44 +020010245 if (!connect.channel_hint)
Jouni Malinen1df4a512014-01-15 00:00:47 +020010246 return -EINVAL;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010247 }
10248
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030010249 if (info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]) {
10250 connect.edmg.channels =
10251 nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]);
10252
10253 if (info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG])
10254 connect.edmg.bw_config =
10255 nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG]);
10256 }
10257
Johannes Bergfffd0932009-07-08 14:22:54 +020010258 if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Johannes Berg768075e2017-11-13 15:35:06 +010010259 connkeys = nl80211_parse_connkeys(rdev, info, NULL);
Johannes Berg4c476992010-10-04 21:36:35 +020010260 if (IS_ERR(connkeys))
10261 return PTR_ERR(connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +020010262 }
10263
Ben Greear7e7c8922011-11-18 11:31:59 -080010264 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
10265 connect.flags |= ASSOC_REQ_DISABLE_HT;
10266
10267 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
10268 memcpy(&connect.ht_capa_mask,
10269 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
10270 sizeof(connect.ht_capa_mask));
10271
10272 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Wei Yongjunb4e4f472012-09-02 21:41:04 +080010273 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
Waiman Long453431a2020-08-06 23:18:13 -070010274 kfree_sensitive(connkeys);
Ben Greear7e7c8922011-11-18 11:31:59 -080010275 return -EINVAL;
Wei Yongjunb4e4f472012-09-02 21:41:04 +080010276 }
Ben Greear7e7c8922011-11-18 11:31:59 -080010277 memcpy(&connect.ht_capa,
10278 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
10279 sizeof(connect.ht_capa));
10280 }
10281
Johannes Bergee2aca32013-02-21 17:36:01 +010010282 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
10283 connect.flags |= ASSOC_REQ_DISABLE_VHT;
10284
10285 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
10286 memcpy(&connect.vht_capa_mask,
10287 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
10288 sizeof(connect.vht_capa_mask));
10289
10290 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
10291 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
Waiman Long453431a2020-08-06 23:18:13 -070010292 kfree_sensitive(connkeys);
Johannes Bergee2aca32013-02-21 17:36:01 +010010293 return -EINVAL;
10294 }
10295 memcpy(&connect.vht_capa,
10296 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
10297 sizeof(connect.vht_capa));
10298 }
10299
Assaf Kraussbab5ab72014-09-03 15:25:01 +030010300 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +020010301 if (!((rdev->wiphy.features &
10302 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
10303 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
10304 !wiphy_ext_feature_isset(&rdev->wiphy,
10305 NL80211_EXT_FEATURE_RRM)) {
Waiman Long453431a2020-08-06 23:18:13 -070010306 kfree_sensitive(connkeys);
Assaf Kraussbab5ab72014-09-03 15:25:01 +030010307 return -EINVAL;
Ola Olsson707554b2015-12-11 21:04:52 +010010308 }
Assaf Kraussbab5ab72014-09-03 15:25:01 +030010309 connect.flags |= ASSOC_REQ_USE_RRM;
10310 }
10311
Lior David34d50512016-01-28 10:58:25 +020010312 connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
Johannes Berg57fbcce2016-04-12 15:56:15 +020010313 if (connect.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
Waiman Long453431a2020-08-06 23:18:13 -070010314 kfree_sensitive(connkeys);
Lior David34d50512016-01-28 10:58:25 +020010315 return -EOPNOTSUPP;
10316 }
10317
Arend van Spriel38de03d2016-03-02 20:37:18 +010010318 if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
10319 /* bss selection makes no sense if bssid is set */
10320 if (connect.bssid) {
Waiman Long453431a2020-08-06 23:18:13 -070010321 kfree_sensitive(connkeys);
Arend van Spriel38de03d2016-03-02 20:37:18 +010010322 return -EINVAL;
10323 }
10324
10325 err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
10326 wiphy, &connect.bss_select);
10327 if (err) {
Waiman Long453431a2020-08-06 23:18:13 -070010328 kfree_sensitive(connkeys);
Arend van Spriel38de03d2016-03-02 20:37:18 +010010329 return err;
10330 }
10331 }
10332
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030010333 if (wiphy_ext_feature_isset(&rdev->wiphy,
10334 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
10335 info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
10336 info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
10337 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
10338 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
10339 connect.fils_erp_username =
10340 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
10341 connect.fils_erp_username_len =
10342 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
10343 connect.fils_erp_realm =
10344 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
10345 connect.fils_erp_realm_len =
10346 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
10347 connect.fils_erp_next_seq_num =
10348 nla_get_u16(
10349 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
10350 connect.fils_erp_rrk =
10351 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
10352 connect.fils_erp_rrk_len =
10353 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
10354 } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
10355 info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
10356 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
10357 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
Waiman Long453431a2020-08-06 23:18:13 -070010358 kfree_sensitive(connkeys);
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030010359 return -EINVAL;
10360 }
10361
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020010362 if (nla_get_flag(info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])) {
10363 if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
Waiman Long453431a2020-08-06 23:18:13 -070010364 kfree_sensitive(connkeys);
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020010365 GENL_SET_ERR_MSG(info,
10366 "external auth requires connection ownership");
10367 return -EINVAL;
10368 }
10369 connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT;
10370 }
10371
Johannes Berg83739b02013-05-15 17:44:01 +020010372 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050010373
Jouni Malinen4ce2bd92016-03-29 13:53:28 +030010374 err = cfg80211_connect(rdev, dev, &connect, connkeys,
10375 connect.prev_bssid);
Johannes Bergfffd0932009-07-08 14:22:54 +020010376 if (err)
Waiman Long453431a2020-08-06 23:18:13 -070010377 kfree_sensitive(connkeys);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050010378
10379 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
10380 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
10381 if (connect.bssid)
10382 memcpy(dev->ieee80211_ptr->disconnect_bssid,
10383 connect.bssid, ETH_ALEN);
10384 else
Miaohe Lin3b1648f2020-08-01 17:15:49 +080010385 eth_zero_addr(dev->ieee80211_ptr->disconnect_bssid);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050010386 }
10387
10388 wdev_unlock(dev->ieee80211_ptr);
10389
Samuel Ortizb23aa672009-07-01 21:26:54 +020010390 return err;
10391}
10392
vamsi krishna088e8df2016-10-27 16:51:11 +030010393static int nl80211_update_connect_params(struct sk_buff *skb,
10394 struct genl_info *info)
10395{
10396 struct cfg80211_connect_params connect = {};
10397 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10398 struct net_device *dev = info->user_ptr[1];
10399 struct wireless_dev *wdev = dev->ieee80211_ptr;
Vidyullatha Kanchanapally7f9a3e12018-05-22 10:19:08 +020010400 bool fils_sk_offload;
10401 u32 auth_type;
vamsi krishna088e8df2016-10-27 16:51:11 +030010402 u32 changed = 0;
10403 int ret;
10404
10405 if (!rdev->ops->update_connect_params)
10406 return -EOPNOTSUPP;
10407
10408 if (info->attrs[NL80211_ATTR_IE]) {
vamsi krishna088e8df2016-10-27 16:51:11 +030010409 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
10410 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
10411 changed |= UPDATE_ASSOC_IES;
10412 }
10413
Vidyullatha Kanchanapally7f9a3e12018-05-22 10:19:08 +020010414 fils_sk_offload = wiphy_ext_feature_isset(&rdev->wiphy,
10415 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
10416
10417 /*
10418 * when driver supports fils-sk offload all attributes must be
10419 * provided. So the else covers "fils-sk-not-all" and
10420 * "no-fils-sk-any".
10421 */
10422 if (fils_sk_offload &&
10423 info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
10424 info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
10425 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
10426 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
10427 connect.fils_erp_username =
10428 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
10429 connect.fils_erp_username_len =
10430 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
10431 connect.fils_erp_realm =
10432 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
10433 connect.fils_erp_realm_len =
10434 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
10435 connect.fils_erp_next_seq_num =
10436 nla_get_u16(
10437 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
10438 connect.fils_erp_rrk =
10439 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
10440 connect.fils_erp_rrk_len =
10441 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
10442 changed |= UPDATE_FILS_ERP_INFO;
10443 } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
10444 info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
10445 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
10446 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
10447 return -EINVAL;
10448 }
10449
10450 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
10451 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
10452 if (!nl80211_valid_auth_type(rdev, auth_type,
10453 NL80211_CMD_CONNECT))
10454 return -EINVAL;
10455
10456 if (auth_type == NL80211_AUTHTYPE_FILS_SK &&
10457 fils_sk_offload && !(changed & UPDATE_FILS_ERP_INFO))
10458 return -EINVAL;
10459
10460 connect.auth_type = auth_type;
10461 changed |= UPDATE_AUTH_TYPE;
10462 }
10463
vamsi krishna088e8df2016-10-27 16:51:11 +030010464 wdev_lock(dev->ieee80211_ptr);
10465 if (!wdev->current_bss)
10466 ret = -ENOLINK;
10467 else
10468 ret = rdev_update_connect_params(rdev, dev, &connect, changed);
10469 wdev_unlock(dev->ieee80211_ptr);
10470
10471 return ret;
10472}
10473
Samuel Ortizb23aa672009-07-01 21:26:54 +020010474static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
10475{
Johannes Berg4c476992010-10-04 21:36:35 +020010476 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10477 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +020010478 u16 reason;
Johannes Berg83739b02013-05-15 17:44:01 +020010479 int ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010480
Andrew Zaborowskibad29292018-05-22 02:46:02 +020010481 if (dev->ieee80211_ptr->conn_owner_nlportid &&
10482 dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
10483 return -EPERM;
10484
Samuel Ortizb23aa672009-07-01 21:26:54 +020010485 if (!info->attrs[NL80211_ATTR_REASON_CODE])
10486 reason = WLAN_REASON_DEAUTH_LEAVING;
10487 else
10488 reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
10489
10490 if (reason == 0)
10491 return -EINVAL;
10492
Johannes Berg074ac8d2010-09-16 14:58:22 +020010493 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020010494 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
10495 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010496
Johannes Berg83739b02013-05-15 17:44:01 +020010497 wdev_lock(dev->ieee80211_ptr);
10498 ret = cfg80211_disconnect(rdev, dev, reason, true);
10499 wdev_unlock(dev->ieee80211_ptr);
10500 return ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010501}
10502
Johannes Berg463d0182009-07-14 00:33:35 +020010503static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
10504{
Johannes Berg4c476992010-10-04 21:36:35 +020010505 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg463d0182009-07-14 00:33:35 +020010506 struct net *net;
10507 int err;
Johannes Berg463d0182009-07-14 00:33:35 +020010508
Vadim Kochan4b681c82015-01-12 16:34:05 +020010509 if (info->attrs[NL80211_ATTR_PID]) {
10510 u32 pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
10511
10512 net = get_net_ns_by_pid(pid);
10513 } else if (info->attrs[NL80211_ATTR_NETNS_FD]) {
10514 u32 fd = nla_get_u32(info->attrs[NL80211_ATTR_NETNS_FD]);
10515
10516 net = get_net_ns_by_fd(fd);
10517 } else {
Johannes Berg463d0182009-07-14 00:33:35 +020010518 return -EINVAL;
Vadim Kochan4b681c82015-01-12 16:34:05 +020010519 }
Johannes Berg463d0182009-07-14 00:33:35 +020010520
Johannes Berg4c476992010-10-04 21:36:35 +020010521 if (IS_ERR(net))
10522 return PTR_ERR(net);
Johannes Berg463d0182009-07-14 00:33:35 +020010523
10524 err = 0;
10525
10526 /* check if anything to do */
Johannes Berg4c476992010-10-04 21:36:35 +020010527 if (!net_eq(wiphy_net(&rdev->wiphy), net))
10528 err = cfg80211_switch_netns(rdev, net);
Johannes Berg463d0182009-07-14 00:33:35 +020010529
Johannes Berg463d0182009-07-14 00:33:35 +020010530 put_net(net);
Johannes Berg463d0182009-07-14 00:33:35 +020010531 return err;
10532}
10533
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010534static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
10535{
Johannes Berg4c476992010-10-04 21:36:35 +020010536 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010537 int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
10538 struct cfg80211_pmksa *pmksa) = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +020010539 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010540 struct cfg80211_pmksa pmksa;
10541
10542 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
10543
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010544 if (!info->attrs[NL80211_ATTR_PMKID])
10545 return -EINVAL;
10546
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010547 pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030010548
10549 if (info->attrs[NL80211_ATTR_MAC]) {
10550 pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
10551 } else if (info->attrs[NL80211_ATTR_SSID] &&
10552 info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
10553 (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
10554 info->attrs[NL80211_ATTR_PMK])) {
10555 pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
10556 pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
10557 pmksa.cache_id =
10558 nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
10559 } else {
10560 return -EINVAL;
10561 }
10562 if (info->attrs[NL80211_ATTR_PMK]) {
10563 pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
10564 pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
10565 }
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010566
Veerendranath Jakkam7fc82af2020-03-13 01:59:03 +020010567 if (info->attrs[NL80211_ATTR_PMK_LIFETIME])
10568 pmksa.pmk_lifetime =
10569 nla_get_u32(info->attrs[NL80211_ATTR_PMK_LIFETIME]);
10570
10571 if (info->attrs[NL80211_ATTR_PMK_REAUTH_THRESHOLD])
10572 pmksa.pmk_reauth_threshold =
10573 nla_get_u8(
10574 info->attrs[NL80211_ATTR_PMK_REAUTH_THRESHOLD]);
10575
Johannes Berg074ac8d2010-09-16 14:58:22 +020010576 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Liangwei Dong6c900362019-01-18 16:54:38 +053010577 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
10578 !(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP &&
10579 wiphy_ext_feature_isset(&rdev->wiphy,
10580 NL80211_EXT_FEATURE_AP_PMKSA_CACHING)))
Johannes Berg4c476992010-10-04 21:36:35 +020010581 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010582
10583 switch (info->genlhdr->cmd) {
10584 case NL80211_CMD_SET_PMKSA:
10585 rdev_ops = rdev->ops->set_pmksa;
10586 break;
10587 case NL80211_CMD_DEL_PMKSA:
10588 rdev_ops = rdev->ops->del_pmksa;
10589 break;
10590 default:
10591 WARN_ON(1);
10592 break;
10593 }
10594
Johannes Berg4c476992010-10-04 21:36:35 +020010595 if (!rdev_ops)
10596 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010597
Johannes Berg4c476992010-10-04 21:36:35 +020010598 return rdev_ops(&rdev->wiphy, dev, &pmksa);
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010599}
10600
10601static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
10602{
Johannes Berg4c476992010-10-04 21:36:35 +020010603 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10604 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010605
Johannes Berg074ac8d2010-09-16 14:58:22 +020010606 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020010607 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
10608 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010609
Johannes Berg4c476992010-10-04 21:36:35 +020010610 if (!rdev->ops->flush_pmksa)
10611 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010612
Hila Gonene35e4d22012-06-27 17:19:42 +030010613 return rdev_flush_pmksa(rdev, dev);
Samuel Ortiz67fbb162009-11-24 23:59:15 +010010614}
10615
Arik Nemtsov109086c2011-09-28 14:12:50 +030010616static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
10617{
10618 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10619 struct net_device *dev = info->user_ptr[1];
10620 u8 action_code, dialog_token;
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +053010621 u32 peer_capability = 0;
Arik Nemtsov109086c2011-09-28 14:12:50 +030010622 u16 status_code;
10623 u8 *peer;
Arik Nemtsov31fa97c2014-06-11 17:18:21 +030010624 bool initiator;
Arik Nemtsov109086c2011-09-28 14:12:50 +030010625
10626 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
10627 !rdev->ops->tdls_mgmt)
10628 return -EOPNOTSUPP;
10629
10630 if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
10631 !info->attrs[NL80211_ATTR_STATUS_CODE] ||
10632 !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
10633 !info->attrs[NL80211_ATTR_IE] ||
10634 !info->attrs[NL80211_ATTR_MAC])
10635 return -EINVAL;
10636
10637 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
10638 action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
10639 status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
10640 dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
Arik Nemtsov31fa97c2014-06-11 17:18:21 +030010641 initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]);
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +053010642 if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
10643 peer_capability =
10644 nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
Arik Nemtsov109086c2011-09-28 14:12:50 +030010645
Hila Gonene35e4d22012-06-27 17:19:42 +030010646 return rdev_tdls_mgmt(rdev, dev, peer, action_code,
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +053010647 dialog_token, status_code, peer_capability,
Arik Nemtsov31fa97c2014-06-11 17:18:21 +030010648 initiator,
Hila Gonene35e4d22012-06-27 17:19:42 +030010649 nla_data(info->attrs[NL80211_ATTR_IE]),
10650 nla_len(info->attrs[NL80211_ATTR_IE]));
Arik Nemtsov109086c2011-09-28 14:12:50 +030010651}
10652
10653static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
10654{
10655 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10656 struct net_device *dev = info->user_ptr[1];
10657 enum nl80211_tdls_operation operation;
10658 u8 *peer;
10659
10660 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
10661 !rdev->ops->tdls_oper)
10662 return -EOPNOTSUPP;
10663
10664 if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
10665 !info->attrs[NL80211_ATTR_MAC])
10666 return -EINVAL;
10667
10668 operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
10669 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
10670
Hila Gonene35e4d22012-06-27 17:19:42 +030010671 return rdev_tdls_oper(rdev, dev, peer, operation);
Arik Nemtsov109086c2011-09-28 14:12:50 +030010672}
10673
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010674static int nl80211_remain_on_channel(struct sk_buff *skb,
10675 struct genl_info *info)
10676{
Johannes Berg4c476992010-10-04 21:36:35 +020010677 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +020010678 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +010010679 struct cfg80211_chan_def chandef;
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +053010680 const struct cfg80211_chan_def *compat_chandef;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010681 struct sk_buff *msg;
10682 void *hdr;
10683 u64 cookie;
Johannes Berg683b6d32012-11-08 21:25:48 +010010684 u32 duration;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010685 int err;
10686
10687 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
10688 !info->attrs[NL80211_ATTR_DURATION])
10689 return -EINVAL;
10690
10691 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
10692
Johannes Berg7c4ef712011-11-18 15:33:48 +010010693 if (!rdev->ops->remain_on_channel ||
10694 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
Johannes Berg4c476992010-10-04 21:36:35 +020010695 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010696
Johannes Bergebf348f2012-06-01 12:50:54 +020010697 /*
10698 * We should be on that channel for at least a minimum amount of
10699 * time (10ms) but no longer than the driver supports.
10700 */
10701 if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
10702 duration > rdev->wiphy.max_remain_on_channel_duration)
10703 return -EINVAL;
10704
Johannes Berg683b6d32012-11-08 21:25:48 +010010705 err = nl80211_parse_chandef(rdev, info, &chandef);
10706 if (err)
10707 return err;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010708
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +053010709 wdev_lock(wdev);
10710 if (!cfg80211_off_channel_oper_allowed(wdev) &&
10711 !cfg80211_chandef_identical(&wdev->chandef, &chandef)) {
10712 compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
10713 &chandef);
10714 if (compat_chandef != &chandef) {
10715 wdev_unlock(wdev);
10716 return -EBUSY;
10717 }
10718 }
10719 wdev_unlock(wdev);
10720
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010721 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +020010722 if (!msg)
10723 return -ENOMEM;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010724
Eric W. Biederman15e47302012-09-07 20:12:54 +000010725 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010726 NL80211_CMD_REMAIN_ON_CHANNEL);
Dan Carpentercb35fba2013-08-14 14:50:01 +030010727 if (!hdr) {
10728 err = -ENOBUFS;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010729 goto free_msg;
10730 }
10731
Johannes Berg683b6d32012-11-08 21:25:48 +010010732 err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
10733 duration, &cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010734
10735 if (err)
10736 goto free_msg;
10737
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020010738 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
10739 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040010740 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010741
10742 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +020010743
10744 return genlmsg_reply(msg, info);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010745
10746 nla_put_failure:
10747 err = -ENOBUFS;
10748 free_msg:
10749 nlmsg_free(msg);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010750 return err;
10751}
10752
10753static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
10754 struct genl_info *info)
10755{
Johannes Berg4c476992010-10-04 21:36:35 +020010756 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +020010757 struct wireless_dev *wdev = info->user_ptr[1];
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010758 u64 cookie;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010759
10760 if (!info->attrs[NL80211_ATTR_COOKIE])
10761 return -EINVAL;
10762
Johannes Berg4c476992010-10-04 21:36:35 +020010763 if (!rdev->ops->cancel_remain_on_channel)
10764 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010765
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010766 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
10767
Hila Gonene35e4d22012-06-27 17:19:42 +030010768 return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010010769}
10770
Jouni Malinen13ae75b2009-12-29 12:59:45 +020010771static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
10772 struct genl_info *info)
10773{
Jouni Malinen13ae75b2009-12-29 12:59:45 +020010774 struct cfg80211_bitrate_mask mask;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +053010775 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +020010776 struct net_device *dev = info->user_ptr[1];
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +053010777 int err;
Jouni Malinen13ae75b2009-12-29 12:59:45 +020010778
Johannes Berg4c476992010-10-04 21:36:35 +020010779 if (!rdev->ops->set_bitrate_mask)
10780 return -EOPNOTSUPP;
Jouni Malinen13ae75b2009-12-29 12:59:45 +020010781
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +053010782 err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
10783 NL80211_ATTR_TX_RATES, &mask);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +053010784 if (err)
10785 return err;
Janusz Dziedzic78693032013-12-03 09:50:44 +010010786
Hila Gonene35e4d22012-06-27 17:19:42 +030010787 return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
Jouni Malinen13ae75b2009-12-29 12:59:45 +020010788}
10789
Johannes Berg2e161f782010-08-12 15:38:38 +020010790static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +020010791{
Johannes Berg4c476992010-10-04 21:36:35 +020010792 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +020010793 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2e161f782010-08-12 15:38:38 +020010794 u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
Jouni Malinen026331c2010-02-15 12:53:10 +020010795
10796 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
10797 return -EINVAL;
10798
Johannes Berg2e161f782010-08-12 15:38:38 +020010799 if (info->attrs[NL80211_ATTR_FRAME_TYPE])
10800 frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
Jouni Malinen026331c2010-02-15 12:53:10 +020010801
Johannes Berg71bbc992012-06-15 15:30:18 +020010802 switch (wdev->iftype) {
10803 case NL80211_IFTYPE_STATION:
10804 case NL80211_IFTYPE_ADHOC:
10805 case NL80211_IFTYPE_P2P_CLIENT:
10806 case NL80211_IFTYPE_AP:
10807 case NL80211_IFTYPE_AP_VLAN:
10808 case NL80211_IFTYPE_MESH_POINT:
10809 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +020010810 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +020010811 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010812 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +020010813 default:
Johannes Berg4c476992010-10-04 21:36:35 +020010814 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +020010815 }
Jouni Malinen026331c2010-02-15 12:53:10 +020010816
10817 /* not much point in registering if we can't reply */
Johannes Berg4c476992010-10-04 21:36:35 +020010818 if (!rdev->ops->mgmt_tx)
10819 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +020010820
Johannes Berg9dba48a2020-04-17 12:40:15 +020010821 if (info->attrs[NL80211_ATTR_RECEIVE_MULTICAST] &&
10822 !wiphy_ext_feature_isset(&rdev->wiphy,
10823 NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS)) {
10824 GENL_SET_ERR_MSG(info,
10825 "multicast RX registrations are not supported");
10826 return -EOPNOTSUPP;
10827 }
10828
Eric W. Biederman15e47302012-09-07 20:12:54 +000010829 return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
Ilan Peerff74c512020-01-31 13:45:29 +020010830 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
10831 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]),
Johannes Berg9dba48a2020-04-17 12:40:15 +020010832 info->attrs[NL80211_ATTR_RECEIVE_MULTICAST],
Ilan Peerff74c512020-01-31 13:45:29 +020010833 info->extack);
Jouni Malinen026331c2010-02-15 12:53:10 +020010834}
10835
Johannes Berg2e161f782010-08-12 15:38:38 +020010836static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +020010837{
Johannes Berg4c476992010-10-04 21:36:35 +020010838 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +020010839 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +010010840 struct cfg80211_chan_def chandef;
Jouni Malinen026331c2010-02-15 12:53:10 +020010841 int err;
Johannes Bergd64d3732011-11-10 09:44:46 +010010842 void *hdr = NULL;
Jouni Malinen026331c2010-02-15 12:53:10 +020010843 u64 cookie;
Johannes Berge247bd902011-11-04 11:18:21 +010010844 struct sk_buff *msg = NULL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020010845 struct cfg80211_mgmt_tx_params params = {
10846 .dont_wait_for_ack =
10847 info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
10848 };
Jouni Malinen026331c2010-02-15 12:53:10 +020010849
Johannes Berg683b6d32012-11-08 21:25:48 +010010850 if (!info->attrs[NL80211_ATTR_FRAME])
Jouni Malinen026331c2010-02-15 12:53:10 +020010851 return -EINVAL;
10852
Johannes Berg4c476992010-10-04 21:36:35 +020010853 if (!rdev->ops->mgmt_tx)
10854 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +020010855
Johannes Berg71bbc992012-06-15 15:30:18 +020010856 switch (wdev->iftype) {
Antonio Quartulliea141b752013-06-11 14:20:03 +020010857 case NL80211_IFTYPE_P2P_DEVICE:
10858 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
10859 return -EINVAL;
Johannes Berg71bbc992012-06-15 15:30:18 +020010860 case NL80211_IFTYPE_STATION:
10861 case NL80211_IFTYPE_ADHOC:
10862 case NL80211_IFTYPE_P2P_CLIENT:
10863 case NL80211_IFTYPE_AP:
10864 case NL80211_IFTYPE_AP_VLAN:
10865 case NL80211_IFTYPE_MESH_POINT:
10866 case NL80211_IFTYPE_P2P_GO:
10867 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010868 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +020010869 default:
Johannes Berg4c476992010-10-04 21:36:35 +020010870 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +020010871 }
Jouni Malinen026331c2010-02-15 12:53:10 +020010872
Johannes Bergf7ca38d2010-11-25 10:02:29 +010010873 if (info->attrs[NL80211_ATTR_DURATION]) {
Johannes Berg7c4ef712011-11-18 15:33:48 +010010874 if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Bergf7ca38d2010-11-25 10:02:29 +010010875 return -EINVAL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020010876 params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
Johannes Bergebf348f2012-06-01 12:50:54 +020010877
10878 /*
10879 * We should wait on the channel for at least a minimum amount
10880 * of time (10ms) but no longer than the driver supports.
10881 */
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020010882 if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
10883 params.wait > rdev->wiphy.max_remain_on_channel_duration)
Johannes Bergebf348f2012-06-01 12:50:54 +020010884 return -EINVAL;
Johannes Bergf7ca38d2010-11-25 10:02:29 +010010885 }
10886
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020010887 params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
Johannes Bergf7ca38d2010-11-25 10:02:29 +010010888
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020010889 if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Berg7c4ef712011-11-18 15:33:48 +010010890 return -EINVAL;
10891
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020010892 params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +053010893
Antonio Quartulliea141b752013-06-11 14:20:03 +020010894 /* get the channel if any has been specified, otherwise pass NULL to
10895 * the driver. The latter will use the current one
10896 */
10897 chandef.chan = NULL;
10898 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
10899 err = nl80211_parse_chandef(rdev, info, &chandef);
10900 if (err)
10901 return err;
10902 }
10903
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020010904 if (!chandef.chan && params.offchan)
Antonio Quartulliea141b752013-06-11 14:20:03 +020010905 return -EINVAL;
Jouni Malinen026331c2010-02-15 12:53:10 +020010906
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +053010907 wdev_lock(wdev);
10908 if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) {
10909 wdev_unlock(wdev);
10910 return -EBUSY;
10911 }
10912 wdev_unlock(wdev);
10913
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +030010914 params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
10915 params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
10916
10917 if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
10918 int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
10919 int i;
10920
10921 if (len % sizeof(u16))
10922 return -EINVAL;
10923
10924 params.n_csa_offsets = len / sizeof(u16);
10925 params.csa_offsets =
10926 nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
10927
10928 /* check that all the offsets fit the frame */
10929 for (i = 0; i < params.n_csa_offsets; i++) {
10930 if (params.csa_offsets[i] >= params.len)
10931 return -EINVAL;
10932 }
10933 }
10934
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020010935 if (!params.dont_wait_for_ack) {
Johannes Berge247bd902011-11-04 11:18:21 +010010936 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10937 if (!msg)
10938 return -ENOMEM;
Jouni Malinen026331c2010-02-15 12:53:10 +020010939
Eric W. Biederman15e47302012-09-07 20:12:54 +000010940 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berge247bd902011-11-04 11:18:21 +010010941 NL80211_CMD_FRAME);
Dan Carpentercb35fba2013-08-14 14:50:01 +030010942 if (!hdr) {
10943 err = -ENOBUFS;
Johannes Berge247bd902011-11-04 11:18:21 +010010944 goto free_msg;
10945 }
Jouni Malinen026331c2010-02-15 12:53:10 +020010946 }
Johannes Berge247bd902011-11-04 11:18:21 +010010947
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020010948 params.chan = chandef.chan;
10949 err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
Jouni Malinen026331c2010-02-15 12:53:10 +020010950 if (err)
10951 goto free_msg;
10952
Johannes Berge247bd902011-11-04 11:18:21 +010010953 if (msg) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020010954 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
10955 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040010956 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020010957
Johannes Berge247bd902011-11-04 11:18:21 +010010958 genlmsg_end(msg, hdr);
10959 return genlmsg_reply(msg, info);
10960 }
10961
10962 return 0;
Jouni Malinen026331c2010-02-15 12:53:10 +020010963
10964 nla_put_failure:
10965 err = -ENOBUFS;
10966 free_msg:
10967 nlmsg_free(msg);
Jouni Malinen026331c2010-02-15 12:53:10 +020010968 return err;
10969}
10970
Johannes Bergf7ca38d2010-11-25 10:02:29 +010010971static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
10972{
10973 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +020010974 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Bergf7ca38d2010-11-25 10:02:29 +010010975 u64 cookie;
10976
10977 if (!info->attrs[NL80211_ATTR_COOKIE])
10978 return -EINVAL;
10979
10980 if (!rdev->ops->mgmt_tx_cancel_wait)
10981 return -EOPNOTSUPP;
10982
Johannes Berg71bbc992012-06-15 15:30:18 +020010983 switch (wdev->iftype) {
10984 case NL80211_IFTYPE_STATION:
10985 case NL80211_IFTYPE_ADHOC:
10986 case NL80211_IFTYPE_P2P_CLIENT:
10987 case NL80211_IFTYPE_AP:
10988 case NL80211_IFTYPE_AP_VLAN:
10989 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +020010990 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +020010991 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010992 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +020010993 default:
Johannes Bergf7ca38d2010-11-25 10:02:29 +010010994 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +020010995 }
Johannes Bergf7ca38d2010-11-25 10:02:29 +010010996
10997 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
10998
Hila Gonene35e4d22012-06-27 17:19:42 +030010999 return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
Johannes Bergf7ca38d2010-11-25 10:02:29 +010011000}
11001
Kalle Valoffb9eb32010-02-17 17:58:10 +020011002static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
11003{
Johannes Berg4c476992010-10-04 21:36:35 +020011004 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +020011005 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020011006 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +020011007 u8 ps_state;
11008 bool state;
11009 int err;
11010
Johannes Berg4c476992010-10-04 21:36:35 +020011011 if (!info->attrs[NL80211_ATTR_PS_STATE])
11012 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011013
11014 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
11015
Kalle Valoffb9eb32010-02-17 17:58:10 +020011016 wdev = dev->ieee80211_ptr;
11017
Johannes Berg4c476992010-10-04 21:36:35 +020011018 if (!rdev->ops->set_power_mgmt)
11019 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011020
11021 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
11022
11023 if (state == wdev->ps)
Johannes Berg4c476992010-10-04 21:36:35 +020011024 return 0;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011025
Hila Gonene35e4d22012-06-27 17:19:42 +030011026 err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
Johannes Berg4c476992010-10-04 21:36:35 +020011027 if (!err)
11028 wdev->ps = state;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011029 return err;
11030}
11031
11032static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
11033{
Johannes Berg4c476992010-10-04 21:36:35 +020011034 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +020011035 enum nl80211_ps_state ps_state;
11036 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020011037 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +020011038 struct sk_buff *msg;
11039 void *hdr;
11040 int err;
11041
Kalle Valoffb9eb32010-02-17 17:58:10 +020011042 wdev = dev->ieee80211_ptr;
11043
Johannes Berg4c476992010-10-04 21:36:35 +020011044 if (!rdev->ops->set_power_mgmt)
11045 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011046
11047 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +020011048 if (!msg)
11049 return -ENOMEM;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011050
Eric W. Biederman15e47302012-09-07 20:12:54 +000011051 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Kalle Valoffb9eb32010-02-17 17:58:10 +020011052 NL80211_CMD_GET_POWER_SAVE);
11053 if (!hdr) {
Johannes Berg4c476992010-10-04 21:36:35 +020011054 err = -ENOBUFS;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011055 goto free_msg;
11056 }
11057
11058 if (wdev->ps)
11059 ps_state = NL80211_PS_ENABLED;
11060 else
11061 ps_state = NL80211_PS_DISABLED;
11062
David S. Miller9360ffd2012-03-29 04:41:26 -040011063 if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
11064 goto nla_put_failure;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011065
11066 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +020011067 return genlmsg_reply(msg, info);
Kalle Valoffb9eb32010-02-17 17:58:10 +020011068
Johannes Berg4c476992010-10-04 21:36:35 +020011069 nla_put_failure:
Kalle Valoffb9eb32010-02-17 17:58:10 +020011070 err = -ENOBUFS;
Johannes Berg4c476992010-10-04 21:36:35 +020011071 free_msg:
Kalle Valoffb9eb32010-02-17 17:58:10 +020011072 nlmsg_free(msg);
Kalle Valoffb9eb32010-02-17 17:58:10 +020011073 return err;
11074}
11075
Johannes Berg94e860f2014-01-20 23:58:15 +010011076static const struct nla_policy
11077nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011078 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011079 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
11080 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
Thomas Pedersen84f10702012-07-12 16:17:33 -070011081 [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
11082 [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
11083 [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010011084 [NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011085};
11086
Thomas Pedersen84f10702012-07-12 16:17:33 -070011087static int nl80211_set_cqm_txe(struct genl_info *info,
Johannes Bergd9d8b012012-11-26 12:51:52 +010011088 u32 rate, u32 pkts, u32 intvl)
Thomas Pedersen84f10702012-07-12 16:17:33 -070011089{
11090 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Thomas Pedersen84f10702012-07-12 16:17:33 -070011091 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +020011092 struct wireless_dev *wdev = dev->ieee80211_ptr;
Thomas Pedersen84f10702012-07-12 16:17:33 -070011093
Johannes Bergd9d8b012012-11-26 12:51:52 +010011094 if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
Thomas Pedersen84f10702012-07-12 16:17:33 -070011095 return -EINVAL;
11096
Thomas Pedersen84f10702012-07-12 16:17:33 -070011097 if (!rdev->ops->set_cqm_txe_config)
11098 return -EOPNOTSUPP;
11099
11100 if (wdev->iftype != NL80211_IFTYPE_STATION &&
11101 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
11102 return -EOPNOTSUPP;
11103
Hila Gonene35e4d22012-06-27 17:19:42 +030011104 return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
Thomas Pedersen84f10702012-07-12 16:17:33 -070011105}
11106
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011107static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
11108 struct net_device *dev)
11109{
11110 struct wireless_dev *wdev = dev->ieee80211_ptr;
11111 s32 last, low, high;
11112 u32 hyst;
Masashi Honma1222a162018-09-25 11:15:01 +090011113 int i, n, low_index;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011114 int err;
11115
11116 /* RSSI reporting disabled? */
11117 if (!wdev->cqm_config)
11118 return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
11119
11120 /*
11121 * Obtain current RSSI value if possible, if not and no RSSI threshold
11122 * event has been received yet, we should receive an event after a
11123 * connection is established and enough beacons received to calculate
11124 * the average.
11125 */
11126 if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
11127 rdev->ops->get_station) {
Johannes Berg73887fd2018-05-18 09:57:55 +020011128 struct station_info sinfo = {};
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011129 u8 *mac_addr;
11130
11131 mac_addr = wdev->current_bss->pub.bssid;
11132
Johannes Berg73887fd2018-05-18 09:57:55 +020011133 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
11134 if (err)
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011135 return err;
11136
Felix Fietkaudf167372020-01-08 18:06:30 +010011137 cfg80211_sinfo_release_content(&sinfo);
Omer Efrat397c6572018-06-17 13:06:14 +030011138 if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011139 wdev->cqm_config->last_rssi_event_value =
Johannes Berg73887fd2018-05-18 09:57:55 +020011140 (s8) sinfo.rx_beacon_signal_avg;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011141 }
11142
11143 last = wdev->cqm_config->last_rssi_event_value;
11144 hyst = wdev->cqm_config->rssi_hyst;
11145 n = wdev->cqm_config->n_rssi_thresholds;
11146
Masashi Honma4b2c5a12019-09-08 09:56:53 +090011147 for (i = 0; i < n; i++) {
11148 i = array_index_nospec(i, n);
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011149 if (last < wdev->cqm_config->rssi_thresholds[i])
11150 break;
Masashi Honma4b2c5a12019-09-08 09:56:53 +090011151 }
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011152
Masashi Honma1222a162018-09-25 11:15:01 +090011153 low_index = i - 1;
11154 if (low_index >= 0) {
11155 low_index = array_index_nospec(low_index, n);
11156 low = wdev->cqm_config->rssi_thresholds[low_index] - hyst;
11157 } else {
11158 low = S32_MIN;
11159 }
11160 if (i < n) {
11161 i = array_index_nospec(i, n);
11162 high = wdev->cqm_config->rssi_thresholds[i] + hyst - 1;
11163 } else {
11164 high = S32_MAX;
11165 }
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011166
11167 return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
11168}
11169
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011170static int nl80211_set_cqm_rssi(struct genl_info *info,
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011171 const s32 *thresholds, int n_thresholds,
11172 u32 hysteresis)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011173{
Johannes Berg4c476992010-10-04 21:36:35 +020011174 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +020011175 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +020011176 struct wireless_dev *wdev = dev->ieee80211_ptr;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011177 int i, err;
11178 s32 prev = S32_MIN;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011179
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011180 /* Check all values negative and sorted */
11181 for (i = 0; i < n_thresholds; i++) {
11182 if (thresholds[i] > 0 || thresholds[i] <= prev)
11183 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011184
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011185 prev = thresholds[i];
11186 }
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011187
Johannes Berg074ac8d2010-09-16 14:58:22 +020011188 if (wdev->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020011189 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
11190 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011191
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011192 wdev_lock(wdev);
11193 cfg80211_cqm_config_free(wdev);
11194 wdev_unlock(wdev);
11195
11196 if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
11197 if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
11198 return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
11199
11200 return rdev_set_cqm_rssi_config(rdev, dev,
11201 thresholds[0], hysteresis);
11202 }
11203
11204 if (!wiphy_ext_feature_isset(&rdev->wiphy,
11205 NL80211_EXT_FEATURE_CQM_RSSI_LIST))
11206 return -EOPNOTSUPP;
11207
11208 if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */
11209 n_thresholds = 0;
11210
11211 wdev_lock(wdev);
11212 if (n_thresholds) {
11213 struct cfg80211_cqm_config *cqm_config;
11214
11215 cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
11216 n_thresholds * sizeof(s32), GFP_KERNEL);
11217 if (!cqm_config) {
11218 err = -ENOMEM;
11219 goto unlock;
11220 }
11221
11222 cqm_config->rssi_hyst = hysteresis;
11223 cqm_config->n_rssi_thresholds = n_thresholds;
11224 memcpy(cqm_config->rssi_thresholds, thresholds,
11225 n_thresholds * sizeof(s32));
11226
11227 wdev->cqm_config = cqm_config;
11228 }
11229
11230 err = cfg80211_cqm_rssi_update(rdev, dev);
11231
11232unlock:
11233 wdev_unlock(wdev);
11234
11235 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011236}
11237
11238static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
11239{
11240 struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
11241 struct nlattr *cqm;
11242 int err;
11243
11244 cqm = info->attrs[NL80211_ATTR_CQM];
Johannes Berg1da5fcc2013-08-06 14:10:48 +020011245 if (!cqm)
11246 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011247
Johannes Berg8cb08172019-04-26 14:07:28 +020011248 err = nla_parse_nested_deprecated(attrs, NL80211_ATTR_CQM_MAX, cqm,
11249 nl80211_attr_cqm_policy,
11250 info->extack);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011251 if (err)
Johannes Berg1da5fcc2013-08-06 14:10:48 +020011252 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011253
11254 if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
11255 attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011256 const s32 *thresholds =
11257 nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
11258 int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
Johannes Berg1da5fcc2013-08-06 14:10:48 +020011259 u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011260
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011261 if (len % 4)
11262 return -EINVAL;
11263
11264 return nl80211_set_cqm_rssi(info, thresholds, len / 4,
11265 hysteresis);
Johannes Berg1da5fcc2013-08-06 14:10:48 +020011266 }
11267
11268 if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
11269 attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
11270 attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
11271 u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
11272 u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
11273 u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
11274
11275 return nl80211_set_cqm_txe(info, rate, pkts, intvl);
11276 }
11277
11278 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011279}
11280
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010011281static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
11282{
11283 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11284 struct net_device *dev = info->user_ptr[1];
11285 struct ocb_setup setup = {};
11286 int err;
11287
11288 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
11289 if (err)
11290 return err;
11291
11292 return cfg80211_join_ocb(rdev, dev, &setup);
11293}
11294
11295static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
11296{
11297 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11298 struct net_device *dev = info->user_ptr[1];
11299
11300 return cfg80211_leave_ocb(rdev, dev);
11301}
11302
Johannes Berg29cbe682010-12-03 09:20:44 +010011303static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
11304{
11305 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11306 struct net_device *dev = info->user_ptr[1];
11307 struct mesh_config cfg;
Javier Cardonac80d5452010-12-16 17:37:49 -080011308 struct mesh_setup setup;
Johannes Berg29cbe682010-12-03 09:20:44 +010011309 int err;
11310
11311 /* start with default */
11312 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
Javier Cardonac80d5452010-12-16 17:37:49 -080011313 memcpy(&setup, &default_mesh_setup, sizeof(setup));
Johannes Berg29cbe682010-12-03 09:20:44 +010011314
Javier Cardona24bdd9f2010-12-16 17:37:48 -080011315 if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
Johannes Berg29cbe682010-12-03 09:20:44 +010011316 /* and parse parameters if given */
Javier Cardona24bdd9f2010-12-16 17:37:48 -080011317 err = nl80211_parse_mesh_config(info, &cfg, NULL);
Johannes Berg29cbe682010-12-03 09:20:44 +010011318 if (err)
11319 return err;
11320 }
11321
11322 if (!info->attrs[NL80211_ATTR_MESH_ID] ||
11323 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
11324 return -EINVAL;
11325
Javier Cardonac80d5452010-12-16 17:37:49 -080011326 setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
11327 setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
11328
Chun-Yeow Yeoh4bb62342011-11-24 17:15:20 -080011329 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
11330 !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
11331 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
11332 return -EINVAL;
11333
Marco Porsch9bdbf042013-01-07 16:04:51 +010011334 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
11335 setup.beacon_interval =
11336 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053011337
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +053011338 err = cfg80211_validate_beacon_int(rdev,
11339 NL80211_IFTYPE_MESH_POINT,
11340 setup.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053011341 if (err)
11342 return err;
Marco Porsch9bdbf042013-01-07 16:04:51 +010011343 }
11344
11345 if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
11346 setup.dtim_period =
11347 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
11348 if (setup.dtim_period < 1 || setup.dtim_period > 100)
11349 return -EINVAL;
11350 }
11351
Javier Cardonac80d5452010-12-16 17:37:49 -080011352 if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
11353 /* parse additional setup parameters if given */
11354 err = nl80211_parse_mesh_setup(info, &setup);
11355 if (err)
11356 return err;
11357 }
11358
Thomas Pedersend37bb182013-03-04 13:06:13 -080011359 if (setup.user_mpm)
11360 cfg.auto_open_plinks = false;
11361
Johannes Bergcc1d2802012-05-16 23:50:20 +020011362 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +010011363 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
11364 if (err)
11365 return err;
Johannes Bergcc1d2802012-05-16 23:50:20 +020011366 } else {
Denis Kenzior188c1b32018-03-26 12:52:46 -050011367 /* __cfg80211_join_mesh() will sort it out */
Johannes Berg683b6d32012-11-08 21:25:48 +010011368 setup.chandef.chan = NULL;
Johannes Bergcc1d2802012-05-16 23:50:20 +020011369 }
11370
Ashok Nagarajanffb3cf32013-06-03 10:33:36 -070011371 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
11372 u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
11373 int n_rates =
11374 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
11375 struct ieee80211_supported_band *sband;
11376
11377 if (!setup.chandef.chan)
11378 return -EINVAL;
11379
11380 sband = rdev->wiphy.bands[setup.chandef.chan->band];
11381
11382 err = ieee80211_get_ratemask(sband, rates, n_rates,
11383 &setup.basic_rates);
11384 if (err)
11385 return err;
11386 }
11387
Johannes Berg8564e382016-09-19 09:44:44 +020011388 if (info->attrs[NL80211_ATTR_TX_RATES]) {
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +053011389 err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
11390 NL80211_ATTR_TX_RATES,
11391 &setup.beacon_rate);
Johannes Berg8564e382016-09-19 09:44:44 +020011392 if (err)
11393 return err;
11394
Johannes Berg265698d2017-09-18 22:46:36 +020011395 if (!setup.chandef.chan)
11396 return -EINVAL;
11397
Johannes Berg8564e382016-09-19 09:44:44 +020011398 err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band,
11399 &setup.beacon_rate);
11400 if (err)
11401 return err;
11402 }
11403
Benjamin Bergd37d49c2017-05-16 11:23:11 +020011404 setup.userspace_handles_dfs =
11405 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
11406
Denis Kenzior1224f582018-03-26 12:52:49 -050011407 if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
11408 int r = validate_pae_over_nl80211(rdev, info);
11409
11410 if (r < 0)
11411 return r;
11412
11413 setup.control_port_over_nl80211 = true;
11414 }
11415
Denis Kenzior188c1b32018-03-26 12:52:46 -050011416 wdev_lock(dev->ieee80211_ptr);
11417 err = __cfg80211_join_mesh(rdev, dev, &setup, &cfg);
11418 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER])
11419 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
11420 wdev_unlock(dev->ieee80211_ptr);
11421
11422 return err;
Johannes Berg29cbe682010-12-03 09:20:44 +010011423}
11424
11425static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
11426{
11427 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11428 struct net_device *dev = info->user_ptr[1];
11429
11430 return cfg80211_leave_mesh(rdev, dev);
11431}
11432
Johannes Bergdfb89c52012-06-27 09:23:48 +020011433#ifdef CONFIG_PM
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080011434static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
11435 struct cfg80211_registered_device *rdev)
11436{
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011437 struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080011438 struct nlattr *nl_pats, *nl_pat;
11439 int i, pat_len;
11440
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011441 if (!wowlan->n_patterns)
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080011442 return 0;
11443
Michal Kubecekae0be8d2019-04-26 11:13:06 +020011444 nl_pats = nla_nest_start_noflag(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080011445 if (!nl_pats)
11446 return -ENOBUFS;
11447
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011448 for (i = 0; i < wowlan->n_patterns; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020011449 nl_pat = nla_nest_start_noflag(msg, i + 1);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080011450 if (!nl_pat)
11451 return -ENOBUFS;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011452 pat_len = wowlan->patterns[i].pattern_len;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070011453 if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011454 wowlan->patterns[i].mask) ||
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070011455 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
11456 wowlan->patterns[i].pattern) ||
11457 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011458 wowlan->patterns[i].pkt_offset))
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080011459 return -ENOBUFS;
11460 nla_nest_end(msg, nl_pat);
11461 }
11462 nla_nest_end(msg, nl_pats);
11463
11464 return 0;
11465}
11466
Johannes Berg2a0e0472013-01-23 22:57:40 +010011467static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
11468 struct cfg80211_wowlan_tcp *tcp)
11469{
11470 struct nlattr *nl_tcp;
11471
11472 if (!tcp)
11473 return 0;
11474
Michal Kubecekae0be8d2019-04-26 11:13:06 +020011475 nl_tcp = nla_nest_start_noflag(msg,
11476 NL80211_WOWLAN_TRIG_TCP_CONNECTION);
Johannes Berg2a0e0472013-01-23 22:57:40 +010011477 if (!nl_tcp)
11478 return -ENOBUFS;
11479
Jiri Benc930345e2015-03-29 16:59:25 +020011480 if (nla_put_in_addr(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
11481 nla_put_in_addr(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
Johannes Berg2a0e0472013-01-23 22:57:40 +010011482 nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
11483 nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
11484 nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
11485 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
11486 tcp->payload_len, tcp->payload) ||
11487 nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
11488 tcp->data_interval) ||
11489 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
11490 tcp->wake_len, tcp->wake_data) ||
11491 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK,
11492 DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask))
11493 return -ENOBUFS;
11494
11495 if (tcp->payload_seq.len &&
11496 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
11497 sizeof(tcp->payload_seq), &tcp->payload_seq))
11498 return -ENOBUFS;
11499
11500 if (tcp->payload_tok.len &&
11501 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
11502 sizeof(tcp->payload_tok) + tcp->tokens_size,
11503 &tcp->payload_tok))
11504 return -ENOBUFS;
11505
Johannes Berge248ad32013-05-16 10:24:28 +020011506 nla_nest_end(msg, nl_tcp);
11507
Johannes Berg2a0e0472013-01-23 22:57:40 +010011508 return 0;
11509}
11510
Luciano Coelho75453cc2015-01-09 14:06:37 +020011511static int nl80211_send_wowlan_nd(struct sk_buff *msg,
11512 struct cfg80211_sched_scan_request *req)
11513{
Avraham Stern3b06d272015-10-12 09:51:34 +030011514 struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
Luciano Coelho75453cc2015-01-09 14:06:37 +020011515 int i;
11516
11517 if (!req)
11518 return 0;
11519
Michal Kubecekae0be8d2019-04-26 11:13:06 +020011520 nd = nla_nest_start_noflag(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
Luciano Coelho75453cc2015-01-09 14:06:37 +020011521 if (!nd)
11522 return -ENOBUFS;
11523
Avraham Stern3b06d272015-10-12 09:51:34 +030011524 if (req->n_scan_plans == 1 &&
11525 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
11526 req->scan_plans[0].interval * 1000))
Luciano Coelho75453cc2015-01-09 14:06:37 +020011527 return -ENOBUFS;
11528
Luciano Coelho21fea562015-03-17 16:36:01 +020011529 if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
11530 return -ENOBUFS;
11531
vamsi krishnabf95ecd2017-01-13 01:12:20 +020011532 if (req->relative_rssi_set) {
11533 struct nl80211_bss_select_rssi_adjust rssi_adjust;
11534
11535 if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
11536 req->relative_rssi))
11537 return -ENOBUFS;
11538
11539 rssi_adjust.band = req->rssi_adjust.band;
11540 rssi_adjust.delta = req->rssi_adjust.delta;
11541 if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
11542 sizeof(rssi_adjust), &rssi_adjust))
11543 return -ENOBUFS;
11544 }
11545
Michal Kubecekae0be8d2019-04-26 11:13:06 +020011546 freqs = nla_nest_start_noflag(msg, NL80211_ATTR_SCAN_FREQUENCIES);
Luciano Coelho75453cc2015-01-09 14:06:37 +020011547 if (!freqs)
11548 return -ENOBUFS;
11549
Johannes Berg53b18982016-09-14 09:59:21 +020011550 for (i = 0; i < req->n_channels; i++) {
11551 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
11552 return -ENOBUFS;
11553 }
Luciano Coelho75453cc2015-01-09 14:06:37 +020011554
11555 nla_nest_end(msg, freqs);
11556
11557 if (req->n_match_sets) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020011558 matches = nla_nest_start_noflag(msg,
11559 NL80211_ATTR_SCHED_SCAN_MATCH);
Johannes Berg76e1fb42016-09-14 09:55:57 +020011560 if (!matches)
11561 return -ENOBUFS;
11562
Luciano Coelho75453cc2015-01-09 14:06:37 +020011563 for (i = 0; i < req->n_match_sets; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020011564 match = nla_nest_start_noflag(msg, i);
Johannes Berg76e1fb42016-09-14 09:55:57 +020011565 if (!match)
11566 return -ENOBUFS;
11567
Johannes Berg53b18982016-09-14 09:59:21 +020011568 if (nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
11569 req->match_sets[i].ssid.ssid_len,
11570 req->match_sets[i].ssid.ssid))
11571 return -ENOBUFS;
Luciano Coelho75453cc2015-01-09 14:06:37 +020011572 nla_nest_end(msg, match);
11573 }
11574 nla_nest_end(msg, matches);
11575 }
11576
Michal Kubecekae0be8d2019-04-26 11:13:06 +020011577 scan_plans = nla_nest_start_noflag(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
Avraham Stern3b06d272015-10-12 09:51:34 +030011578 if (!scan_plans)
11579 return -ENOBUFS;
11580
11581 for (i = 0; i < req->n_scan_plans; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020011582 scan_plan = nla_nest_start_noflag(msg, i + 1);
Johannes Berg76e1fb42016-09-14 09:55:57 +020011583 if (!scan_plan)
11584 return -ENOBUFS;
11585
Colin Ian King67626962018-09-06 10:58:44 +010011586 if (nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
Avraham Stern3b06d272015-10-12 09:51:34 +030011587 req->scan_plans[i].interval) ||
11588 (req->scan_plans[i].iterations &&
11589 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
11590 req->scan_plans[i].iterations)))
11591 return -ENOBUFS;
11592 nla_nest_end(msg, scan_plan);
11593 }
11594 nla_nest_end(msg, scan_plans);
11595
Luciano Coelho75453cc2015-01-09 14:06:37 +020011596 nla_nest_end(msg, nd);
11597
11598 return 0;
11599}
11600
Johannes Bergff1b6e62011-05-04 15:37:28 +020011601static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
11602{
11603 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11604 struct sk_buff *msg;
11605 void *hdr;
Johannes Berg2a0e0472013-01-23 22:57:40 +010011606 u32 size = NLMSG_DEFAULT_SIZE;
Johannes Bergff1b6e62011-05-04 15:37:28 +020011607
Johannes Berg964dc9e2013-06-03 17:25:34 +020011608 if (!rdev->wiphy.wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020011609 return -EOPNOTSUPP;
11610
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011611 if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
Johannes Berg2a0e0472013-01-23 22:57:40 +010011612 /* adjust size to have room for all the data */
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011613 size += rdev->wiphy.wowlan_config->tcp->tokens_size +
11614 rdev->wiphy.wowlan_config->tcp->payload_len +
11615 rdev->wiphy.wowlan_config->tcp->wake_len +
11616 rdev->wiphy.wowlan_config->tcp->wake_len / 8;
Johannes Berg2a0e0472013-01-23 22:57:40 +010011617 }
11618
11619 msg = nlmsg_new(size, GFP_KERNEL);
Johannes Bergff1b6e62011-05-04 15:37:28 +020011620 if (!msg)
11621 return -ENOMEM;
11622
Eric W. Biederman15e47302012-09-07 20:12:54 +000011623 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Bergff1b6e62011-05-04 15:37:28 +020011624 NL80211_CMD_GET_WOWLAN);
11625 if (!hdr)
11626 goto nla_put_failure;
11627
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011628 if (rdev->wiphy.wowlan_config) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020011629 struct nlattr *nl_wowlan;
11630
Michal Kubecekae0be8d2019-04-26 11:13:06 +020011631 nl_wowlan = nla_nest_start_noflag(msg,
11632 NL80211_ATTR_WOWLAN_TRIGGERS);
Johannes Bergff1b6e62011-05-04 15:37:28 +020011633 if (!nl_wowlan)
11634 goto nla_put_failure;
11635
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011636 if ((rdev->wiphy.wowlan_config->any &&
David S. Miller9360ffd2012-03-29 04:41:26 -040011637 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011638 (rdev->wiphy.wowlan_config->disconnect &&
David S. Miller9360ffd2012-03-29 04:41:26 -040011639 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011640 (rdev->wiphy.wowlan_config->magic_pkt &&
David S. Miller9360ffd2012-03-29 04:41:26 -040011641 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011642 (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
David S. Miller9360ffd2012-03-29 04:41:26 -040011643 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011644 (rdev->wiphy.wowlan_config->eap_identity_req &&
David S. Miller9360ffd2012-03-29 04:41:26 -040011645 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011646 (rdev->wiphy.wowlan_config->four_way_handshake &&
David S. Miller9360ffd2012-03-29 04:41:26 -040011647 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011648 (rdev->wiphy.wowlan_config->rfkill_release &&
David S. Miller9360ffd2012-03-29 04:41:26 -040011649 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
11650 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +010011651
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080011652 if (nl80211_send_wowlan_patterns(msg, rdev))
11653 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +010011654
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011655 if (nl80211_send_wowlan_tcp(msg,
11656 rdev->wiphy.wowlan_config->tcp))
Johannes Berg2a0e0472013-01-23 22:57:40 +010011657 goto nla_put_failure;
11658
Luciano Coelho75453cc2015-01-09 14:06:37 +020011659 if (nl80211_send_wowlan_nd(
11660 msg,
11661 rdev->wiphy.wowlan_config->nd_config))
11662 goto nla_put_failure;
11663
Johannes Bergff1b6e62011-05-04 15:37:28 +020011664 nla_nest_end(msg, nl_wowlan);
11665 }
11666
11667 genlmsg_end(msg, hdr);
11668 return genlmsg_reply(msg, info);
11669
11670nla_put_failure:
11671 nlmsg_free(msg);
11672 return -ENOBUFS;
11673}
11674
Johannes Berg2a0e0472013-01-23 22:57:40 +010011675static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
11676 struct nlattr *attr,
11677 struct cfg80211_wowlan *trig)
11678{
11679 struct nlattr *tb[NUM_NL80211_WOWLAN_TCP];
11680 struct cfg80211_wowlan_tcp *cfg;
11681 struct nl80211_wowlan_tcp_data_token *tok = NULL;
11682 struct nl80211_wowlan_tcp_data_seq *seq = NULL;
11683 u32 size;
11684 u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
11685 int err, port;
11686
Johannes Berg964dc9e2013-06-03 17:25:34 +020011687 if (!rdev->wiphy.wowlan->tcp)
Johannes Berg2a0e0472013-01-23 22:57:40 +010011688 return -EINVAL;
11689
Johannes Berg8cb08172019-04-26 14:07:28 +020011690 err = nla_parse_nested_deprecated(tb, MAX_NL80211_WOWLAN_TCP, attr,
11691 nl80211_wowlan_tcp_policy, NULL);
Johannes Berg2a0e0472013-01-23 22:57:40 +010011692 if (err)
11693 return err;
11694
11695 if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] ||
11696 !tb[NL80211_WOWLAN_TCP_DST_IPV4] ||
11697 !tb[NL80211_WOWLAN_TCP_DST_MAC] ||
11698 !tb[NL80211_WOWLAN_TCP_DST_PORT] ||
11699 !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] ||
11700 !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] ||
11701 !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] ||
11702 !tb[NL80211_WOWLAN_TCP_WAKE_MASK])
11703 return -EINVAL;
11704
11705 data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020011706 if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010011707 return -EINVAL;
11708
11709 if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
Johannes Berg964dc9e2013-06-03 17:25:34 +020011710 rdev->wiphy.wowlan->tcp->data_interval_max ||
Johannes Berg723d5682013-02-26 13:56:40 +010011711 nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
Johannes Berg2a0e0472013-01-23 22:57:40 +010011712 return -EINVAL;
11713
11714 wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020011715 if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010011716 return -EINVAL;
11717
11718 wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
11719 if (wake_mask_size != DIV_ROUND_UP(wake_size, 8))
11720 return -EINVAL;
11721
11722 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) {
11723 u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
11724
11725 tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
11726 tokens_size = tokln - sizeof(*tok);
11727
11728 if (!tok->len || tokens_size % tok->len)
11729 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020011730 if (!rdev->wiphy.wowlan->tcp->tok)
Johannes Berg2a0e0472013-01-23 22:57:40 +010011731 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020011732 if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010011733 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020011734 if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010011735 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020011736 if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
Johannes Berg2a0e0472013-01-23 22:57:40 +010011737 return -EINVAL;
11738 if (tok->offset + tok->len > data_size)
11739 return -EINVAL;
11740 }
11741
11742 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
11743 seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020011744 if (!rdev->wiphy.wowlan->tcp->seq)
Johannes Berg2a0e0472013-01-23 22:57:40 +010011745 return -EINVAL;
11746 if (seq->len == 0 || seq->len > 4)
11747 return -EINVAL;
11748 if (seq->len + seq->offset > data_size)
11749 return -EINVAL;
11750 }
11751
11752 size = sizeof(*cfg);
11753 size += data_size;
11754 size += wake_size + wake_mask_size;
11755 size += tokens_size;
11756
11757 cfg = kzalloc(size, GFP_KERNEL);
11758 if (!cfg)
11759 return -ENOMEM;
Jiri Benc67b61f62015-03-29 16:59:26 +020011760 cfg->src = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
11761 cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
Johannes Berg2a0e0472013-01-23 22:57:40 +010011762 memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
11763 ETH_ALEN);
11764 if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
11765 port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
11766 else
11767 port = 0;
11768#ifdef CONFIG_INET
11769 /* allocate a socket and port for it and use it */
11770 err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
11771 IPPROTO_TCP, &cfg->sock, 1);
11772 if (err) {
11773 kfree(cfg);
11774 return err;
11775 }
11776 if (inet_csk_get_port(cfg->sock->sk, port)) {
11777 sock_release(cfg->sock);
11778 kfree(cfg);
11779 return -EADDRINUSE;
11780 }
11781 cfg->src_port = inet_sk(cfg->sock->sk)->inet_num;
11782#else
11783 if (!port) {
11784 kfree(cfg);
11785 return -EINVAL;
11786 }
11787 cfg->src_port = port;
11788#endif
11789
11790 cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]);
11791 cfg->payload_len = data_size;
11792 cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size;
11793 memcpy((void *)cfg->payload,
11794 nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]),
11795 data_size);
11796 if (seq)
11797 cfg->payload_seq = *seq;
11798 cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]);
11799 cfg->wake_len = wake_size;
11800 cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size;
11801 memcpy((void *)cfg->wake_data,
11802 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]),
11803 wake_size);
11804 cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size +
11805 data_size + wake_size;
11806 memcpy((void *)cfg->wake_mask,
11807 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]),
11808 wake_mask_size);
11809 if (tok) {
11810 cfg->tokens_size = tokens_size;
11811 memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size);
11812 }
11813
11814 trig->tcp = cfg;
11815
11816 return 0;
11817}
11818
Luciano Coelho8cd4d452014-09-17 11:55:28 +030011819static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
11820 const struct wiphy_wowlan_support *wowlan,
11821 struct nlattr *attr,
11822 struct cfg80211_wowlan *trig)
11823{
11824 struct nlattr **tb;
11825 int err;
11826
Kees Cook6396bb22018-06-12 14:03:40 -070011827 tb = kcalloc(NUM_NL80211_ATTR, sizeof(*tb), GFP_KERNEL);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030011828 if (!tb)
11829 return -ENOMEM;
11830
11831 if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) {
11832 err = -EOPNOTSUPP;
11833 goto out;
11834 }
11835
Johannes Berg8cb08172019-04-26 14:07:28 +020011836 err = nla_parse_nested_deprecated(tb, NL80211_ATTR_MAX, attr,
11837 nl80211_policy, NULL);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030011838 if (err)
11839 goto out;
11840
Arend Van Sprielaad1e812017-01-27 12:27:44 +000011841 trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb,
11842 wowlan->max_nd_match_sets);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030011843 err = PTR_ERR_OR_ZERO(trig->nd_config);
11844 if (err)
11845 trig->nd_config = NULL;
11846
11847out:
11848 kfree(tb);
11849 return err;
11850}
11851
Johannes Bergff1b6e62011-05-04 15:37:28 +020011852static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
11853{
11854 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11855 struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
Johannes Bergff1b6e62011-05-04 15:37:28 +020011856 struct cfg80211_wowlan new_triggers = {};
Johannes Bergae33bd82012-07-12 16:25:02 +020011857 struct cfg80211_wowlan *ntrig;
Johannes Berg964dc9e2013-06-03 17:25:34 +020011858 const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
Johannes Bergff1b6e62011-05-04 15:37:28 +020011859 int err, i;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011860 bool prev_enabled = rdev->wiphy.wowlan_config;
Johannes Berg98fc4382015-03-01 09:10:13 +020011861 bool regular = false;
Johannes Bergff1b6e62011-05-04 15:37:28 +020011862
Johannes Berg964dc9e2013-06-03 17:25:34 +020011863 if (!wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020011864 return -EOPNOTSUPP;
11865
Johannes Bergae33bd82012-07-12 16:25:02 +020011866 if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
11867 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020011868 rdev->wiphy.wowlan_config = NULL;
Johannes Bergae33bd82012-07-12 16:25:02 +020011869 goto set_wakeup;
11870 }
Johannes Bergff1b6e62011-05-04 15:37:28 +020011871
Johannes Berg8cb08172019-04-26 14:07:28 +020011872 err = nla_parse_nested_deprecated(tb, MAX_NL80211_WOWLAN_TRIG,
11873 info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS],
11874 nl80211_wowlan_policy, info->extack);
Johannes Bergff1b6e62011-05-04 15:37:28 +020011875 if (err)
11876 return err;
11877
11878 if (tb[NL80211_WOWLAN_TRIG_ANY]) {
11879 if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
11880 return -EINVAL;
11881 new_triggers.any = true;
11882 }
11883
11884 if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
11885 if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
11886 return -EINVAL;
11887 new_triggers.disconnect = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020011888 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020011889 }
11890
11891 if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
11892 if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
11893 return -EINVAL;
11894 new_triggers.magic_pkt = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020011895 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020011896 }
11897
Johannes Berg77dbbb12011-07-13 10:48:55 +020011898 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
11899 return -EINVAL;
11900
11901 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) {
11902 if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
11903 return -EINVAL;
11904 new_triggers.gtk_rekey_failure = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020011905 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020011906 }
11907
11908 if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
11909 if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
11910 return -EINVAL;
11911 new_triggers.eap_identity_req = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020011912 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020011913 }
11914
11915 if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
11916 if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
11917 return -EINVAL;
11918 new_triggers.four_way_handshake = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020011919 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020011920 }
11921
11922 if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
11923 if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
11924 return -EINVAL;
11925 new_triggers.rfkill_release = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020011926 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020011927 }
11928
Johannes Bergff1b6e62011-05-04 15:37:28 +020011929 if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
11930 struct nlattr *pat;
11931 int n_patterns = 0;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080011932 int rem, pat_len, mask_len, pkt_offset;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070011933 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
Johannes Bergff1b6e62011-05-04 15:37:28 +020011934
Johannes Berg98fc4382015-03-01 09:10:13 +020011935 regular = true;
11936
Johannes Bergff1b6e62011-05-04 15:37:28 +020011937 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
11938 rem)
11939 n_patterns++;
11940 if (n_patterns > wowlan->n_patterns)
11941 return -EINVAL;
11942
11943 new_triggers.patterns = kcalloc(n_patterns,
11944 sizeof(new_triggers.patterns[0]),
11945 GFP_KERNEL);
11946 if (!new_triggers.patterns)
11947 return -ENOMEM;
11948
11949 new_triggers.n_patterns = n_patterns;
11950 i = 0;
11951
11952 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
11953 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020011954 u8 *mask_pat;
11955
Johannes Berg8cb08172019-04-26 14:07:28 +020011956 err = nla_parse_nested_deprecated(pat_tb,
11957 MAX_NL80211_PKTPAT,
11958 pat,
11959 nl80211_packet_pattern_policy,
11960 info->extack);
Johannes Berg95bca622018-06-29 09:33:39 +020011961 if (err)
11962 goto error;
11963
Johannes Bergff1b6e62011-05-04 15:37:28 +020011964 err = -EINVAL;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070011965 if (!pat_tb[NL80211_PKTPAT_MASK] ||
11966 !pat_tb[NL80211_PKTPAT_PATTERN])
Johannes Bergff1b6e62011-05-04 15:37:28 +020011967 goto error;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070011968 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
Johannes Bergff1b6e62011-05-04 15:37:28 +020011969 mask_len = DIV_ROUND_UP(pat_len, 8);
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070011970 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
Johannes Bergff1b6e62011-05-04 15:37:28 +020011971 goto error;
11972 if (pat_len > wowlan->pattern_max_len ||
11973 pat_len < wowlan->pattern_min_len)
11974 goto error;
11975
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070011976 if (!pat_tb[NL80211_PKTPAT_OFFSET])
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080011977 pkt_offset = 0;
11978 else
11979 pkt_offset = nla_get_u32(
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070011980 pat_tb[NL80211_PKTPAT_OFFSET]);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080011981 if (pkt_offset > wowlan->max_pkt_offset)
11982 goto error;
11983 new_triggers.patterns[i].pkt_offset = pkt_offset;
11984
Johannes Berg922bd802014-05-19 17:59:50 +020011985 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
11986 if (!mask_pat) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020011987 err = -ENOMEM;
11988 goto error;
11989 }
Johannes Berg922bd802014-05-19 17:59:50 +020011990 new_triggers.patterns[i].mask = mask_pat;
11991 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020011992 mask_len);
Johannes Berg922bd802014-05-19 17:59:50 +020011993 mask_pat += mask_len;
11994 new_triggers.patterns[i].pattern = mask_pat;
Johannes Bergff1b6e62011-05-04 15:37:28 +020011995 new_triggers.patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020011996 memcpy(mask_pat,
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070011997 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020011998 pat_len);
11999 i++;
12000 }
12001 }
12002
Johannes Berg2a0e0472013-01-23 22:57:40 +010012003 if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020012004 regular = true;
Johannes Berg2a0e0472013-01-23 22:57:40 +010012005 err = nl80211_parse_wowlan_tcp(
12006 rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
12007 &new_triggers);
12008 if (err)
12009 goto error;
12010 }
12011
Luciano Coelho8cd4d452014-09-17 11:55:28 +030012012 if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020012013 regular = true;
Luciano Coelho8cd4d452014-09-17 11:55:28 +030012014 err = nl80211_parse_wowlan_nd(
12015 rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
12016 &new_triggers);
12017 if (err)
12018 goto error;
12019 }
12020
Johannes Berg98fc4382015-03-01 09:10:13 +020012021 /* The 'any' trigger means the device continues operating more or less
12022 * as in its normal operation mode and wakes up the host on most of the
12023 * normal interrupts (like packet RX, ...)
12024 * It therefore makes little sense to combine with the more constrained
12025 * wakeup trigger modes.
12026 */
12027 if (new_triggers.any && regular) {
12028 err = -EINVAL;
12029 goto error;
12030 }
12031
Johannes Bergae33bd82012-07-12 16:25:02 +020012032 ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
12033 if (!ntrig) {
12034 err = -ENOMEM;
12035 goto error;
Johannes Bergff1b6e62011-05-04 15:37:28 +020012036 }
Johannes Bergae33bd82012-07-12 16:25:02 +020012037 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012038 rdev->wiphy.wowlan_config = ntrig;
Johannes Bergff1b6e62011-05-04 15:37:28 +020012039
Johannes Bergae33bd82012-07-12 16:25:02 +020012040 set_wakeup:
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012041 if (rdev->ops->set_wakeup &&
12042 prev_enabled != !!rdev->wiphy.wowlan_config)
12043 rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
Johannes Berg6d525632012-04-04 15:05:25 +020012044
Johannes Bergff1b6e62011-05-04 15:37:28 +020012045 return 0;
12046 error:
12047 for (i = 0; i < new_triggers.n_patterns; i++)
12048 kfree(new_triggers.patterns[i].mask);
12049 kfree(new_triggers.patterns);
Johannes Berg2a0e0472013-01-23 22:57:40 +010012050 if (new_triggers.tcp && new_triggers.tcp->sock)
12051 sock_release(new_triggers.tcp->sock);
12052 kfree(new_triggers.tcp);
Ola Olssone5dbe072015-12-12 23:17:17 +010012053 kfree(new_triggers.nd_config);
Johannes Bergff1b6e62011-05-04 15:37:28 +020012054 return err;
12055}
Johannes Bergdfb89c52012-06-27 09:23:48 +020012056#endif
Johannes Bergff1b6e62011-05-04 15:37:28 +020012057
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012058static int nl80211_send_coalesce_rules(struct sk_buff *msg,
12059 struct cfg80211_registered_device *rdev)
12060{
12061 struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
12062 int i, j, pat_len;
12063 struct cfg80211_coalesce_rules *rule;
12064
12065 if (!rdev->coalesce->n_rules)
12066 return 0;
12067
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012068 nl_rules = nla_nest_start_noflag(msg, NL80211_ATTR_COALESCE_RULE);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012069 if (!nl_rules)
12070 return -ENOBUFS;
12071
12072 for (i = 0; i < rdev->coalesce->n_rules; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012073 nl_rule = nla_nest_start_noflag(msg, i + 1);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012074 if (!nl_rule)
12075 return -ENOBUFS;
12076
12077 rule = &rdev->coalesce->rules[i];
12078 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
12079 rule->delay))
12080 return -ENOBUFS;
12081
12082 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
12083 rule->condition))
12084 return -ENOBUFS;
12085
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012086 nl_pats = nla_nest_start_noflag(msg,
12087 NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012088 if (!nl_pats)
12089 return -ENOBUFS;
12090
12091 for (j = 0; j < rule->n_patterns; j++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012092 nl_pat = nla_nest_start_noflag(msg, j + 1);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012093 if (!nl_pat)
12094 return -ENOBUFS;
12095 pat_len = rule->patterns[j].pattern_len;
12096 if (nla_put(msg, NL80211_PKTPAT_MASK,
12097 DIV_ROUND_UP(pat_len, 8),
12098 rule->patterns[j].mask) ||
12099 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
12100 rule->patterns[j].pattern) ||
12101 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
12102 rule->patterns[j].pkt_offset))
12103 return -ENOBUFS;
12104 nla_nest_end(msg, nl_pat);
12105 }
12106 nla_nest_end(msg, nl_pats);
12107 nla_nest_end(msg, nl_rule);
12108 }
12109 nla_nest_end(msg, nl_rules);
12110
12111 return 0;
12112}
12113
12114static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
12115{
12116 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12117 struct sk_buff *msg;
12118 void *hdr;
12119
12120 if (!rdev->wiphy.coalesce)
12121 return -EOPNOTSUPP;
12122
12123 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12124 if (!msg)
12125 return -ENOMEM;
12126
12127 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
12128 NL80211_CMD_GET_COALESCE);
12129 if (!hdr)
12130 goto nla_put_failure;
12131
12132 if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
12133 goto nla_put_failure;
12134
12135 genlmsg_end(msg, hdr);
12136 return genlmsg_reply(msg, info);
12137
12138nla_put_failure:
12139 nlmsg_free(msg);
12140 return -ENOBUFS;
12141}
12142
12143void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
12144{
12145 struct cfg80211_coalesce *coalesce = rdev->coalesce;
12146 int i, j;
12147 struct cfg80211_coalesce_rules *rule;
12148
12149 if (!coalesce)
12150 return;
12151
12152 for (i = 0; i < coalesce->n_rules; i++) {
12153 rule = &coalesce->rules[i];
12154 for (j = 0; j < rule->n_patterns; j++)
12155 kfree(rule->patterns[j].mask);
12156 kfree(rule->patterns);
12157 }
12158 kfree(coalesce->rules);
12159 kfree(coalesce);
12160 rdev->coalesce = NULL;
12161}
12162
12163static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
12164 struct nlattr *rule,
12165 struct cfg80211_coalesce_rules *new_rule)
12166{
12167 int err, i;
12168 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
12169 struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
12170 int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
12171 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
12172
Johannes Berg8cb08172019-04-26 14:07:28 +020012173 err = nla_parse_nested_deprecated(tb, NL80211_ATTR_COALESCE_RULE_MAX,
12174 rule, nl80211_coalesce_policy, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012175 if (err)
12176 return err;
12177
12178 if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
12179 new_rule->delay =
12180 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
12181 if (new_rule->delay > coalesce->max_delay)
12182 return -EINVAL;
12183
12184 if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
12185 new_rule->condition =
12186 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012187
12188 if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
12189 return -EINVAL;
12190
12191 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
12192 rem)
12193 n_patterns++;
12194 if (n_patterns > coalesce->n_patterns)
12195 return -EINVAL;
12196
12197 new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
12198 GFP_KERNEL);
12199 if (!new_rule->patterns)
12200 return -ENOMEM;
12201
12202 new_rule->n_patterns = n_patterns;
12203 i = 0;
12204
12205 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
12206 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020012207 u8 *mask_pat;
12208
Johannes Berg8cb08172019-04-26 14:07:28 +020012209 err = nla_parse_nested_deprecated(pat_tb, MAX_NL80211_PKTPAT,
12210 pat,
12211 nl80211_packet_pattern_policy,
12212 NULL);
Johannes Berg95bca622018-06-29 09:33:39 +020012213 if (err)
12214 return err;
12215
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012216 if (!pat_tb[NL80211_PKTPAT_MASK] ||
12217 !pat_tb[NL80211_PKTPAT_PATTERN])
12218 return -EINVAL;
12219 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
12220 mask_len = DIV_ROUND_UP(pat_len, 8);
12221 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
12222 return -EINVAL;
12223 if (pat_len > coalesce->pattern_max_len ||
12224 pat_len < coalesce->pattern_min_len)
12225 return -EINVAL;
12226
12227 if (!pat_tb[NL80211_PKTPAT_OFFSET])
12228 pkt_offset = 0;
12229 else
12230 pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
12231 if (pkt_offset > coalesce->max_pkt_offset)
12232 return -EINVAL;
12233 new_rule->patterns[i].pkt_offset = pkt_offset;
12234
Johannes Berg922bd802014-05-19 17:59:50 +020012235 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
12236 if (!mask_pat)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012237 return -ENOMEM;
Johannes Berg922bd802014-05-19 17:59:50 +020012238
12239 new_rule->patterns[i].mask = mask_pat;
12240 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
12241 mask_len);
12242
12243 mask_pat += mask_len;
12244 new_rule->patterns[i].pattern = mask_pat;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012245 new_rule->patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020012246 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
12247 pat_len);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012248 i++;
12249 }
12250
12251 return 0;
12252}
12253
12254static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
12255{
12256 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12257 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
12258 struct cfg80211_coalesce new_coalesce = {};
12259 struct cfg80211_coalesce *n_coalesce;
12260 int err, rem_rule, n_rules = 0, i, j;
12261 struct nlattr *rule;
12262 struct cfg80211_coalesce_rules *tmp_rule;
12263
12264 if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
12265 return -EOPNOTSUPP;
12266
12267 if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
12268 cfg80211_rdev_free_coalesce(rdev);
Ilan Peera1056b1b2015-10-22 22:27:46 +030012269 rdev_set_coalesce(rdev, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012270 return 0;
12271 }
12272
12273 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
12274 rem_rule)
12275 n_rules++;
12276 if (n_rules > coalesce->n_rules)
12277 return -EINVAL;
12278
12279 new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
12280 GFP_KERNEL);
12281 if (!new_coalesce.rules)
12282 return -ENOMEM;
12283
12284 new_coalesce.n_rules = n_rules;
12285 i = 0;
12286
12287 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
12288 rem_rule) {
12289 err = nl80211_parse_coalesce_rule(rdev, rule,
12290 &new_coalesce.rules[i]);
12291 if (err)
12292 goto error;
12293
12294 i++;
12295 }
12296
Ilan Peera1056b1b2015-10-22 22:27:46 +030012297 err = rdev_set_coalesce(rdev, &new_coalesce);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012298 if (err)
12299 goto error;
12300
12301 n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
12302 if (!n_coalesce) {
12303 err = -ENOMEM;
12304 goto error;
12305 }
12306 cfg80211_rdev_free_coalesce(rdev);
12307 rdev->coalesce = n_coalesce;
12308
12309 return 0;
12310error:
12311 for (i = 0; i < new_coalesce.n_rules; i++) {
12312 tmp_rule = &new_coalesce.rules[i];
12313 for (j = 0; j < tmp_rule->n_patterns; j++)
12314 kfree(tmp_rule->patterns[j].mask);
12315 kfree(tmp_rule->patterns);
12316 }
12317 kfree(new_coalesce.rules);
12318
12319 return err;
12320}
12321
Johannes Berge5497d72011-07-05 16:35:40 +020012322static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
12323{
12324 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12325 struct net_device *dev = info->user_ptr[1];
12326 struct wireless_dev *wdev = dev->ieee80211_ptr;
12327 struct nlattr *tb[NUM_NL80211_REKEY_DATA];
12328 struct cfg80211_gtk_rekey_data rekey_data;
12329 int err;
12330
12331 if (!info->attrs[NL80211_ATTR_REKEY_DATA])
12332 return -EINVAL;
12333
Johannes Berg8cb08172019-04-26 14:07:28 +020012334 err = nla_parse_nested_deprecated(tb, MAX_NL80211_REKEY_DATA,
12335 info->attrs[NL80211_ATTR_REKEY_DATA],
12336 nl80211_rekey_policy, info->extack);
Johannes Berge5497d72011-07-05 16:35:40 +020012337 if (err)
12338 return err;
12339
Vladis Dronove785fa02017-09-13 00:21:21 +020012340 if (!tb[NL80211_REKEY_DATA_REPLAY_CTR] || !tb[NL80211_REKEY_DATA_KEK] ||
12341 !tb[NL80211_REKEY_DATA_KCK])
12342 return -EINVAL;
Nathan Errera093a48d2020-05-28 21:22:38 +020012343 if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN &&
12344 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK &&
12345 nla_len(tb[NL80211_REKEY_DATA_KEK]) == NL80211_KEK_EXT_LEN))
Johannes Berge5497d72011-07-05 16:35:40 +020012346 return -ERANGE;
Nathan Errera093a48d2020-05-28 21:22:38 +020012347 if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN &&
12348 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK &&
12349 nla_len(tb[NL80211_REKEY_DATA_KEK]) == NL80211_KCK_EXT_LEN))
Johannes Berge5497d72011-07-05 16:35:40 +020012350 return -ERANGE;
12351
Johannes Berg78f686c2014-09-10 22:28:06 +030012352 rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
12353 rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
12354 rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
Nathan Errera093a48d2020-05-28 21:22:38 +020012355 rekey_data.kek_len = nla_len(tb[NL80211_REKEY_DATA_KEK]);
12356 rekey_data.kck_len = nla_len(tb[NL80211_REKEY_DATA_KCK]);
12357 if (tb[NL80211_REKEY_DATA_AKM])
12358 rekey_data.akm = nla_get_u32(tb[NL80211_REKEY_DATA_AKM]);
Johannes Berge5497d72011-07-05 16:35:40 +020012359
12360 wdev_lock(wdev);
12361 if (!wdev->current_bss) {
12362 err = -ENOTCONN;
12363 goto out;
12364 }
12365
12366 if (!rdev->ops->set_rekey_data) {
12367 err = -EOPNOTSUPP;
12368 goto out;
12369 }
12370
Hila Gonene35e4d22012-06-27 17:19:42 +030012371 err = rdev_set_rekey_data(rdev, dev, &rekey_data);
Johannes Berge5497d72011-07-05 16:35:40 +020012372 out:
12373 wdev_unlock(wdev);
12374 return err;
12375}
12376
Johannes Berg28946da2011-11-04 11:18:12 +010012377static int nl80211_register_unexpected_frame(struct sk_buff *skb,
12378 struct genl_info *info)
12379{
12380 struct net_device *dev = info->user_ptr[1];
12381 struct wireless_dev *wdev = dev->ieee80211_ptr;
12382
12383 if (wdev->iftype != NL80211_IFTYPE_AP &&
12384 wdev->iftype != NL80211_IFTYPE_P2P_GO)
12385 return -EINVAL;
12386
Eric W. Biederman15e47302012-09-07 20:12:54 +000012387 if (wdev->ap_unexpected_nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010012388 return -EBUSY;
12389
Eric W. Biederman15e47302012-09-07 20:12:54 +000012390 wdev->ap_unexpected_nlportid = info->snd_portid;
Johannes Berg28946da2011-11-04 11:18:12 +010012391 return 0;
12392}
12393
Johannes Berg7f6cf312011-11-04 11:18:15 +010012394static int nl80211_probe_client(struct sk_buff *skb,
12395 struct genl_info *info)
12396{
12397 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12398 struct net_device *dev = info->user_ptr[1];
12399 struct wireless_dev *wdev = dev->ieee80211_ptr;
12400 struct sk_buff *msg;
12401 void *hdr;
12402 const u8 *addr;
12403 u64 cookie;
12404 int err;
12405
12406 if (wdev->iftype != NL80211_IFTYPE_AP &&
12407 wdev->iftype != NL80211_IFTYPE_P2P_GO)
12408 return -EOPNOTSUPP;
12409
12410 if (!info->attrs[NL80211_ATTR_MAC])
12411 return -EINVAL;
12412
12413 if (!rdev->ops->probe_client)
12414 return -EOPNOTSUPP;
12415
12416 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12417 if (!msg)
12418 return -ENOMEM;
12419
Eric W. Biederman15e47302012-09-07 20:12:54 +000012420 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg7f6cf312011-11-04 11:18:15 +010012421 NL80211_CMD_PROBE_CLIENT);
Dan Carpentercb35fba2013-08-14 14:50:01 +030012422 if (!hdr) {
12423 err = -ENOBUFS;
Johannes Berg7f6cf312011-11-04 11:18:15 +010012424 goto free_msg;
12425 }
12426
12427 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
12428
Hila Gonene35e4d22012-06-27 17:19:42 +030012429 err = rdev_probe_client(rdev, dev, addr, &cookie);
Johannes Berg7f6cf312011-11-04 11:18:15 +010012430 if (err)
12431 goto free_msg;
12432
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020012433 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
12434 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040012435 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010012436
12437 genlmsg_end(msg, hdr);
12438
12439 return genlmsg_reply(msg, info);
12440
12441 nla_put_failure:
12442 err = -ENOBUFS;
12443 free_msg:
12444 nlmsg_free(msg);
12445 return err;
12446}
12447
Johannes Berg5e760232011-11-04 11:18:17 +010012448static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
12449{
12450 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Ben Greear37c73b52012-10-26 14:49:25 -070012451 struct cfg80211_beacon_registration *reg, *nreg;
12452 int rv;
Johannes Berg5e760232011-11-04 11:18:17 +010012453
12454 if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
12455 return -EOPNOTSUPP;
12456
Ben Greear37c73b52012-10-26 14:49:25 -070012457 nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
12458 if (!nreg)
12459 return -ENOMEM;
Johannes Berg5e760232011-11-04 11:18:17 +010012460
Ben Greear37c73b52012-10-26 14:49:25 -070012461 /* First, check if already registered. */
12462 spin_lock_bh(&rdev->beacon_registrations_lock);
12463 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
12464 if (reg->nlportid == info->snd_portid) {
12465 rv = -EALREADY;
12466 goto out_err;
12467 }
12468 }
12469 /* Add it to the list */
12470 nreg->nlportid = info->snd_portid;
12471 list_add(&nreg->list, &rdev->beacon_registrations);
12472
12473 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010012474
12475 return 0;
Ben Greear37c73b52012-10-26 14:49:25 -070012476out_err:
12477 spin_unlock_bh(&rdev->beacon_registrations_lock);
12478 kfree(nreg);
12479 return rv;
Johannes Berg5e760232011-11-04 11:18:17 +010012480}
12481
Johannes Berg98104fde2012-06-16 00:19:54 +020012482static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
12483{
12484 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12485 struct wireless_dev *wdev = info->user_ptr[1];
12486 int err;
12487
12488 if (!rdev->ops->start_p2p_device)
12489 return -EOPNOTSUPP;
12490
12491 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
12492 return -EOPNOTSUPP;
12493
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012494 if (wdev_running(wdev))
Johannes Berg98104fde2012-06-16 00:19:54 +020012495 return 0;
12496
Luciano Coelhob6a55012014-02-27 11:07:21 +020012497 if (rfkill_blocked(rdev->rfkill))
12498 return -ERFKILL;
Johannes Berg98104fde2012-06-16 00:19:54 +020012499
Johannes Bergeeb126e2012-10-23 15:16:50 +020012500 err = rdev_start_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020012501 if (err)
12502 return err;
12503
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012504 wdev->is_running = true;
Johannes Berg98104fde2012-06-16 00:19:54 +020012505 rdev->opencount++;
Johannes Berg98104fde2012-06-16 00:19:54 +020012506
12507 return 0;
12508}
12509
12510static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
12511{
12512 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12513 struct wireless_dev *wdev = info->user_ptr[1];
12514
12515 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
12516 return -EOPNOTSUPP;
12517
12518 if (!rdev->ops->stop_p2p_device)
12519 return -EOPNOTSUPP;
12520
Johannes Bergf9f47522013-03-19 15:04:07 +010012521 cfg80211_stop_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020012522
12523 return 0;
12524}
12525
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012526static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
12527{
12528 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12529 struct wireless_dev *wdev = info->user_ptr[1];
12530 struct cfg80211_nan_conf conf = {};
12531 int err;
12532
12533 if (wdev->iftype != NL80211_IFTYPE_NAN)
12534 return -EOPNOTSUPP;
12535
Johannes Bergeeb04a92016-11-21 13:55:48 +010012536 if (wdev_running(wdev))
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012537 return -EEXIST;
12538
12539 if (rfkill_blocked(rdev->rfkill))
12540 return -ERFKILL;
12541
12542 if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
12543 return -EINVAL;
12544
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012545 conf.master_pref =
12546 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012547
Luca Coelho85859892017-02-08 15:00:34 +020012548 if (info->attrs[NL80211_ATTR_BANDS]) {
12549 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
12550
12551 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
12552 return -EOPNOTSUPP;
12553
12554 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
12555 return -EINVAL;
12556
12557 conf.bands = bands;
12558 }
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012559
12560 err = rdev_start_nan(rdev, wdev, &conf);
12561 if (err)
12562 return err;
12563
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012564 wdev->is_running = true;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012565 rdev->opencount++;
12566
12567 return 0;
12568}
12569
12570static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
12571{
12572 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12573 struct wireless_dev *wdev = info->user_ptr[1];
12574
12575 if (wdev->iftype != NL80211_IFTYPE_NAN)
12576 return -EOPNOTSUPP;
12577
12578 cfg80211_stop_nan(rdev, wdev);
12579
12580 return 0;
12581}
12582
Ayala Bekera442b762016-09-20 17:31:15 +030012583static int validate_nan_filter(struct nlattr *filter_attr)
12584{
12585 struct nlattr *attr;
12586 int len = 0, n_entries = 0, rem;
12587
12588 nla_for_each_nested(attr, filter_attr, rem) {
12589 len += nla_len(attr);
12590 n_entries++;
12591 }
12592
12593 if (len >= U8_MAX)
12594 return -EINVAL;
12595
12596 return n_entries;
12597}
12598
12599static int handle_nan_filter(struct nlattr *attr_filter,
12600 struct cfg80211_nan_func *func,
12601 bool tx)
12602{
12603 struct nlattr *attr;
12604 int n_entries, rem, i;
12605 struct cfg80211_nan_func_filter *filter;
12606
12607 n_entries = validate_nan_filter(attr_filter);
12608 if (n_entries < 0)
12609 return n_entries;
12610
12611 BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters));
12612
12613 filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL);
12614 if (!filter)
12615 return -ENOMEM;
12616
12617 i = 0;
12618 nla_for_each_nested(attr, attr_filter, rem) {
Thomas Grafb15ca182016-10-26 10:53:16 +020012619 filter[i].filter = nla_memdup(attr, GFP_KERNEL);
Ayala Bekera442b762016-09-20 17:31:15 +030012620 filter[i].len = nla_len(attr);
12621 i++;
12622 }
12623 if (tx) {
12624 func->num_tx_filters = n_entries;
12625 func->tx_filters = filter;
12626 } else {
12627 func->num_rx_filters = n_entries;
12628 func->rx_filters = filter;
12629 }
12630
12631 return 0;
12632}
12633
12634static int nl80211_nan_add_func(struct sk_buff *skb,
12635 struct genl_info *info)
12636{
12637 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12638 struct wireless_dev *wdev = info->user_ptr[1];
12639 struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR], *func_attr;
12640 struct cfg80211_nan_func *func;
12641 struct sk_buff *msg = NULL;
12642 void *hdr = NULL;
12643 int err = 0;
12644
12645 if (wdev->iftype != NL80211_IFTYPE_NAN)
12646 return -EOPNOTSUPP;
12647
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012648 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030012649 return -ENOTCONN;
12650
12651 if (!info->attrs[NL80211_ATTR_NAN_FUNC])
12652 return -EINVAL;
12653
Johannes Berg8cb08172019-04-26 14:07:28 +020012654 err = nla_parse_nested_deprecated(tb, NL80211_NAN_FUNC_ATTR_MAX,
12655 info->attrs[NL80211_ATTR_NAN_FUNC],
12656 nl80211_nan_func_policy,
12657 info->extack);
Ayala Bekera442b762016-09-20 17:31:15 +030012658 if (err)
12659 return err;
12660
12661 func = kzalloc(sizeof(*func), GFP_KERNEL);
12662 if (!func)
12663 return -ENOMEM;
12664
Johannes Bergb60ad342018-10-01 11:52:07 +020012665 func->cookie = cfg80211_assign_cookie(rdev);
Ayala Bekera442b762016-09-20 17:31:15 +030012666
Johannes Bergcb9abd42020-08-05 15:47:16 +020012667 if (!tb[NL80211_NAN_FUNC_TYPE]) {
Ayala Bekera442b762016-09-20 17:31:15 +030012668 err = -EINVAL;
12669 goto out;
12670 }
12671
12672
12673 func->type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]);
12674
12675 if (!tb[NL80211_NAN_FUNC_SERVICE_ID]) {
12676 err = -EINVAL;
12677 goto out;
12678 }
12679
12680 memcpy(func->service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]),
12681 sizeof(func->service_id));
12682
12683 func->close_range =
12684 nla_get_flag(tb[NL80211_NAN_FUNC_CLOSE_RANGE]);
12685
12686 if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) {
12687 func->serv_spec_info_len =
12688 nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
12689 func->serv_spec_info =
12690 kmemdup(nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]),
12691 func->serv_spec_info_len,
12692 GFP_KERNEL);
12693 if (!func->serv_spec_info) {
12694 err = -ENOMEM;
12695 goto out;
12696 }
12697 }
12698
12699 if (tb[NL80211_NAN_FUNC_TTL])
12700 func->ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]);
12701
12702 switch (func->type) {
12703 case NL80211_NAN_FUNC_PUBLISH:
12704 if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE]) {
12705 err = -EINVAL;
12706 goto out;
12707 }
12708
12709 func->publish_type =
12710 nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]);
12711 func->publish_bcast =
12712 nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]);
12713
12714 if ((!(func->publish_type & NL80211_NAN_SOLICITED_PUBLISH)) &&
12715 func->publish_bcast) {
12716 err = -EINVAL;
12717 goto out;
12718 }
12719 break;
12720 case NL80211_NAN_FUNC_SUBSCRIBE:
12721 func->subscribe_active =
12722 nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]);
12723 break;
12724 case NL80211_NAN_FUNC_FOLLOW_UP:
12725 if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] ||
Hao Chen3ea15452018-01-03 11:00:31 +080012726 !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] ||
12727 !tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]) {
Ayala Bekera442b762016-09-20 17:31:15 +030012728 err = -EINVAL;
12729 goto out;
12730 }
12731
12732 func->followup_id =
12733 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]);
12734 func->followup_reqid =
12735 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]);
12736 memcpy(func->followup_dest.addr,
12737 nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]),
12738 sizeof(func->followup_dest.addr));
12739 if (func->ttl) {
12740 err = -EINVAL;
12741 goto out;
12742 }
12743 break;
12744 default:
12745 err = -EINVAL;
12746 goto out;
12747 }
12748
12749 if (tb[NL80211_NAN_FUNC_SRF]) {
12750 struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
12751
Johannes Berg8cb08172019-04-26 14:07:28 +020012752 err = nla_parse_nested_deprecated(srf_tb,
12753 NL80211_NAN_SRF_ATTR_MAX,
12754 tb[NL80211_NAN_FUNC_SRF],
12755 nl80211_nan_srf_policy,
12756 info->extack);
Ayala Bekera442b762016-09-20 17:31:15 +030012757 if (err)
12758 goto out;
12759
12760 func->srf_include =
12761 nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]);
12762
12763 if (srf_tb[NL80211_NAN_SRF_BF]) {
12764 if (srf_tb[NL80211_NAN_SRF_MAC_ADDRS] ||
12765 !srf_tb[NL80211_NAN_SRF_BF_IDX]) {
12766 err = -EINVAL;
12767 goto out;
12768 }
12769
12770 func->srf_bf_len =
12771 nla_len(srf_tb[NL80211_NAN_SRF_BF]);
12772 func->srf_bf =
12773 kmemdup(nla_data(srf_tb[NL80211_NAN_SRF_BF]),
12774 func->srf_bf_len, GFP_KERNEL);
12775 if (!func->srf_bf) {
12776 err = -ENOMEM;
12777 goto out;
12778 }
12779
12780 func->srf_bf_idx =
12781 nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]);
12782 } else {
12783 struct nlattr *attr, *mac_attr =
12784 srf_tb[NL80211_NAN_SRF_MAC_ADDRS];
12785 int n_entries, rem, i = 0;
12786
12787 if (!mac_attr) {
12788 err = -EINVAL;
12789 goto out;
12790 }
12791
12792 n_entries = validate_acl_mac_addrs(mac_attr);
12793 if (n_entries <= 0) {
12794 err = -EINVAL;
12795 goto out;
12796 }
12797
12798 func->srf_num_macs = n_entries;
12799 func->srf_macs =
Kees Cook6396bb22018-06-12 14:03:40 -070012800 kcalloc(n_entries, sizeof(*func->srf_macs),
Ayala Bekera442b762016-09-20 17:31:15 +030012801 GFP_KERNEL);
12802 if (!func->srf_macs) {
12803 err = -ENOMEM;
12804 goto out;
12805 }
12806
12807 nla_for_each_nested(attr, mac_attr, rem)
12808 memcpy(func->srf_macs[i++].addr, nla_data(attr),
12809 sizeof(*func->srf_macs));
12810 }
12811 }
12812
12813 if (tb[NL80211_NAN_FUNC_TX_MATCH_FILTER]) {
12814 err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER],
12815 func, true);
12816 if (err)
12817 goto out;
12818 }
12819
12820 if (tb[NL80211_NAN_FUNC_RX_MATCH_FILTER]) {
12821 err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER],
12822 func, false);
12823 if (err)
12824 goto out;
12825 }
12826
12827 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12828 if (!msg) {
12829 err = -ENOMEM;
12830 goto out;
12831 }
12832
12833 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
12834 NL80211_CMD_ADD_NAN_FUNCTION);
12835 /* This can't really happen - we just allocated 4KB */
12836 if (WARN_ON(!hdr)) {
12837 err = -ENOMEM;
12838 goto out;
12839 }
12840
12841 err = rdev_add_nan_func(rdev, wdev, func);
12842out:
12843 if (err < 0) {
12844 cfg80211_free_nan_func(func);
12845 nlmsg_free(msg);
12846 return err;
12847 }
12848
12849 /* propagate the instance id and cookie to userspace */
12850 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, func->cookie,
12851 NL80211_ATTR_PAD))
12852 goto nla_put_failure;
12853
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012854 func_attr = nla_nest_start_noflag(msg, NL80211_ATTR_NAN_FUNC);
Ayala Bekera442b762016-09-20 17:31:15 +030012855 if (!func_attr)
12856 goto nla_put_failure;
12857
12858 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID,
12859 func->instance_id))
12860 goto nla_put_failure;
12861
12862 nla_nest_end(msg, func_attr);
12863
12864 genlmsg_end(msg, hdr);
12865 return genlmsg_reply(msg, info);
12866
12867nla_put_failure:
12868 nlmsg_free(msg);
12869 return -ENOBUFS;
12870}
12871
12872static int nl80211_nan_del_func(struct sk_buff *skb,
12873 struct genl_info *info)
12874{
12875 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12876 struct wireless_dev *wdev = info->user_ptr[1];
12877 u64 cookie;
12878
12879 if (wdev->iftype != NL80211_IFTYPE_NAN)
12880 return -EOPNOTSUPP;
12881
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012882 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030012883 return -ENOTCONN;
12884
12885 if (!info->attrs[NL80211_ATTR_COOKIE])
12886 return -EINVAL;
12887
Ayala Bekera442b762016-09-20 17:31:15 +030012888 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
12889
12890 rdev_del_nan_func(rdev, wdev, cookie);
12891
12892 return 0;
12893}
12894
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030012895static int nl80211_nan_change_config(struct sk_buff *skb,
12896 struct genl_info *info)
12897{
12898 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12899 struct wireless_dev *wdev = info->user_ptr[1];
12900 struct cfg80211_nan_conf conf = {};
12901 u32 changed = 0;
12902
12903 if (wdev->iftype != NL80211_IFTYPE_NAN)
12904 return -EOPNOTSUPP;
12905
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012906 if (!wdev_running(wdev))
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030012907 return -ENOTCONN;
12908
12909 if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
12910 conf.master_pref =
12911 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
12912 if (conf.master_pref <= 1 || conf.master_pref == 255)
12913 return -EINVAL;
12914
12915 changed |= CFG80211_NAN_CONF_CHANGED_PREF;
12916 }
12917
Luca Coelho85859892017-02-08 15:00:34 +020012918 if (info->attrs[NL80211_ATTR_BANDS]) {
12919 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
12920
12921 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
12922 return -EOPNOTSUPP;
12923
12924 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
12925 return -EINVAL;
12926
12927 conf.bands = bands;
12928 changed |= CFG80211_NAN_CONF_CHANGED_BANDS;
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030012929 }
12930
12931 if (!changed)
12932 return -EINVAL;
12933
12934 return rdev_nan_change_conf(rdev, wdev, &conf, changed);
12935}
12936
Ayala Beker50bcd312016-09-20 17:31:17 +030012937void cfg80211_nan_match(struct wireless_dev *wdev,
12938 struct cfg80211_nan_match_params *match, gfp_t gfp)
12939{
12940 struct wiphy *wiphy = wdev->wiphy;
12941 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
12942 struct nlattr *match_attr, *local_func_attr, *peer_func_attr;
12943 struct sk_buff *msg;
12944 void *hdr;
12945
12946 if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr))
12947 return;
12948
12949 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
12950 if (!msg)
12951 return;
12952
12953 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH);
12954 if (!hdr) {
12955 nlmsg_free(msg);
12956 return;
12957 }
12958
12959 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
12960 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
12961 wdev->netdev->ifindex)) ||
12962 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
12963 NL80211_ATTR_PAD))
12964 goto nla_put_failure;
12965
12966 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie,
12967 NL80211_ATTR_PAD) ||
12968 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr))
12969 goto nla_put_failure;
12970
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012971 match_attr = nla_nest_start_noflag(msg, NL80211_ATTR_NAN_MATCH);
Ayala Beker50bcd312016-09-20 17:31:17 +030012972 if (!match_attr)
12973 goto nla_put_failure;
12974
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012975 local_func_attr = nla_nest_start_noflag(msg,
12976 NL80211_NAN_MATCH_FUNC_LOCAL);
Ayala Beker50bcd312016-09-20 17:31:17 +030012977 if (!local_func_attr)
12978 goto nla_put_failure;
12979
12980 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id))
12981 goto nla_put_failure;
12982
12983 nla_nest_end(msg, local_func_attr);
12984
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012985 peer_func_attr = nla_nest_start_noflag(msg,
12986 NL80211_NAN_MATCH_FUNC_PEER);
Ayala Beker50bcd312016-09-20 17:31:17 +030012987 if (!peer_func_attr)
12988 goto nla_put_failure;
12989
12990 if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) ||
12991 nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id))
12992 goto nla_put_failure;
12993
12994 if (match->info && match->info_len &&
12995 nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len,
12996 match->info))
12997 goto nla_put_failure;
12998
12999 nla_nest_end(msg, peer_func_attr);
13000 nla_nest_end(msg, match_attr);
13001 genlmsg_end(msg, hdr);
13002
13003 if (!wdev->owner_nlportid)
13004 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
13005 msg, 0, NL80211_MCGRP_NAN, gfp);
13006 else
13007 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
13008 wdev->owner_nlportid);
13009
13010 return;
13011
13012nla_put_failure:
13013 nlmsg_free(msg);
13014}
13015EXPORT_SYMBOL(cfg80211_nan_match);
13016
Ayala Beker368e5a72016-09-20 17:31:18 +030013017void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
13018 u8 inst_id,
13019 enum nl80211_nan_func_term_reason reason,
13020 u64 cookie, gfp_t gfp)
13021{
13022 struct wiphy *wiphy = wdev->wiphy;
13023 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
13024 struct sk_buff *msg;
13025 struct nlattr *func_attr;
13026 void *hdr;
13027
13028 if (WARN_ON(!inst_id))
13029 return;
13030
13031 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
13032 if (!msg)
13033 return;
13034
13035 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_NAN_FUNCTION);
13036 if (!hdr) {
13037 nlmsg_free(msg);
13038 return;
13039 }
13040
13041 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13042 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13043 wdev->netdev->ifindex)) ||
13044 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13045 NL80211_ATTR_PAD))
13046 goto nla_put_failure;
13047
13048 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
13049 NL80211_ATTR_PAD))
13050 goto nla_put_failure;
13051
Michal Kubecekae0be8d2019-04-26 11:13:06 +020013052 func_attr = nla_nest_start_noflag(msg, NL80211_ATTR_NAN_FUNC);
Ayala Beker368e5a72016-09-20 17:31:18 +030013053 if (!func_attr)
13054 goto nla_put_failure;
13055
13056 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, inst_id) ||
13057 nla_put_u8(msg, NL80211_NAN_FUNC_TERM_REASON, reason))
13058 goto nla_put_failure;
13059
13060 nla_nest_end(msg, func_attr);
13061 genlmsg_end(msg, hdr);
13062
13063 if (!wdev->owner_nlportid)
13064 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
13065 msg, 0, NL80211_MCGRP_NAN, gfp);
13066 else
13067 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
13068 wdev->owner_nlportid);
13069
13070 return;
13071
13072nla_put_failure:
13073 nlmsg_free(msg);
13074}
13075EXPORT_SYMBOL(cfg80211_nan_func_terminated);
13076
Johannes Berg3713b4e2013-02-14 16:19:38 +010013077static int nl80211_get_protocol_features(struct sk_buff *skb,
13078 struct genl_info *info)
13079{
13080 void *hdr;
13081 struct sk_buff *msg;
13082
13083 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13084 if (!msg)
13085 return -ENOMEM;
13086
13087 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
13088 NL80211_CMD_GET_PROTOCOL_FEATURES);
13089 if (!hdr)
13090 goto nla_put_failure;
13091
13092 if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
13093 NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
13094 goto nla_put_failure;
13095
13096 genlmsg_end(msg, hdr);
13097 return genlmsg_reply(msg, info);
13098
13099 nla_put_failure:
13100 kfree_skb(msg);
13101 return -ENOBUFS;
13102}
13103
Jouni Malinen355199e2013-02-27 17:14:27 +020013104static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
13105{
13106 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13107 struct cfg80211_update_ft_ies_params ft_params;
13108 struct net_device *dev = info->user_ptr[1];
13109
13110 if (!rdev->ops->update_ft_ies)
13111 return -EOPNOTSUPP;
13112
13113 if (!info->attrs[NL80211_ATTR_MDID] ||
Johannes Berg3d7af872018-10-02 10:00:08 +020013114 !info->attrs[NL80211_ATTR_IE])
Jouni Malinen355199e2013-02-27 17:14:27 +020013115 return -EINVAL;
13116
13117 memset(&ft_params, 0, sizeof(ft_params));
13118 ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
13119 ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
13120 ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
13121
13122 return rdev_update_ft_ies(rdev, dev, &ft_params);
13123}
13124
Arend van Spriel5de17982013-04-18 15:49:00 +020013125static int nl80211_crit_protocol_start(struct sk_buff *skb,
13126 struct genl_info *info)
13127{
13128 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13129 struct wireless_dev *wdev = info->user_ptr[1];
13130 enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
13131 u16 duration;
13132 int ret;
13133
13134 if (!rdev->ops->crit_proto_start)
13135 return -EOPNOTSUPP;
13136
13137 if (WARN_ON(!rdev->ops->crit_proto_stop))
13138 return -EINVAL;
13139
13140 if (rdev->crit_proto_nlportid)
13141 return -EBUSY;
13142
13143 /* determine protocol if provided */
13144 if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
13145 proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
13146
13147 if (proto >= NUM_NL80211_CRIT_PROTO)
13148 return -EINVAL;
13149
13150 /* timeout must be provided */
13151 if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
13152 return -EINVAL;
13153
13154 duration =
13155 nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
13156
Arend van Spriel5de17982013-04-18 15:49:00 +020013157 ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
13158 if (!ret)
13159 rdev->crit_proto_nlportid = info->snd_portid;
13160
13161 return ret;
13162}
13163
13164static int nl80211_crit_protocol_stop(struct sk_buff *skb,
13165 struct genl_info *info)
13166{
13167 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13168 struct wireless_dev *wdev = info->user_ptr[1];
13169
13170 if (!rdev->ops->crit_proto_stop)
13171 return -EOPNOTSUPP;
13172
13173 if (rdev->crit_proto_nlportid) {
13174 rdev->crit_proto_nlportid = 0;
13175 rdev_crit_proto_stop(rdev, wdev);
13176 }
13177 return 0;
13178}
13179
Johannes Berg901bb982019-05-28 10:56:03 +020013180static int nl80211_vendor_check_policy(const struct wiphy_vendor_command *vcmd,
13181 struct nlattr *attr,
13182 struct netlink_ext_ack *extack)
13183{
13184 if (vcmd->policy == VENDOR_CMD_RAW_DATA) {
13185 if (attr->nla_type & NLA_F_NESTED) {
13186 NL_SET_ERR_MSG_ATTR(extack, attr,
13187 "unexpected nested data");
13188 return -EINVAL;
13189 }
13190
13191 return 0;
13192 }
13193
13194 if (!(attr->nla_type & NLA_F_NESTED)) {
13195 NL_SET_ERR_MSG_ATTR(extack, attr, "expected nested data");
13196 return -EINVAL;
13197 }
13198
Michal Kubecek32d51092019-12-11 10:58:19 +010013199 return nla_validate_nested(attr, vcmd->maxattr, vcmd->policy, extack);
Johannes Berg901bb982019-05-28 10:56:03 +020013200}
13201
Johannes Bergad7e7182013-11-13 13:37:47 +010013202static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
13203{
13204 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13205 struct wireless_dev *wdev =
13206 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
13207 int i, err;
13208 u32 vid, subcmd;
13209
13210 if (!rdev->wiphy.vendor_commands)
13211 return -EOPNOTSUPP;
13212
13213 if (IS_ERR(wdev)) {
13214 err = PTR_ERR(wdev);
13215 if (err != -EINVAL)
13216 return err;
13217 wdev = NULL;
13218 } else if (wdev->wiphy != &rdev->wiphy) {
13219 return -EINVAL;
13220 }
13221
13222 if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
13223 !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
13224 return -EINVAL;
13225
13226 vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
13227 subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
13228 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
13229 const struct wiphy_vendor_command *vcmd;
13230 void *data = NULL;
13231 int len = 0;
13232
13233 vcmd = &rdev->wiphy.vendor_commands[i];
13234
13235 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
13236 continue;
13237
13238 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
13239 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
13240 if (!wdev)
13241 return -EINVAL;
13242 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
13243 !wdev->netdev)
13244 return -EINVAL;
13245
13246 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Arend Van Spriel73c7da32016-10-20 20:08:22 +010013247 if (!wdev_running(wdev))
Johannes Bergad7e7182013-11-13 13:37:47 +010013248 return -ENETDOWN;
13249 }
13250 } else {
13251 wdev = NULL;
13252 }
13253
Julian Squires4052d3d2020-07-06 17:13:53 -040013254 if (!vcmd->doit)
13255 return -EOPNOTSUPP;
13256
Johannes Bergad7e7182013-11-13 13:37:47 +010013257 if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
13258 data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
13259 len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
Johannes Berg901bb982019-05-28 10:56:03 +020013260
13261 err = nl80211_vendor_check_policy(vcmd,
13262 info->attrs[NL80211_ATTR_VENDOR_DATA],
13263 info->extack);
13264 if (err)
13265 return err;
Johannes Bergad7e7182013-11-13 13:37:47 +010013266 }
13267
13268 rdev->cur_cmd_info = info;
Johannes Berg901bb982019-05-28 10:56:03 +020013269 err = vcmd->doit(&rdev->wiphy, wdev, data, len);
Johannes Bergad7e7182013-11-13 13:37:47 +010013270 rdev->cur_cmd_info = NULL;
13271 return err;
13272 }
13273
13274 return -EOPNOTSUPP;
13275}
13276
Johannes Berg7bdbe402015-08-15 22:39:49 +030013277static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
13278 struct netlink_callback *cb,
13279 struct cfg80211_registered_device **rdev,
13280 struct wireless_dev **wdev)
13281{
Johannes Berg50508d92019-07-29 16:31:09 +020013282 struct nlattr **attrbuf;
Johannes Berg7bdbe402015-08-15 22:39:49 +030013283 u32 vid, subcmd;
13284 unsigned int i;
13285 int vcmd_idx = -1;
13286 int err;
13287 void *data = NULL;
13288 unsigned int data_len = 0;
13289
Johannes Berg7bdbe402015-08-15 22:39:49 +030013290 if (cb->args[0]) {
13291 /* subtract the 1 again here */
13292 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
13293 struct wireless_dev *tmp;
13294
Johannes Bergea90e0d2017-03-15 14:26:04 +010013295 if (!wiphy)
13296 return -ENODEV;
Johannes Berg7bdbe402015-08-15 22:39:49 +030013297 *rdev = wiphy_to_rdev(wiphy);
13298 *wdev = NULL;
13299
13300 if (cb->args[1]) {
Johannes Berg53873f12016-05-03 16:52:04 +030013301 list_for_each_entry(tmp, &wiphy->wdev_list, list) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030013302 if (tmp->identifier == cb->args[1] - 1) {
13303 *wdev = tmp;
13304 break;
13305 }
13306 }
13307 }
13308
13309 /* keep rtnl locked in successful case */
13310 return 0;
13311 }
13312
Johannes Berg50508d92019-07-29 16:31:09 +020013313 attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
13314 if (!attrbuf)
13315 return -ENOMEM;
13316
Johannes Berg8cb08172019-04-26 14:07:28 +020013317 err = nlmsg_parse_deprecated(cb->nlh,
13318 GENL_HDRLEN + nl80211_fam.hdrsize,
13319 attrbuf, nl80211_fam.maxattr,
13320 nl80211_policy, NULL);
Johannes Berg7bdbe402015-08-15 22:39:49 +030013321 if (err)
Johannes Berg50508d92019-07-29 16:31:09 +020013322 goto out;
Johannes Berg7bdbe402015-08-15 22:39:49 +030013323
Johannes Bergc90c39d2016-10-24 14:40:01 +020013324 if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
Johannes Berg50508d92019-07-29 16:31:09 +020013325 !attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
13326 err = -EINVAL;
13327 goto out;
13328 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030013329
Johannes Bergc90c39d2016-10-24 14:40:01 +020013330 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg7bdbe402015-08-15 22:39:49 +030013331 if (IS_ERR(*wdev))
13332 *wdev = NULL;
13333
Johannes Bergc90c39d2016-10-24 14:40:01 +020013334 *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg50508d92019-07-29 16:31:09 +020013335 if (IS_ERR(*rdev)) {
13336 err = PTR_ERR(*rdev);
13337 goto out;
13338 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030013339
Johannes Bergc90c39d2016-10-24 14:40:01 +020013340 vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
13341 subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030013342
13343 for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
13344 const struct wiphy_vendor_command *vcmd;
13345
13346 vcmd = &(*rdev)->wiphy.vendor_commands[i];
13347
13348 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
13349 continue;
13350
Johannes Berg50508d92019-07-29 16:31:09 +020013351 if (!vcmd->dumpit) {
13352 err = -EOPNOTSUPP;
13353 goto out;
13354 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030013355
13356 vcmd_idx = i;
13357 break;
13358 }
13359
Johannes Berg50508d92019-07-29 16:31:09 +020013360 if (vcmd_idx < 0) {
13361 err = -EOPNOTSUPP;
13362 goto out;
13363 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030013364
Johannes Bergc90c39d2016-10-24 14:40:01 +020013365 if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
13366 data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
13367 data_len = nla_len(attrbuf[NL80211_ATTR_VENDOR_DATA]);
Johannes Berg901bb982019-05-28 10:56:03 +020013368
13369 err = nl80211_vendor_check_policy(
13370 &(*rdev)->wiphy.vendor_commands[vcmd_idx],
13371 attrbuf[NL80211_ATTR_VENDOR_DATA],
13372 cb->extack);
13373 if (err)
Johannes Berg50508d92019-07-29 16:31:09 +020013374 goto out;
Johannes Berg7bdbe402015-08-15 22:39:49 +030013375 }
13376
13377 /* 0 is the first index - add 1 to parse only once */
13378 cb->args[0] = (*rdev)->wiphy_idx + 1;
13379 /* add 1 to know if it was NULL */
13380 cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
13381 cb->args[2] = vcmd_idx;
13382 cb->args[3] = (unsigned long)data;
13383 cb->args[4] = data_len;
13384
13385 /* keep rtnl locked in successful case */
Johannes Berg50508d92019-07-29 16:31:09 +020013386 err = 0;
13387out:
13388 kfree(attrbuf);
13389 return err;
Johannes Berg7bdbe402015-08-15 22:39:49 +030013390}
13391
13392static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
13393 struct netlink_callback *cb)
13394{
13395 struct cfg80211_registered_device *rdev;
13396 struct wireless_dev *wdev;
13397 unsigned int vcmd_idx;
13398 const struct wiphy_vendor_command *vcmd;
13399 void *data;
13400 int data_len;
13401 int err;
13402 struct nlattr *vendor_data;
13403
Johannes Bergea90e0d2017-03-15 14:26:04 +010013404 rtnl_lock();
Johannes Berg7bdbe402015-08-15 22:39:49 +030013405 err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
13406 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +010013407 goto out;
Johannes Berg7bdbe402015-08-15 22:39:49 +030013408
13409 vcmd_idx = cb->args[2];
13410 data = (void *)cb->args[3];
13411 data_len = cb->args[4];
13412 vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
13413
13414 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
13415 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
Johannes Bergea90e0d2017-03-15 14:26:04 +010013416 if (!wdev) {
13417 err = -EINVAL;
13418 goto out;
13419 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030013420 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
Johannes Bergea90e0d2017-03-15 14:26:04 +010013421 !wdev->netdev) {
13422 err = -EINVAL;
13423 goto out;
13424 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030013425
13426 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Johannes Bergea90e0d2017-03-15 14:26:04 +010013427 if (!wdev_running(wdev)) {
13428 err = -ENETDOWN;
13429 goto out;
13430 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030013431 }
13432 }
13433
13434 while (1) {
13435 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
13436 cb->nlh->nlmsg_seq, NLM_F_MULTI,
13437 NL80211_CMD_VENDOR);
13438 if (!hdr)
13439 break;
13440
13441 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013442 (wdev && nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
13443 wdev_id(wdev),
13444 NL80211_ATTR_PAD))) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030013445 genlmsg_cancel(skb, hdr);
13446 break;
13447 }
13448
Michal Kubecekae0be8d2019-04-26 11:13:06 +020013449 vendor_data = nla_nest_start_noflag(skb,
13450 NL80211_ATTR_VENDOR_DATA);
Johannes Berg7bdbe402015-08-15 22:39:49 +030013451 if (!vendor_data) {
13452 genlmsg_cancel(skb, hdr);
13453 break;
13454 }
13455
13456 err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
13457 (unsigned long *)&cb->args[5]);
13458 nla_nest_end(skb, vendor_data);
13459
13460 if (err == -ENOBUFS || err == -ENOENT) {
13461 genlmsg_cancel(skb, hdr);
13462 break;
Julian Squires9c167b22020-07-20 12:20:35 -023013463 } else if (err <= 0) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030013464 genlmsg_cancel(skb, hdr);
13465 goto out;
13466 }
13467
13468 genlmsg_end(skb, hdr);
13469 }
13470
13471 err = skb->len;
13472 out:
13473 rtnl_unlock();
13474 return err;
13475}
13476
Johannes Bergad7e7182013-11-13 13:37:47 +010013477struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
13478 enum nl80211_commands cmd,
13479 enum nl80211_attrs attr,
13480 int approxlen)
13481{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013482 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Bergad7e7182013-11-13 13:37:47 +010013483
13484 if (WARN_ON(!rdev->cur_cmd_info))
13485 return NULL;
13486
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020013487 return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
Johannes Bergad7e7182013-11-13 13:37:47 +010013488 rdev->cur_cmd_info->snd_portid,
13489 rdev->cur_cmd_info->snd_seq,
Johannes Berg567ffc32013-12-18 14:43:31 +010013490 cmd, attr, NULL, GFP_KERNEL);
Johannes Bergad7e7182013-11-13 13:37:47 +010013491}
13492EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
13493
13494int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
13495{
13496 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
13497 void *hdr = ((void **)skb->cb)[1];
13498 struct nlattr *data = ((void **)skb->cb)[2];
13499
Johannes Bergbd8c78e2014-07-30 14:55:26 +020013500 /* clear CB data for netlink core to own from now on */
13501 memset(skb->cb, 0, sizeof(skb->cb));
13502
Johannes Bergad7e7182013-11-13 13:37:47 +010013503 if (WARN_ON(!rdev->cur_cmd_info)) {
13504 kfree_skb(skb);
13505 return -EINVAL;
13506 }
13507
13508 nla_nest_end(skb, data);
13509 genlmsg_end(skb, hdr);
13510 return genlmsg_reply(skb, rdev->cur_cmd_info);
13511}
13512EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
13513
Johannes Berg55c1fdf2019-02-06 13:17:19 +020013514unsigned int cfg80211_vendor_cmd_get_sender(struct wiphy *wiphy)
13515{
13516 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
13517
13518 if (WARN_ON(!rdev->cur_cmd_info))
13519 return 0;
13520
13521 return rdev->cur_cmd_info->snd_portid;
13522}
13523EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_get_sender);
13524
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080013525static int nl80211_set_qos_map(struct sk_buff *skb,
13526 struct genl_info *info)
13527{
13528 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13529 struct cfg80211_qos_map *qos_map = NULL;
13530 struct net_device *dev = info->user_ptr[1];
13531 u8 *pos, len, num_des, des_len, des;
13532 int ret;
13533
13534 if (!rdev->ops->set_qos_map)
13535 return -EOPNOTSUPP;
13536
13537 if (info->attrs[NL80211_ATTR_QOS_MAP]) {
13538 pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
13539 len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
13540
Johannes Bergc8b82802020-08-19 08:56:43 +020013541 if (len % 2)
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080013542 return -EINVAL;
13543
13544 qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
13545 if (!qos_map)
13546 return -ENOMEM;
13547
13548 num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
13549 if (num_des) {
13550 des_len = num_des *
13551 sizeof(struct cfg80211_dscp_exception);
13552 memcpy(qos_map->dscp_exception, pos, des_len);
13553 qos_map->num_des = num_des;
13554 for (des = 0; des < num_des; des++) {
13555 if (qos_map->dscp_exception[des].up > 7) {
13556 kfree(qos_map);
13557 return -EINVAL;
13558 }
13559 }
13560 pos += des_len;
13561 }
13562 memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
13563 }
13564
13565 wdev_lock(dev->ieee80211_ptr);
13566 ret = nl80211_key_allowed(dev->ieee80211_ptr);
13567 if (!ret)
13568 ret = rdev_set_qos_map(rdev, dev, qos_map);
13569 wdev_unlock(dev->ieee80211_ptr);
13570
13571 kfree(qos_map);
13572 return ret;
13573}
13574
Johannes Berg960d01a2014-09-09 22:55:35 +030013575static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
13576{
13577 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13578 struct net_device *dev = info->user_ptr[1];
13579 struct wireless_dev *wdev = dev->ieee80211_ptr;
13580 const u8 *peer;
13581 u8 tsid, up;
13582 u16 admitted_time = 0;
13583 int err;
13584
Johannes Berg723e73a2014-10-22 09:25:06 +020013585 if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
Johannes Berg960d01a2014-09-09 22:55:35 +030013586 return -EOPNOTSUPP;
13587
13588 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
13589 !info->attrs[NL80211_ATTR_USER_PRIO])
13590 return -EINVAL;
13591
13592 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
Johannes Berg960d01a2014-09-09 22:55:35 +030013593 up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
Johannes Berg960d01a2014-09-09 22:55:35 +030013594
13595 /* WMM uses TIDs 0-7 even for TSPEC */
Johannes Berg723e73a2014-10-22 09:25:06 +020013596 if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
Johannes Berg960d01a2014-09-09 22:55:35 +030013597 /* TODO: handle 802.11 TSPEC/admission control
Johannes Berg723e73a2014-10-22 09:25:06 +020013598 * need more attributes for that (e.g. BA session requirement);
13599 * change the WMM adminssion test above to allow both then
Johannes Berg960d01a2014-09-09 22:55:35 +030013600 */
13601 return -EINVAL;
13602 }
13603
13604 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
13605
13606 if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
13607 admitted_time =
13608 nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
13609 if (!admitted_time)
13610 return -EINVAL;
13611 }
13612
13613 wdev_lock(wdev);
13614 switch (wdev->iftype) {
13615 case NL80211_IFTYPE_STATION:
13616 case NL80211_IFTYPE_P2P_CLIENT:
13617 if (wdev->current_bss)
13618 break;
13619 err = -ENOTCONN;
13620 goto out;
13621 default:
13622 err = -EOPNOTSUPP;
13623 goto out;
13624 }
13625
13626 err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
13627
13628 out:
13629 wdev_unlock(wdev);
13630 return err;
13631}
13632
13633static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
13634{
13635 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13636 struct net_device *dev = info->user_ptr[1];
13637 struct wireless_dev *wdev = dev->ieee80211_ptr;
13638 const u8 *peer;
13639 u8 tsid;
13640 int err;
13641
13642 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
13643 return -EINVAL;
13644
13645 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
13646 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
13647
13648 wdev_lock(wdev);
13649 err = rdev_del_tx_ts(rdev, dev, tsid, peer);
13650 wdev_unlock(wdev);
13651
13652 return err;
13653}
13654
Arik Nemtsov1057d352014-11-19 12:54:26 +020013655static int nl80211_tdls_channel_switch(struct sk_buff *skb,
13656 struct genl_info *info)
13657{
13658 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13659 struct net_device *dev = info->user_ptr[1];
13660 struct wireless_dev *wdev = dev->ieee80211_ptr;
13661 struct cfg80211_chan_def chandef = {};
13662 const u8 *addr;
13663 u8 oper_class;
13664 int err;
13665
13666 if (!rdev->ops->tdls_channel_switch ||
13667 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
13668 return -EOPNOTSUPP;
13669
13670 switch (dev->ieee80211_ptr->iftype) {
13671 case NL80211_IFTYPE_STATION:
13672 case NL80211_IFTYPE_P2P_CLIENT:
13673 break;
13674 default:
13675 return -EOPNOTSUPP;
13676 }
13677
13678 if (!info->attrs[NL80211_ATTR_MAC] ||
13679 !info->attrs[NL80211_ATTR_OPER_CLASS])
13680 return -EINVAL;
13681
13682 err = nl80211_parse_chandef(rdev, info, &chandef);
13683 if (err)
13684 return err;
13685
13686 /*
13687 * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012
13688 * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the
13689 * specification is not defined for them.
13690 */
Johannes Berg57fbcce2016-04-12 15:56:15 +020013691 if (chandef.chan->band == NL80211_BAND_2GHZ &&
Arik Nemtsov1057d352014-11-19 12:54:26 +020013692 chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
13693 chandef.width != NL80211_CHAN_WIDTH_20)
13694 return -EINVAL;
13695
13696 /* we will be active on the TDLS link */
Arik Nemtsov923b3522015-07-08 15:41:44 +030013697 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
13698 wdev->iftype))
Arik Nemtsov1057d352014-11-19 12:54:26 +020013699 return -EINVAL;
13700
13701 /* don't allow switching to DFS channels */
13702 if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype))
13703 return -EINVAL;
13704
13705 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
13706 oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]);
13707
13708 wdev_lock(wdev);
13709 err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef);
13710 wdev_unlock(wdev);
13711
13712 return err;
13713}
13714
13715static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
13716 struct genl_info *info)
13717{
13718 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13719 struct net_device *dev = info->user_ptr[1];
13720 struct wireless_dev *wdev = dev->ieee80211_ptr;
13721 const u8 *addr;
13722
13723 if (!rdev->ops->tdls_channel_switch ||
13724 !rdev->ops->tdls_cancel_channel_switch ||
13725 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
13726 return -EOPNOTSUPP;
13727
13728 switch (dev->ieee80211_ptr->iftype) {
13729 case NL80211_IFTYPE_STATION:
13730 case NL80211_IFTYPE_P2P_CLIENT:
13731 break;
13732 default:
13733 return -EOPNOTSUPP;
13734 }
13735
13736 if (!info->attrs[NL80211_ATTR_MAC])
13737 return -EINVAL;
13738
13739 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
13740
13741 wdev_lock(wdev);
13742 rdev_tdls_cancel_channel_switch(rdev, dev, addr);
13743 wdev_unlock(wdev);
13744
13745 return 0;
13746}
13747
Michael Braunce0ce132016-10-10 19:12:22 +020013748static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
13749 struct genl_info *info)
13750{
13751 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13752 struct net_device *dev = info->user_ptr[1];
13753 struct wireless_dev *wdev = dev->ieee80211_ptr;
13754 const struct nlattr *nla;
13755 bool enabled;
13756
Michael Braunce0ce132016-10-10 19:12:22 +020013757 if (!rdev->ops->set_multicast_to_unicast)
13758 return -EOPNOTSUPP;
13759
13760 if (wdev->iftype != NL80211_IFTYPE_AP &&
13761 wdev->iftype != NL80211_IFTYPE_P2P_GO)
13762 return -EOPNOTSUPP;
13763
13764 nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
13765 enabled = nla_get_flag(nla);
13766
13767 return rdev_set_multicast_to_unicast(rdev, dev, enabled);
13768}
13769
Avraham Stern3a00df52017-06-09 13:08:43 +010013770static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
13771{
13772 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13773 struct net_device *dev = info->user_ptr[1];
13774 struct wireless_dev *wdev = dev->ieee80211_ptr;
13775 struct cfg80211_pmk_conf pmk_conf = {};
13776 int ret;
13777
13778 if (wdev->iftype != NL80211_IFTYPE_STATION &&
13779 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
13780 return -EOPNOTSUPP;
13781
13782 if (!wiphy_ext_feature_isset(&rdev->wiphy,
13783 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
13784 return -EOPNOTSUPP;
13785
13786 if (!info->attrs[NL80211_ATTR_MAC] || !info->attrs[NL80211_ATTR_PMK])
13787 return -EINVAL;
13788
13789 wdev_lock(wdev);
13790 if (!wdev->current_bss) {
13791 ret = -ENOTCONN;
13792 goto out;
13793 }
13794
13795 pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
13796 if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) {
13797 ret = -EINVAL;
13798 goto out;
13799 }
13800
13801 pmk_conf.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
13802 pmk_conf.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
13803 if (pmk_conf.pmk_len != WLAN_PMK_LEN &&
13804 pmk_conf.pmk_len != WLAN_PMK_LEN_SUITE_B_192) {
13805 ret = -EINVAL;
13806 goto out;
13807 }
13808
Johannes Bergcb9abd42020-08-05 15:47:16 +020013809 if (info->attrs[NL80211_ATTR_PMKR0_NAME])
Avraham Stern3a00df52017-06-09 13:08:43 +010013810 pmk_conf.pmk_r0_name =
13811 nla_data(info->attrs[NL80211_ATTR_PMKR0_NAME]);
Avraham Stern3a00df52017-06-09 13:08:43 +010013812
13813 ret = rdev_set_pmk(rdev, dev, &pmk_conf);
13814out:
13815 wdev_unlock(wdev);
13816 return ret;
13817}
13818
13819static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
13820{
13821 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13822 struct net_device *dev = info->user_ptr[1];
13823 struct wireless_dev *wdev = dev->ieee80211_ptr;
13824 const u8 *aa;
13825 int ret;
13826
13827 if (wdev->iftype != NL80211_IFTYPE_STATION &&
13828 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
13829 return -EOPNOTSUPP;
13830
13831 if (!wiphy_ext_feature_isset(&rdev->wiphy,
13832 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
13833 return -EOPNOTSUPP;
13834
13835 if (!info->attrs[NL80211_ATTR_MAC])
13836 return -EINVAL;
13837
13838 wdev_lock(wdev);
13839 aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
13840 ret = rdev_del_pmk(rdev, dev, aa);
13841 wdev_unlock(wdev);
13842
13843 return ret;
13844}
13845
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020013846static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info)
13847{
13848 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13849 struct net_device *dev = info->user_ptr[1];
13850 struct cfg80211_external_auth_params params;
13851
Srinivas Dasaridb8d93a2018-02-02 11:15:27 +020013852 if (!rdev->ops->external_auth)
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020013853 return -EOPNOTSUPP;
13854
Srinivas Dasarife494372019-01-23 18:06:56 +053013855 if (!info->attrs[NL80211_ATTR_SSID] &&
13856 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
13857 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020013858 return -EINVAL;
13859
13860 if (!info->attrs[NL80211_ATTR_BSSID])
13861 return -EINVAL;
13862
13863 if (!info->attrs[NL80211_ATTR_STATUS_CODE])
13864 return -EINVAL;
13865
13866 memset(&params, 0, sizeof(params));
13867
Srinivas Dasarife494372019-01-23 18:06:56 +053013868 if (info->attrs[NL80211_ATTR_SSID]) {
13869 params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
Johannes Bergcb9abd42020-08-05 15:47:16 +020013870 if (params.ssid.ssid_len == 0)
Srinivas Dasarife494372019-01-23 18:06:56 +053013871 return -EINVAL;
13872 memcpy(params.ssid.ssid,
13873 nla_data(info->attrs[NL80211_ATTR_SSID]),
13874 params.ssid.ssid_len);
13875 }
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020013876
13877 memcpy(params.bssid, nla_data(info->attrs[NL80211_ATTR_BSSID]),
13878 ETH_ALEN);
13879
13880 params.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
13881
Srinivas Dasarife494372019-01-23 18:06:56 +053013882 if (info->attrs[NL80211_ATTR_PMKID])
13883 params.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
13884
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020013885 return rdev_external_auth(rdev, dev, &params);
13886}
13887
Denis Kenzior2576a9a2018-03-26 12:52:42 -050013888static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
13889{
Markus Theildca9ca22020-05-08 16:42:00 +020013890 bool dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
Denis Kenzior2576a9a2018-03-26 12:52:42 -050013891 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13892 struct net_device *dev = info->user_ptr[1];
13893 struct wireless_dev *wdev = dev->ieee80211_ptr;
13894 const u8 *buf;
13895 size_t len;
13896 u8 *dest;
13897 u16 proto;
13898 bool noencrypt;
Markus Theildca9ca22020-05-08 16:42:00 +020013899 u64 cookie = 0;
Denis Kenzior2576a9a2018-03-26 12:52:42 -050013900 int err;
13901
13902 if (!wiphy_ext_feature_isset(&rdev->wiphy,
13903 NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
13904 return -EOPNOTSUPP;
13905
13906 if (!rdev->ops->tx_control_port)
13907 return -EOPNOTSUPP;
13908
13909 if (!info->attrs[NL80211_ATTR_FRAME] ||
13910 !info->attrs[NL80211_ATTR_MAC] ||
13911 !info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
13912 GENL_SET_ERR_MSG(info, "Frame, MAC or ethertype missing");
13913 return -EINVAL;
13914 }
13915
13916 wdev_lock(wdev);
13917
13918 switch (wdev->iftype) {
13919 case NL80211_IFTYPE_AP:
13920 case NL80211_IFTYPE_P2P_GO:
13921 case NL80211_IFTYPE_MESH_POINT:
13922 break;
13923 case NL80211_IFTYPE_ADHOC:
13924 case NL80211_IFTYPE_STATION:
13925 case NL80211_IFTYPE_P2P_CLIENT:
13926 if (wdev->current_bss)
13927 break;
13928 err = -ENOTCONN;
13929 goto out;
13930 default:
13931 err = -EOPNOTSUPP;
13932 goto out;
13933 }
13934
13935 wdev_unlock(wdev);
13936
13937 buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
13938 len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
13939 dest = nla_data(info->attrs[NL80211_ATTR_MAC]);
13940 proto = nla_get_u16(info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
13941 noencrypt =
13942 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);
13943
Markus Theildca9ca22020-05-08 16:42:00 +020013944 err = rdev_tx_control_port(rdev, dev, buf, len,
13945 dest, cpu_to_be16(proto), noencrypt,
13946 dont_wait_for_ack ? NULL : &cookie);
13947 if (!err && !dont_wait_for_ack)
13948 nl_set_extack_cookie_u64(info->extack, cookie);
13949 return err;
Denis Kenzior2576a9a2018-03-26 12:52:42 -050013950 out:
13951 wdev_unlock(wdev);
13952 return err;
13953}
13954
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070013955static int nl80211_get_ftm_responder_stats(struct sk_buff *skb,
13956 struct genl_info *info)
13957{
13958 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13959 struct net_device *dev = info->user_ptr[1];
13960 struct wireless_dev *wdev = dev->ieee80211_ptr;
13961 struct cfg80211_ftm_responder_stats ftm_stats = {};
13962 struct sk_buff *msg;
13963 void *hdr;
13964 struct nlattr *ftm_stats_attr;
13965 int err;
13966
13967 if (wdev->iftype != NL80211_IFTYPE_AP || !wdev->beacon_interval)
13968 return -EOPNOTSUPP;
13969
13970 err = rdev_get_ftm_responder_stats(rdev, dev, &ftm_stats);
13971 if (err)
13972 return err;
13973
13974 if (!ftm_stats.filled)
13975 return -ENODATA;
13976
13977 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13978 if (!msg)
13979 return -ENOMEM;
13980
13981 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
13982 NL80211_CMD_GET_FTM_RESPONDER_STATS);
13983 if (!hdr)
Navid Emamdoost1399c592019-10-04 14:42:19 -050013984 goto nla_put_failure;
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070013985
13986 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
13987 goto nla_put_failure;
13988
Michal Kubecekae0be8d2019-04-26 11:13:06 +020013989 ftm_stats_attr = nla_nest_start_noflag(msg,
13990 NL80211_ATTR_FTM_RESPONDER_STATS);
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070013991 if (!ftm_stats_attr)
13992 goto nla_put_failure;
13993
13994#define SET_FTM(field, name, type) \
13995 do { if ((ftm_stats.filled & BIT(NL80211_FTM_STATS_ ## name)) && \
13996 nla_put_ ## type(msg, NL80211_FTM_STATS_ ## name, \
13997 ftm_stats.field)) \
13998 goto nla_put_failure; } while (0)
13999#define SET_FTM_U64(field, name) \
14000 do { if ((ftm_stats.filled & BIT(NL80211_FTM_STATS_ ## name)) && \
14001 nla_put_u64_64bit(msg, NL80211_FTM_STATS_ ## name, \
14002 ftm_stats.field, NL80211_FTM_STATS_PAD)) \
14003 goto nla_put_failure; } while (0)
14004
14005 SET_FTM(success_num, SUCCESS_NUM, u32);
14006 SET_FTM(partial_num, PARTIAL_NUM, u32);
14007 SET_FTM(failed_num, FAILED_NUM, u32);
14008 SET_FTM(asap_num, ASAP_NUM, u32);
14009 SET_FTM(non_asap_num, NON_ASAP_NUM, u32);
14010 SET_FTM_U64(total_duration_ms, TOTAL_DURATION_MSEC);
14011 SET_FTM(unknown_triggers_num, UNKNOWN_TRIGGERS_NUM, u32);
14012 SET_FTM(reschedule_requests_num, RESCHEDULE_REQUESTS_NUM, u32);
14013 SET_FTM(out_of_window_triggers_num, OUT_OF_WINDOW_TRIGGERS_NUM, u32);
14014#undef SET_FTM
14015
14016 nla_nest_end(msg, ftm_stats_attr);
14017
14018 genlmsg_end(msg, hdr);
14019 return genlmsg_reply(msg, info);
14020
14021nla_put_failure:
14022 nlmsg_free(msg);
14023 return -ENOBUFS;
14024}
14025
Sunil Duttcb74e972019-02-20 16:18:07 +053014026static int nl80211_update_owe_info(struct sk_buff *skb, struct genl_info *info)
14027{
14028 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14029 struct cfg80211_update_owe_info owe_info;
14030 struct net_device *dev = info->user_ptr[1];
14031
14032 if (!rdev->ops->update_owe_info)
14033 return -EOPNOTSUPP;
14034
14035 if (!info->attrs[NL80211_ATTR_STATUS_CODE] ||
14036 !info->attrs[NL80211_ATTR_MAC])
14037 return -EINVAL;
14038
14039 memset(&owe_info, 0, sizeof(owe_info));
14040 owe_info.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
14041 nla_memcpy(owe_info.peer, info->attrs[NL80211_ATTR_MAC], ETH_ALEN);
14042
14043 if (info->attrs[NL80211_ATTR_IE]) {
14044 owe_info.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
14045 owe_info.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
14046 }
14047
14048 return rdev_update_owe_info(rdev, dev, &owe_info);
14049}
14050
Rajkumar Manoharan5ab92e72019-04-11 13:47:24 -070014051static int nl80211_probe_mesh_link(struct sk_buff *skb, struct genl_info *info)
14052{
14053 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14054 struct net_device *dev = info->user_ptr[1];
14055 struct wireless_dev *wdev = dev->ieee80211_ptr;
14056 struct station_info sinfo = {};
14057 const u8 *buf;
14058 size_t len;
14059 u8 *dest;
14060 int err;
14061
14062 if (!rdev->ops->probe_mesh_link || !rdev->ops->get_station)
14063 return -EOPNOTSUPP;
14064
14065 if (!info->attrs[NL80211_ATTR_MAC] ||
14066 !info->attrs[NL80211_ATTR_FRAME]) {
14067 GENL_SET_ERR_MSG(info, "Frame or MAC missing");
14068 return -EINVAL;
14069 }
14070
14071 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
14072 return -EOPNOTSUPP;
14073
14074 dest = nla_data(info->attrs[NL80211_ATTR_MAC]);
14075 buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
14076 len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
14077
14078 if (len < sizeof(struct ethhdr))
14079 return -EINVAL;
14080
14081 if (!ether_addr_equal(buf, dest) || is_multicast_ether_addr(buf) ||
14082 !ether_addr_equal(buf + ETH_ALEN, dev->dev_addr))
14083 return -EINVAL;
14084
14085 err = rdev_get_station(rdev, dev, dest, &sinfo);
14086 if (err)
14087 return err;
14088
Felix Fietkau2a279b342020-01-08 18:06:29 +010014089 cfg80211_sinfo_release_content(&sinfo);
14090
Rajkumar Manoharan5ab92e72019-04-11 13:47:24 -070014091 return rdev_probe_mesh_link(rdev, dev, dest, buf, len);
14092}
14093
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014094static int parse_tid_conf(struct cfg80211_registered_device *rdev,
14095 struct nlattr *attrs[], struct net_device *dev,
Johannes Berg3710a8a2020-02-24 11:34:25 +010014096 struct cfg80211_tid_cfg *tid_conf,
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014097 struct genl_info *info, const u8 *peer)
14098{
14099 struct netlink_ext_ack *extack = info->extack;
Johannes Berg3710a8a2020-02-24 11:34:25 +010014100 u64 mask;
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014101 int err;
14102
14103 if (!attrs[NL80211_TID_CONFIG_ATTR_TIDS])
14104 return -EINVAL;
14105
14106 tid_conf->config_override =
14107 nla_get_flag(attrs[NL80211_TID_CONFIG_ATTR_OVERRIDE]);
Johannes Berg3710a8a2020-02-24 11:34:25 +010014108 tid_conf->tids = nla_get_u16(attrs[NL80211_TID_CONFIG_ATTR_TIDS]);
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014109
14110 if (tid_conf->config_override) {
14111 if (rdev->ops->reset_tid_config) {
14112 err = rdev_reset_tid_config(rdev, dev, peer,
Johannes Berg3710a8a2020-02-24 11:34:25 +010014113 tid_conf->tids);
Sergey Matyukevichc0336952020-04-24 14:29:04 +030014114 if (err)
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014115 return err;
14116 } else {
14117 return -EINVAL;
14118 }
14119 }
14120
14121 if (attrs[NL80211_TID_CONFIG_ATTR_NOACK]) {
Johannes Berg3710a8a2020-02-24 11:34:25 +010014122 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_NOACK);
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014123 tid_conf->noack =
14124 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_NOACK]);
14125 }
14126
Tamizh chelvam6a21d162020-01-20 13:21:23 +053014127 if (attrs[NL80211_TID_CONFIG_ATTR_RETRY_SHORT]) {
14128 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_RETRY_SHORT);
14129 tid_conf->retry_short =
14130 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_RETRY_SHORT]);
14131
14132 if (tid_conf->retry_short > rdev->wiphy.max_data_retry_count)
14133 return -EINVAL;
14134 }
14135
14136 if (attrs[NL80211_TID_CONFIG_ATTR_RETRY_LONG]) {
14137 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG);
14138 tid_conf->retry_long =
14139 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_RETRY_LONG]);
14140
14141 if (tid_conf->retry_long > rdev->wiphy.max_data_retry_count)
14142 return -EINVAL;
14143 }
14144
Tamizh chelvamade274b2020-01-20 13:21:24 +053014145 if (attrs[NL80211_TID_CONFIG_ATTR_AMPDU_CTRL]) {
14146 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL);
14147 tid_conf->ampdu =
14148 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_AMPDU_CTRL]);
14149 }
14150
Tamizh chelvam04f7d142020-01-20 13:21:25 +053014151 if (attrs[NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL]) {
14152 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL);
14153 tid_conf->rtscts =
14154 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL]);
14155 }
14156
Sergey Matyukevich33462e62020-04-24 14:29:03 +030014157 if (attrs[NL80211_TID_CONFIG_ATTR_AMSDU_CTRL]) {
14158 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_AMSDU_CTRL);
14159 tid_conf->amsdu =
14160 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_AMSDU_CTRL]);
14161 }
14162
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +053014163 if (attrs[NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE]) {
14164 u32 idx = NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE, attr;
14165
14166 tid_conf->txrate_type = nla_get_u8(attrs[idx]);
14167
14168 if (tid_conf->txrate_type != NL80211_TX_RATE_AUTOMATIC) {
14169 attr = NL80211_TID_CONFIG_ATTR_TX_RATE;
14170 err = nl80211_parse_tx_bitrate_mask(info, attrs, attr,
14171 &tid_conf->txrate_mask);
14172 if (err)
14173 return err;
14174
14175 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_TX_RATE);
14176 }
14177 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE);
14178 }
14179
Johannes Berg3710a8a2020-02-24 11:34:25 +010014180 if (peer)
14181 mask = rdev->wiphy.tid_config_support.peer;
14182 else
14183 mask = rdev->wiphy.tid_config_support.vif;
14184
14185 if (tid_conf->mask & ~mask) {
14186 NL_SET_ERR_MSG(extack, "unsupported TID configuration");
14187 return -ENOTSUPP;
14188 }
14189
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014190 return 0;
14191}
14192
14193static int nl80211_set_tid_config(struct sk_buff *skb,
14194 struct genl_info *info)
14195{
14196 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14197 struct nlattr *attrs[NL80211_TID_CONFIG_ATTR_MAX + 1];
14198 struct net_device *dev = info->user_ptr[1];
Johannes Berg3710a8a2020-02-24 11:34:25 +010014199 struct cfg80211_tid_config *tid_config;
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014200 struct nlattr *tid;
14201 int conf_idx = 0, rem_conf;
14202 int ret = -EINVAL;
14203 u32 num_conf = 0;
14204
14205 if (!info->attrs[NL80211_ATTR_TID_CONFIG])
14206 return -EINVAL;
14207
14208 if (!rdev->ops->set_tid_config)
14209 return -EOPNOTSUPP;
14210
14211 nla_for_each_nested(tid, info->attrs[NL80211_ATTR_TID_CONFIG],
14212 rem_conf)
14213 num_conf++;
14214
14215 tid_config = kzalloc(struct_size(tid_config, tid_conf, num_conf),
14216 GFP_KERNEL);
14217 if (!tid_config)
14218 return -ENOMEM;
14219
14220 tid_config->n_tid_conf = num_conf;
14221
14222 if (info->attrs[NL80211_ATTR_MAC])
14223 tid_config->peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
14224
14225 nla_for_each_nested(tid, info->attrs[NL80211_ATTR_TID_CONFIG],
14226 rem_conf) {
14227 ret = nla_parse_nested(attrs, NL80211_TID_CONFIG_ATTR_MAX,
14228 tid, NULL, NULL);
14229
14230 if (ret)
14231 goto bad_tid_conf;
14232
14233 ret = parse_tid_conf(rdev, attrs, dev,
14234 &tid_config->tid_conf[conf_idx],
14235 info, tid_config->peer);
14236 if (ret)
14237 goto bad_tid_conf;
14238
14239 conf_idx++;
14240 }
14241
14242 ret = rdev_set_tid_config(rdev, dev, tid_config);
14243
14244bad_tid_conf:
14245 kfree(tid_config);
14246 return ret;
14247}
14248
Johannes Berg4c476992010-10-04 21:36:35 +020014249#define NL80211_FLAG_NEED_WIPHY 0x01
14250#define NL80211_FLAG_NEED_NETDEV 0x02
14251#define NL80211_FLAG_NEED_RTNL 0x04
Johannes Berg41265712010-10-04 21:14:05 +020014252#define NL80211_FLAG_CHECK_NETDEV_UP 0x08
14253#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
14254 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg1bf614e2012-06-15 15:23:36 +020014255#define NL80211_FLAG_NEED_WDEV 0x10
Johannes Berg98104fde2012-06-16 00:19:54 +020014256/* If a netdev is associated, it must be UP, P2P must be started */
Johannes Berg1bf614e2012-06-15 15:23:36 +020014257#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
14258 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg5393b912014-09-10 15:00:16 +030014259#define NL80211_FLAG_CLEAR_SKB 0x20
Johannes Berg4c476992010-10-04 21:36:35 +020014260
Johannes Bergf84f7712013-11-14 17:14:45 +010014261static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020014262 struct genl_info *info)
14263{
14264 struct cfg80211_registered_device *rdev;
Johannes Berg89a54e42012-06-15 14:33:17 +020014265 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020014266 struct net_device *dev;
Johannes Berg4c476992010-10-04 21:36:35 +020014267 bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
14268
14269 if (rtnl)
14270 rtnl_lock();
14271
14272 if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
Johannes Berg4f7eff12012-06-15 14:14:22 +020014273 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
Johannes Berg4c476992010-10-04 21:36:35 +020014274 if (IS_ERR(rdev)) {
14275 if (rtnl)
14276 rtnl_unlock();
14277 return PTR_ERR(rdev);
14278 }
14279 info->user_ptr[0] = rdev;
Johannes Berg1bf614e2012-06-15 15:23:36 +020014280 } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
14281 ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
Johannes Berg5fe231e2013-05-08 21:45:15 +020014282 ASSERT_RTNL();
14283
Johannes Berg89a54e42012-06-15 14:33:17 +020014284 wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
14285 info->attrs);
14286 if (IS_ERR(wdev)) {
Johannes Berg4c476992010-10-04 21:36:35 +020014287 if (rtnl)
14288 rtnl_unlock();
Johannes Berg89a54e42012-06-15 14:33:17 +020014289 return PTR_ERR(wdev);
Johannes Berg4c476992010-10-04 21:36:35 +020014290 }
Johannes Berg89a54e42012-06-15 14:33:17 +020014291
Johannes Berg89a54e42012-06-15 14:33:17 +020014292 dev = wdev->netdev;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014293 rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg89a54e42012-06-15 14:33:17 +020014294
Johannes Berg1bf614e2012-06-15 15:23:36 +020014295 if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
14296 if (!dev) {
Johannes Berg1bf614e2012-06-15 15:23:36 +020014297 if (rtnl)
14298 rtnl_unlock();
14299 return -EINVAL;
14300 }
14301
14302 info->user_ptr[1] = dev;
14303 } else {
14304 info->user_ptr[1] = wdev;
Johannes Berg41265712010-10-04 21:14:05 +020014305 }
Johannes Berg89a54e42012-06-15 14:33:17 +020014306
Arend Van Spriel73c7da32016-10-20 20:08:22 +010014307 if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
14308 !wdev_running(wdev)) {
14309 if (rtnl)
14310 rtnl_unlock();
14311 return -ENETDOWN;
Johannes Berg1bf614e2012-06-15 15:23:36 +020014312 }
14313
Arend Van Spriel73c7da32016-10-20 20:08:22 +010014314 if (dev)
14315 dev_hold(dev);
14316
Johannes Berg4c476992010-10-04 21:36:35 +020014317 info->user_ptr[0] = rdev;
Johannes Berg4c476992010-10-04 21:36:35 +020014318 }
14319
14320 return 0;
14321}
14322
Johannes Bergf84f7712013-11-14 17:14:45 +010014323static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020014324 struct genl_info *info)
14325{
Johannes Berg1bf614e2012-06-15 15:23:36 +020014326 if (info->user_ptr[1]) {
14327 if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
14328 struct wireless_dev *wdev = info->user_ptr[1];
14329
14330 if (wdev->netdev)
14331 dev_put(wdev->netdev);
14332 } else {
14333 dev_put(info->user_ptr[1]);
14334 }
14335 }
Johannes Berg5393b912014-09-10 15:00:16 +030014336
Johannes Berg4c476992010-10-04 21:36:35 +020014337 if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
14338 rtnl_unlock();
Johannes Berg5393b912014-09-10 15:00:16 +030014339
14340 /* If needed, clear the netlink message payload from the SKB
14341 * as it might contain key data that shouldn't stick around on
14342 * the heap after the SKB is freed. The netlink message header
14343 * is still needed for further processing, so leave it intact.
14344 */
14345 if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) {
14346 struct nlmsghdr *nlh = nlmsg_hdr(skb);
14347
14348 memset(nlmsg_data(nlh), 0, nlmsg_len(nlh));
14349 }
Johannes Berg4c476992010-10-04 21:36:35 +020014350}
14351
Johannes Berg4534de82013-11-14 17:14:46 +010014352static const struct genl_ops nl80211_ops[] = {
Johannes Berg55682962007-09-20 13:09:35 -040014353 {
14354 .cmd = NL80211_CMD_GET_WIPHY,
Johannes Bergef6243a2019-04-26 14:07:31 +020014355 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040014356 .doit = nl80211_get_wiphy,
14357 .dumpit = nl80211_dump_wiphy,
Johannes Berg86e8cf92013-06-19 10:57:22 +020014358 .done = nl80211_dump_wiphy_done,
Johannes Berg55682962007-09-20 13:09:35 -040014359 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020014360 .internal_flags = NL80211_FLAG_NEED_WIPHY |
14361 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040014362 },
14363 {
14364 .cmd = NL80211_CMD_SET_WIPHY,
Johannes Bergef6243a2019-04-26 14:07:31 +020014365 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040014366 .doit = nl80211_set_wiphy,
Martin Willi5617c6c2016-05-09 18:33:58 +020014367 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020014368 .internal_flags = NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040014369 },
14370 {
14371 .cmd = NL80211_CMD_GET_INTERFACE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014372 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040014373 .doit = nl80211_get_interface,
14374 .dumpit = nl80211_dump_interface,
Johannes Berg55682962007-09-20 13:09:35 -040014375 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020014376 .internal_flags = NL80211_FLAG_NEED_WDEV |
14377 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040014378 },
14379 {
14380 .cmd = NL80211_CMD_SET_INTERFACE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014381 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040014382 .doit = nl80211_set_interface,
Martin Willi5617c6c2016-05-09 18:33:58 +020014383 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020014384 .internal_flags = NL80211_FLAG_NEED_NETDEV |
14385 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040014386 },
14387 {
14388 .cmd = NL80211_CMD_NEW_INTERFACE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014389 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040014390 .doit = nl80211_new_interface,
Martin Willi5617c6c2016-05-09 18:33:58 +020014391 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020014392 .internal_flags = NL80211_FLAG_NEED_WIPHY |
14393 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040014394 },
14395 {
14396 .cmd = NL80211_CMD_DEL_INTERFACE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014397 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040014398 .doit = nl80211_del_interface,
Martin Willi5617c6c2016-05-09 18:33:58 +020014399 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg84efbb82012-06-16 00:00:26 +020014400 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020014401 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040014402 },
Johannes Berg41ade002007-12-19 02:03:29 +010014403 {
14404 .cmd = NL80211_CMD_GET_KEY,
Johannes Bergef6243a2019-04-26 14:07:31 +020014405 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg41ade002007-12-19 02:03:29 +010014406 .doit = nl80211_get_key,
Martin Willi5617c6c2016-05-09 18:33:58 +020014407 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014408 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014409 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010014410 },
14411 {
14412 .cmd = NL80211_CMD_SET_KEY,
Johannes Bergef6243a2019-04-26 14:07:31 +020014413 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg41ade002007-12-19 02:03:29 +010014414 .doit = nl80211_set_key,
Martin Willi5617c6c2016-05-09 18:33:58 +020014415 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014416 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030014417 NL80211_FLAG_NEED_RTNL |
14418 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010014419 },
14420 {
14421 .cmd = NL80211_CMD_NEW_KEY,
Johannes Bergef6243a2019-04-26 14:07:31 +020014422 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg41ade002007-12-19 02:03:29 +010014423 .doit = nl80211_new_key,
Martin Willi5617c6c2016-05-09 18:33:58 +020014424 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014425 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030014426 NL80211_FLAG_NEED_RTNL |
14427 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010014428 },
14429 {
14430 .cmd = NL80211_CMD_DEL_KEY,
Johannes Bergef6243a2019-04-26 14:07:31 +020014431 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg41ade002007-12-19 02:03:29 +010014432 .doit = nl80211_del_key,
Martin Willi5617c6c2016-05-09 18:33:58 +020014433 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014434 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014435 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010014436 },
Johannes Berged1b6cc2007-12-19 02:03:32 +010014437 {
14438 .cmd = NL80211_CMD_SET_BEACON,
Johannes Bergef6243a2019-04-26 14:07:31 +020014439 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Martin Willi5617c6c2016-05-09 18:33:58 +020014440 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010014441 .doit = nl80211_set_beacon,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014442 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014443 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010014444 },
14445 {
Johannes Berg88600202012-02-13 15:17:18 +010014446 .cmd = NL80211_CMD_START_AP,
Johannes Bergef6243a2019-04-26 14:07:31 +020014447 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Martin Willi5617c6c2016-05-09 18:33:58 +020014448 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010014449 .doit = nl80211_start_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014450 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014451 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010014452 },
14453 {
Johannes Berg88600202012-02-13 15:17:18 +010014454 .cmd = NL80211_CMD_STOP_AP,
Johannes Bergef6243a2019-04-26 14:07:31 +020014455 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Martin Willi5617c6c2016-05-09 18:33:58 +020014456 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010014457 .doit = nl80211_stop_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014458 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014459 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010014460 },
Johannes Berg5727ef12007-12-19 02:03:34 +010014461 {
14462 .cmd = NL80211_CMD_GET_STATION,
Johannes Bergef6243a2019-04-26 14:07:31 +020014463 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg5727ef12007-12-19 02:03:34 +010014464 .doit = nl80211_get_station,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014465 .dumpit = nl80211_dump_station,
Johannes Berg4c476992010-10-04 21:36:35 +020014466 .internal_flags = NL80211_FLAG_NEED_NETDEV |
14467 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010014468 },
14469 {
14470 .cmd = NL80211_CMD_SET_STATION,
Johannes Bergef6243a2019-04-26 14:07:31 +020014471 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg5727ef12007-12-19 02:03:34 +010014472 .doit = nl80211_set_station,
Martin Willi5617c6c2016-05-09 18:33:58 +020014473 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014474 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014475 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010014476 },
14477 {
14478 .cmd = NL80211_CMD_NEW_STATION,
Johannes Bergef6243a2019-04-26 14:07:31 +020014479 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg5727ef12007-12-19 02:03:34 +010014480 .doit = nl80211_new_station,
Martin Willi5617c6c2016-05-09 18:33:58 +020014481 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014482 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014483 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010014484 },
14485 {
14486 .cmd = NL80211_CMD_DEL_STATION,
Johannes Bergef6243a2019-04-26 14:07:31 +020014487 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg5727ef12007-12-19 02:03:34 +010014488 .doit = nl80211_del_station,
Martin Willi5617c6c2016-05-09 18:33:58 +020014489 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014490 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014491 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010014492 },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014493 {
14494 .cmd = NL80211_CMD_GET_MPATH,
Johannes Bergef6243a2019-04-26 14:07:31 +020014495 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014496 .doit = nl80211_get_mpath,
14497 .dumpit = nl80211_dump_mpath,
Martin Willi5617c6c2016-05-09 18:33:58 +020014498 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014499 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014500 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014501 },
14502 {
Henning Rogge66be7d22014-09-12 08:58:49 +020014503 .cmd = NL80211_CMD_GET_MPP,
Johannes Bergef6243a2019-04-26 14:07:31 +020014504 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Henning Rogge66be7d22014-09-12 08:58:49 +020014505 .doit = nl80211_get_mpp,
14506 .dumpit = nl80211_dump_mpp,
Martin Willi5617c6c2016-05-09 18:33:58 +020014507 .flags = GENL_UNS_ADMIN_PERM,
Henning Rogge66be7d22014-09-12 08:58:49 +020014508 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14509 NL80211_FLAG_NEED_RTNL,
14510 },
14511 {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014512 .cmd = NL80211_CMD_SET_MPATH,
Johannes Bergef6243a2019-04-26 14:07:31 +020014513 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014514 .doit = nl80211_set_mpath,
Martin Willi5617c6c2016-05-09 18:33:58 +020014515 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014516 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014517 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014518 },
14519 {
14520 .cmd = NL80211_CMD_NEW_MPATH,
Johannes Bergef6243a2019-04-26 14:07:31 +020014521 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014522 .doit = nl80211_new_mpath,
Martin Willi5617c6c2016-05-09 18:33:58 +020014523 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014524 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014525 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014526 },
14527 {
14528 .cmd = NL80211_CMD_DEL_MPATH,
Johannes Bergef6243a2019-04-26 14:07:31 +020014529 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014530 .doit = nl80211_del_mpath,
Martin Willi5617c6c2016-05-09 18:33:58 +020014531 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014532 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014533 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010014534 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +030014535 {
14536 .cmd = NL80211_CMD_SET_BSS,
Johannes Bergef6243a2019-04-26 14:07:31 +020014537 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen9f1ba902008-08-07 20:07:01 +030014538 .doit = nl80211_set_bss,
Martin Willi5617c6c2016-05-09 18:33:58 +020014539 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014540 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014541 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9f1ba902008-08-07 20:07:01 +030014542 },
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070014543 {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080014544 .cmd = NL80211_CMD_GET_REG,
Johannes Bergef6243a2019-04-26 14:07:31 +020014545 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arik Nemtsovad30ca22014-12-15 19:25:59 +020014546 .doit = nl80211_get_reg_do,
14547 .dumpit = nl80211_get_reg_dump,
Johannes Berg5fe231e2013-05-08 21:45:15 +020014548 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080014549 /* can be retrieved by unprivileged users */
14550 },
Johannes Bergb6863032015-10-15 09:25:18 +020014551#ifdef CONFIG_CFG80211_CRDA_SUPPORT
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080014552 {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070014553 .cmd = NL80211_CMD_SET_REG,
Johannes Bergef6243a2019-04-26 14:07:31 +020014554 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070014555 .doit = nl80211_set_reg,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070014556 .flags = GENL_ADMIN_PERM,
Johannes Berg5fe231e2013-05-08 21:45:15 +020014557 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070014558 },
Johannes Bergb6863032015-10-15 09:25:18 +020014559#endif
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070014560 {
14561 .cmd = NL80211_CMD_REQ_SET_REG,
Johannes Bergef6243a2019-04-26 14:07:31 +020014562 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070014563 .doit = nl80211_req_set_reg,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070014564 .flags = GENL_ADMIN_PERM,
14565 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070014566 {
Johannes Berg1ea4ff3e92017-09-13 16:07:22 +020014567 .cmd = NL80211_CMD_RELOAD_REGDB,
Johannes Bergef6243a2019-04-26 14:07:31 +020014568 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg1ea4ff3e92017-09-13 16:07:22 +020014569 .doit = nl80211_reload_regdb,
Johannes Berg1ea4ff3e92017-09-13 16:07:22 +020014570 .flags = GENL_ADMIN_PERM,
14571 },
14572 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080014573 .cmd = NL80211_CMD_GET_MESH_CONFIG,
Johannes Bergef6243a2019-04-26 14:07:31 +020014574 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Javier Cardona24bdd9f2010-12-16 17:37:48 -080014575 .doit = nl80211_get_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070014576 /* can be retrieved by unprivileged users */
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014577 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014578 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070014579 },
14580 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080014581 .cmd = NL80211_CMD_SET_MESH_CONFIG,
Johannes Bergef6243a2019-04-26 14:07:31 +020014582 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Javier Cardona24bdd9f2010-12-16 17:37:48 -080014583 .doit = nl80211_update_mesh_config,
Martin Willi5617c6c2016-05-09 18:33:58 +020014584 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010014585 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014586 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070014587 },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +020014588 {
Johannes Berg2a519312009-02-10 21:25:55 +010014589 .cmd = NL80211_CMD_TRIGGER_SCAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020014590 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg2a519312009-02-10 21:25:55 +010014591 .doit = nl80211_trigger_scan,
Martin Willi5617c6c2016-05-09 18:33:58 +020014592 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergfd014282012-06-18 19:17:03 +020014593 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014594 NL80211_FLAG_NEED_RTNL,
Johannes Berg2a519312009-02-10 21:25:55 +010014595 },
14596 {
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053014597 .cmd = NL80211_CMD_ABORT_SCAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020014598 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053014599 .doit = nl80211_abort_scan,
Martin Willi5617c6c2016-05-09 18:33:58 +020014600 .flags = GENL_UNS_ADMIN_PERM,
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053014601 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14602 NL80211_FLAG_NEED_RTNL,
14603 },
14604 {
Johannes Berg2a519312009-02-10 21:25:55 +010014605 .cmd = NL80211_CMD_GET_SCAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020014606 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg2a519312009-02-10 21:25:55 +010014607 .dumpit = nl80211_dump_scan,
14608 },
Jouni Malinen636a5d32009-03-19 13:39:22 +020014609 {
Luciano Coelho807f8a82011-05-11 17:09:35 +030014610 .cmd = NL80211_CMD_START_SCHED_SCAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020014611 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luciano Coelho807f8a82011-05-11 17:09:35 +030014612 .doit = nl80211_start_sched_scan,
Martin Willi5617c6c2016-05-09 18:33:58 +020014613 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030014614 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14615 NL80211_FLAG_NEED_RTNL,
14616 },
14617 {
14618 .cmd = NL80211_CMD_STOP_SCHED_SCAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020014619 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luciano Coelho807f8a82011-05-11 17:09:35 +030014620 .doit = nl80211_stop_sched_scan,
Martin Willi5617c6c2016-05-09 18:33:58 +020014621 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030014622 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14623 NL80211_FLAG_NEED_RTNL,
14624 },
14625 {
Jouni Malinen636a5d32009-03-19 13:39:22 +020014626 .cmd = NL80211_CMD_AUTHENTICATE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014627 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen636a5d32009-03-19 13:39:22 +020014628 .doit = nl80211_authenticate,
Martin Willi5617c6c2016-05-09 18:33:58 +020014629 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014630 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030014631 NL80211_FLAG_NEED_RTNL |
14632 NL80211_FLAG_CLEAR_SKB,
Jouni Malinen636a5d32009-03-19 13:39:22 +020014633 },
14634 {
14635 .cmd = NL80211_CMD_ASSOCIATE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014636 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen636a5d32009-03-19 13:39:22 +020014637 .doit = nl80211_associate,
Martin Willi5617c6c2016-05-09 18:33:58 +020014638 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014639 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Sunil Duttd6db02a2019-02-25 15:37:20 +053014640 NL80211_FLAG_NEED_RTNL |
14641 NL80211_FLAG_CLEAR_SKB,
Jouni Malinen636a5d32009-03-19 13:39:22 +020014642 },
14643 {
14644 .cmd = NL80211_CMD_DEAUTHENTICATE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014645 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen636a5d32009-03-19 13:39:22 +020014646 .doit = nl80211_deauthenticate,
Martin Willi5617c6c2016-05-09 18:33:58 +020014647 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014648 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014649 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020014650 },
14651 {
14652 .cmd = NL80211_CMD_DISASSOCIATE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014653 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen636a5d32009-03-19 13:39:22 +020014654 .doit = nl80211_disassociate,
Martin Willi5617c6c2016-05-09 18:33:58 +020014655 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014656 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014657 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020014658 },
Johannes Berg04a773a2009-04-19 21:24:32 +020014659 {
14660 .cmd = NL80211_CMD_JOIN_IBSS,
Johannes Bergef6243a2019-04-26 14:07:31 +020014661 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg04a773a2009-04-19 21:24:32 +020014662 .doit = nl80211_join_ibss,
Martin Willi5617c6c2016-05-09 18:33:58 +020014663 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014664 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014665 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020014666 },
14667 {
14668 .cmd = NL80211_CMD_LEAVE_IBSS,
Johannes Bergef6243a2019-04-26 14:07:31 +020014669 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg04a773a2009-04-19 21:24:32 +020014670 .doit = nl80211_leave_ibss,
Martin Willi5617c6c2016-05-09 18:33:58 +020014671 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014672 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014673 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020014674 },
Johannes Bergaff89a92009-07-01 21:26:51 +020014675#ifdef CONFIG_NL80211_TESTMODE
14676 {
14677 .cmd = NL80211_CMD_TESTMODE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014678 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergaff89a92009-07-01 21:26:51 +020014679 .doit = nl80211_testmode_do,
Wey-Yi Guy71063f02011-05-20 09:05:54 -070014680 .dumpit = nl80211_testmode_dump,
Martin Willi5617c6c2016-05-09 18:33:58 +020014681 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020014682 .internal_flags = NL80211_FLAG_NEED_WIPHY |
14683 NL80211_FLAG_NEED_RTNL,
Johannes Bergaff89a92009-07-01 21:26:51 +020014684 },
14685#endif
Samuel Ortizb23aa672009-07-01 21:26:54 +020014686 {
14687 .cmd = NL80211_CMD_CONNECT,
Johannes Bergef6243a2019-04-26 14:07:31 +020014688 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortizb23aa672009-07-01 21:26:54 +020014689 .doit = nl80211_connect,
Martin Willi5617c6c2016-05-09 18:33:58 +020014690 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014691 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Sunil Duttd6db02a2019-02-25 15:37:20 +053014692 NL80211_FLAG_NEED_RTNL |
14693 NL80211_FLAG_CLEAR_SKB,
Samuel Ortizb23aa672009-07-01 21:26:54 +020014694 },
14695 {
vamsi krishna088e8df2016-10-27 16:51:11 +030014696 .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
Johannes Bergef6243a2019-04-26 14:07:31 +020014697 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
vamsi krishna088e8df2016-10-27 16:51:11 +030014698 .doit = nl80211_update_connect_params,
vamsi krishna088e8df2016-10-27 16:51:11 +030014699 .flags = GENL_ADMIN_PERM,
14700 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Sunil Duttd6db02a2019-02-25 15:37:20 +053014701 NL80211_FLAG_NEED_RTNL |
14702 NL80211_FLAG_CLEAR_SKB,
vamsi krishna088e8df2016-10-27 16:51:11 +030014703 },
14704 {
Samuel Ortizb23aa672009-07-01 21:26:54 +020014705 .cmd = NL80211_CMD_DISCONNECT,
Johannes Bergef6243a2019-04-26 14:07:31 +020014706 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortizb23aa672009-07-01 21:26:54 +020014707 .doit = nl80211_disconnect,
Martin Willi5617c6c2016-05-09 18:33:58 +020014708 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020014709 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014710 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020014711 },
Johannes Berg463d0182009-07-14 00:33:35 +020014712 {
14713 .cmd = NL80211_CMD_SET_WIPHY_NETNS,
Johannes Bergef6243a2019-04-26 14:07:31 +020014714 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg463d0182009-07-14 00:33:35 +020014715 .doit = nl80211_wiphy_netns,
Martin Willi5617c6c2016-05-09 18:33:58 +020014716 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020014717 .internal_flags = NL80211_FLAG_NEED_WIPHY |
14718 NL80211_FLAG_NEED_RTNL,
Johannes Berg463d0182009-07-14 00:33:35 +020014719 },
Holger Schurig61fa7132009-11-11 12:25:40 +010014720 {
14721 .cmd = NL80211_CMD_GET_SURVEY,
Johannes Bergef6243a2019-04-26 14:07:31 +020014722 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Holger Schurig61fa7132009-11-11 12:25:40 +010014723 .dumpit = nl80211_dump_survey,
14724 },
Samuel Ortiz67fbb162009-11-24 23:59:15 +010014725 {
14726 .cmd = NL80211_CMD_SET_PMKSA,
Johannes Bergef6243a2019-04-26 14:07:31 +020014727 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010014728 .doit = nl80211_setdel_pmksa,
Martin Willi5617c6c2016-05-09 18:33:58 +020014729 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014730 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Sunil Duttd6db02a2019-02-25 15:37:20 +053014731 NL80211_FLAG_NEED_RTNL |
14732 NL80211_FLAG_CLEAR_SKB,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010014733 },
14734 {
14735 .cmd = NL80211_CMD_DEL_PMKSA,
Johannes Bergef6243a2019-04-26 14:07:31 +020014736 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010014737 .doit = nl80211_setdel_pmksa,
Martin Willi5617c6c2016-05-09 18:33:58 +020014738 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014739 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014740 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010014741 },
14742 {
14743 .cmd = NL80211_CMD_FLUSH_PMKSA,
Johannes Bergef6243a2019-04-26 14:07:31 +020014744 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010014745 .doit = nl80211_flush_pmksa,
Martin Willi5617c6c2016-05-09 18:33:58 +020014746 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014747 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014748 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010014749 },
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014750 {
14751 .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
Johannes Bergef6243a2019-04-26 14:07:31 +020014752 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014753 .doit = nl80211_remain_on_channel,
Martin Willi5617c6c2016-05-09 18:33:58 +020014754 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020014755 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014756 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014757 },
14758 {
14759 .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
Johannes Bergef6243a2019-04-26 14:07:31 +020014760 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014761 .doit = nl80211_cancel_remain_on_channel,
Martin Willi5617c6c2016-05-09 18:33:58 +020014762 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020014763 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014764 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014765 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +020014766 {
14767 .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
Johannes Bergef6243a2019-04-26 14:07:31 +020014768 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen13ae75b2009-12-29 12:59:45 +020014769 .doit = nl80211_set_tx_bitrate_mask,
Martin Willi5617c6c2016-05-09 18:33:58 +020014770 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020014771 .internal_flags = NL80211_FLAG_NEED_NETDEV |
14772 NL80211_FLAG_NEED_RTNL,
Jouni Malinen13ae75b2009-12-29 12:59:45 +020014773 },
Jouni Malinen026331c2010-02-15 12:53:10 +020014774 {
Johannes Berg2e161f782010-08-12 15:38:38 +020014775 .cmd = NL80211_CMD_REGISTER_FRAME,
Johannes Bergef6243a2019-04-26 14:07:31 +020014776 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg2e161f782010-08-12 15:38:38 +020014777 .doit = nl80211_register_mgmt,
Martin Willi5617c6c2016-05-09 18:33:58 +020014778 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020014779 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020014780 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020014781 },
14782 {
Johannes Berg2e161f782010-08-12 15:38:38 +020014783 .cmd = NL80211_CMD_FRAME,
Johannes Bergef6243a2019-04-26 14:07:31 +020014784 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg2e161f782010-08-12 15:38:38 +020014785 .doit = nl80211_tx_mgmt,
Martin Willi5617c6c2016-05-09 18:33:58 +020014786 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020014787 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020014788 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020014789 },
Kalle Valoffb9eb32010-02-17 17:58:10 +020014790 {
Johannes Bergf7ca38d2010-11-25 10:02:29 +010014791 .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
Johannes Bergef6243a2019-04-26 14:07:31 +020014792 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergf7ca38d2010-11-25 10:02:29 +010014793 .doit = nl80211_tx_mgmt_cancel_wait,
Martin Willi5617c6c2016-05-09 18:33:58 +020014794 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020014795 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Bergf7ca38d2010-11-25 10:02:29 +010014796 NL80211_FLAG_NEED_RTNL,
14797 },
14798 {
Kalle Valoffb9eb32010-02-17 17:58:10 +020014799 .cmd = NL80211_CMD_SET_POWER_SAVE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014800 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Kalle Valoffb9eb32010-02-17 17:58:10 +020014801 .doit = nl80211_set_power_save,
Martin Willi5617c6c2016-05-09 18:33:58 +020014802 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020014803 .internal_flags = NL80211_FLAG_NEED_NETDEV |
14804 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020014805 },
14806 {
14807 .cmd = NL80211_CMD_GET_POWER_SAVE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014808 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Kalle Valoffb9eb32010-02-17 17:58:10 +020014809 .doit = nl80211_get_power_save,
Kalle Valoffb9eb32010-02-17 17:58:10 +020014810 /* can be retrieved by unprivileged users */
Johannes Berg4c476992010-10-04 21:36:35 +020014811 .internal_flags = NL80211_FLAG_NEED_NETDEV |
14812 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020014813 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014814 {
14815 .cmd = NL80211_CMD_SET_CQM,
Johannes Bergef6243a2019-04-26 14:07:31 +020014816 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014817 .doit = nl80211_set_cqm,
Martin Willi5617c6c2016-05-09 18:33:58 +020014818 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020014819 .internal_flags = NL80211_FLAG_NEED_NETDEV |
14820 NL80211_FLAG_NEED_RTNL,
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014821 },
Johannes Bergf444de02010-05-05 15:25:02 +020014822 {
14823 .cmd = NL80211_CMD_SET_CHANNEL,
Johannes Bergef6243a2019-04-26 14:07:31 +020014824 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergf444de02010-05-05 15:25:02 +020014825 .doit = nl80211_set_channel,
Martin Willi5617c6c2016-05-09 18:33:58 +020014826 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020014827 .internal_flags = NL80211_FLAG_NEED_NETDEV |
14828 NL80211_FLAG_NEED_RTNL,
Johannes Bergf444de02010-05-05 15:25:02 +020014829 },
Bill Jordane8347eb2010-10-01 13:54:28 -040014830 {
14831 .cmd = NL80211_CMD_SET_WDS_PEER,
Johannes Bergef6243a2019-04-26 14:07:31 +020014832 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Bill Jordane8347eb2010-10-01 13:54:28 -040014833 .doit = nl80211_set_wds_peer,
Martin Willi5617c6c2016-05-09 18:33:58 +020014834 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg43b19952010-10-07 13:10:30 +020014835 .internal_flags = NL80211_FLAG_NEED_NETDEV |
14836 NL80211_FLAG_NEED_RTNL,
Bill Jordane8347eb2010-10-01 13:54:28 -040014837 },
Johannes Berg29cbe682010-12-03 09:20:44 +010014838 {
14839 .cmd = NL80211_CMD_JOIN_MESH,
Johannes Bergef6243a2019-04-26 14:07:31 +020014840 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg29cbe682010-12-03 09:20:44 +010014841 .doit = nl80211_join_mesh,
Martin Willi5617c6c2016-05-09 18:33:58 +020014842 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010014843 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14844 NL80211_FLAG_NEED_RTNL,
14845 },
14846 {
14847 .cmd = NL80211_CMD_LEAVE_MESH,
Johannes Bergef6243a2019-04-26 14:07:31 +020014848 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg29cbe682010-12-03 09:20:44 +010014849 .doit = nl80211_leave_mesh,
Martin Willi5617c6c2016-05-09 18:33:58 +020014850 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010014851 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14852 NL80211_FLAG_NEED_RTNL,
14853 },
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010014854 {
14855 .cmd = NL80211_CMD_JOIN_OCB,
Johannes Bergef6243a2019-04-26 14:07:31 +020014856 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010014857 .doit = nl80211_join_ocb,
Martin Willi5617c6c2016-05-09 18:33:58 +020014858 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010014859 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14860 NL80211_FLAG_NEED_RTNL,
14861 },
14862 {
14863 .cmd = NL80211_CMD_LEAVE_OCB,
Johannes Bergef6243a2019-04-26 14:07:31 +020014864 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010014865 .doit = nl80211_leave_ocb,
Martin Willi5617c6c2016-05-09 18:33:58 +020014866 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010014867 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14868 NL80211_FLAG_NEED_RTNL,
14869 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020014870#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +020014871 {
14872 .cmd = NL80211_CMD_GET_WOWLAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020014873 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergff1b6e62011-05-04 15:37:28 +020014874 .doit = nl80211_get_wowlan,
Johannes Bergff1b6e62011-05-04 15:37:28 +020014875 /* can be retrieved by unprivileged users */
14876 .internal_flags = NL80211_FLAG_NEED_WIPHY |
14877 NL80211_FLAG_NEED_RTNL,
14878 },
14879 {
14880 .cmd = NL80211_CMD_SET_WOWLAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020014881 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergff1b6e62011-05-04 15:37:28 +020014882 .doit = nl80211_set_wowlan,
Martin Willi5617c6c2016-05-09 18:33:58 +020014883 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergff1b6e62011-05-04 15:37:28 +020014884 .internal_flags = NL80211_FLAG_NEED_WIPHY |
14885 NL80211_FLAG_NEED_RTNL,
14886 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020014887#endif
Johannes Berge5497d72011-07-05 16:35:40 +020014888 {
14889 .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +020014890 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berge5497d72011-07-05 16:35:40 +020014891 .doit = nl80211_set_rekey_data,
Martin Willi5617c6c2016-05-09 18:33:58 +020014892 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berge5497d72011-07-05 16:35:40 +020014893 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030014894 NL80211_FLAG_NEED_RTNL |
14895 NL80211_FLAG_CLEAR_SKB,
Johannes Berge5497d72011-07-05 16:35:40 +020014896 },
Arik Nemtsov109086c2011-09-28 14:12:50 +030014897 {
14898 .cmd = NL80211_CMD_TDLS_MGMT,
Johannes Bergef6243a2019-04-26 14:07:31 +020014899 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arik Nemtsov109086c2011-09-28 14:12:50 +030014900 .doit = nl80211_tdls_mgmt,
Martin Willi5617c6c2016-05-09 18:33:58 +020014901 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030014902 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14903 NL80211_FLAG_NEED_RTNL,
14904 },
14905 {
14906 .cmd = NL80211_CMD_TDLS_OPER,
Johannes Bergef6243a2019-04-26 14:07:31 +020014907 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arik Nemtsov109086c2011-09-28 14:12:50 +030014908 .doit = nl80211_tdls_oper,
Martin Willi5617c6c2016-05-09 18:33:58 +020014909 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030014910 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14911 NL80211_FLAG_NEED_RTNL,
14912 },
Johannes Berg28946da2011-11-04 11:18:12 +010014913 {
14914 .cmd = NL80211_CMD_UNEXPECTED_FRAME,
Johannes Bergef6243a2019-04-26 14:07:31 +020014915 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg28946da2011-11-04 11:18:12 +010014916 .doit = nl80211_register_unexpected_frame,
Martin Willi5617c6c2016-05-09 18:33:58 +020014917 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg28946da2011-11-04 11:18:12 +010014918 .internal_flags = NL80211_FLAG_NEED_NETDEV |
14919 NL80211_FLAG_NEED_RTNL,
14920 },
Johannes Berg7f6cf312011-11-04 11:18:15 +010014921 {
14922 .cmd = NL80211_CMD_PROBE_CLIENT,
Johannes Bergef6243a2019-04-26 14:07:31 +020014923 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg7f6cf312011-11-04 11:18:15 +010014924 .doit = nl80211_probe_client,
Martin Willi5617c6c2016-05-09 18:33:58 +020014925 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020014926 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg7f6cf312011-11-04 11:18:15 +010014927 NL80211_FLAG_NEED_RTNL,
14928 },
Johannes Berg5e760232011-11-04 11:18:17 +010014929 {
14930 .cmd = NL80211_CMD_REGISTER_BEACONS,
Johannes Bergef6243a2019-04-26 14:07:31 +020014931 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg5e760232011-11-04 11:18:17 +010014932 .doit = nl80211_register_beacons,
Martin Willi5617c6c2016-05-09 18:33:58 +020014933 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg5e760232011-11-04 11:18:17 +010014934 .internal_flags = NL80211_FLAG_NEED_WIPHY |
14935 NL80211_FLAG_NEED_RTNL,
14936 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010014937 {
14938 .cmd = NL80211_CMD_SET_NOACK_MAP,
Johannes Bergef6243a2019-04-26 14:07:31 +020014939 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010014940 .doit = nl80211_set_noack_map,
Martin Willi5617c6c2016-05-09 18:33:58 +020014941 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010014942 .internal_flags = NL80211_FLAG_NEED_NETDEV |
14943 NL80211_FLAG_NEED_RTNL,
14944 },
Johannes Berg98104fde2012-06-16 00:19:54 +020014945 {
14946 .cmd = NL80211_CMD_START_P2P_DEVICE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014947 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg98104fde2012-06-16 00:19:54 +020014948 .doit = nl80211_start_p2p_device,
Martin Willi5617c6c2016-05-09 18:33:58 +020014949 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020014950 .internal_flags = NL80211_FLAG_NEED_WDEV |
14951 NL80211_FLAG_NEED_RTNL,
14952 },
14953 {
14954 .cmd = NL80211_CMD_STOP_P2P_DEVICE,
Johannes Bergef6243a2019-04-26 14:07:31 +020014955 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg98104fde2012-06-16 00:19:54 +020014956 .doit = nl80211_stop_p2p_device,
Martin Willi5617c6c2016-05-09 18:33:58 +020014957 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020014958 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14959 NL80211_FLAG_NEED_RTNL,
14960 },
Antonio Quartullif4e583c2012-11-02 13:27:48 +010014961 {
Ayala Bekercb3b7d82016-09-20 17:31:13 +030014962 .cmd = NL80211_CMD_START_NAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020014963 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ayala Bekercb3b7d82016-09-20 17:31:13 +030014964 .doit = nl80211_start_nan,
Ayala Bekercb3b7d82016-09-20 17:31:13 +030014965 .flags = GENL_ADMIN_PERM,
14966 .internal_flags = NL80211_FLAG_NEED_WDEV |
14967 NL80211_FLAG_NEED_RTNL,
14968 },
14969 {
14970 .cmd = NL80211_CMD_STOP_NAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020014971 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ayala Bekercb3b7d82016-09-20 17:31:13 +030014972 .doit = nl80211_stop_nan,
Ayala Bekercb3b7d82016-09-20 17:31:13 +030014973 .flags = GENL_ADMIN_PERM,
14974 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14975 NL80211_FLAG_NEED_RTNL,
14976 },
14977 {
Ayala Bekera442b762016-09-20 17:31:15 +030014978 .cmd = NL80211_CMD_ADD_NAN_FUNCTION,
Johannes Bergef6243a2019-04-26 14:07:31 +020014979 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ayala Bekera442b762016-09-20 17:31:15 +030014980 .doit = nl80211_nan_add_func,
Ayala Bekera442b762016-09-20 17:31:15 +030014981 .flags = GENL_ADMIN_PERM,
14982 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14983 NL80211_FLAG_NEED_RTNL,
14984 },
14985 {
14986 .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
Johannes Bergef6243a2019-04-26 14:07:31 +020014987 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ayala Bekera442b762016-09-20 17:31:15 +030014988 .doit = nl80211_nan_del_func,
Ayala Bekera442b762016-09-20 17:31:15 +030014989 .flags = GENL_ADMIN_PERM,
14990 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14991 NL80211_FLAG_NEED_RTNL,
14992 },
14993 {
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030014994 .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
Johannes Bergef6243a2019-04-26 14:07:31 +020014995 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030014996 .doit = nl80211_nan_change_config,
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030014997 .flags = GENL_ADMIN_PERM,
14998 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14999 NL80211_FLAG_NEED_RTNL,
15000 },
15001 {
Antonio Quartullif4e583c2012-11-02 13:27:48 +010015002 .cmd = NL80211_CMD_SET_MCAST_RATE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015003 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Antonio Quartullif4e583c2012-11-02 13:27:48 +010015004 .doit = nl80211_set_mcast_rate,
Martin Willi5617c6c2016-05-09 18:33:58 +020015005 .flags = GENL_UNS_ADMIN_PERM,
Antonio Quartullif4e583c2012-11-02 13:27:48 +010015006 .internal_flags = NL80211_FLAG_NEED_NETDEV |
15007 NL80211_FLAG_NEED_RTNL,
15008 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053015009 {
15010 .cmd = NL80211_CMD_SET_MAC_ACL,
Johannes Bergef6243a2019-04-26 14:07:31 +020015011 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053015012 .doit = nl80211_set_mac_acl,
Martin Willi5617c6c2016-05-09 18:33:58 +020015013 .flags = GENL_UNS_ADMIN_PERM,
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053015014 .internal_flags = NL80211_FLAG_NEED_NETDEV |
15015 NL80211_FLAG_NEED_RTNL,
15016 },
Simon Wunderlich04f39042013-02-08 18:16:19 +010015017 {
15018 .cmd = NL80211_CMD_RADAR_DETECT,
Johannes Bergef6243a2019-04-26 14:07:31 +020015019 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Simon Wunderlich04f39042013-02-08 18:16:19 +010015020 .doit = nl80211_start_radar_detection,
Martin Willi5617c6c2016-05-09 18:33:58 +020015021 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich04f39042013-02-08 18:16:19 +010015022 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15023 NL80211_FLAG_NEED_RTNL,
15024 },
Johannes Berg3713b4e2013-02-14 16:19:38 +010015025 {
15026 .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
Johannes Bergef6243a2019-04-26 14:07:31 +020015027 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg3713b4e2013-02-14 16:19:38 +010015028 .doit = nl80211_get_protocol_features,
Johannes Berg3713b4e2013-02-14 16:19:38 +010015029 },
Jouni Malinen355199e2013-02-27 17:14:27 +020015030 {
15031 .cmd = NL80211_CMD_UPDATE_FT_IES,
Johannes Bergef6243a2019-04-26 14:07:31 +020015032 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen355199e2013-02-27 17:14:27 +020015033 .doit = nl80211_update_ft_ies,
Martin Willi5617c6c2016-05-09 18:33:58 +020015034 .flags = GENL_UNS_ADMIN_PERM,
Jouni Malinen355199e2013-02-27 17:14:27 +020015035 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15036 NL80211_FLAG_NEED_RTNL,
15037 },
Arend van Spriel5de17982013-04-18 15:49:00 +020015038 {
15039 .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
Johannes Bergef6243a2019-04-26 14:07:31 +020015040 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arend van Spriel5de17982013-04-18 15:49:00 +020015041 .doit = nl80211_crit_protocol_start,
Martin Willi5617c6c2016-05-09 18:33:58 +020015042 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020015043 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
15044 NL80211_FLAG_NEED_RTNL,
15045 },
15046 {
15047 .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
Johannes Bergef6243a2019-04-26 14:07:31 +020015048 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arend van Spriel5de17982013-04-18 15:49:00 +020015049 .doit = nl80211_crit_protocol_stop,
Martin Willi5617c6c2016-05-09 18:33:58 +020015050 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020015051 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
15052 NL80211_FLAG_NEED_RTNL,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070015053 },
15054 {
15055 .cmd = NL80211_CMD_GET_COALESCE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015056 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070015057 .doit = nl80211_get_coalesce,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070015058 .internal_flags = NL80211_FLAG_NEED_WIPHY |
15059 NL80211_FLAG_NEED_RTNL,
15060 },
15061 {
15062 .cmd = NL80211_CMD_SET_COALESCE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015063 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070015064 .doit = nl80211_set_coalesce,
Martin Willi5617c6c2016-05-09 18:33:58 +020015065 .flags = GENL_UNS_ADMIN_PERM,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070015066 .internal_flags = NL80211_FLAG_NEED_WIPHY |
15067 NL80211_FLAG_NEED_RTNL,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020015068 },
15069 {
15070 .cmd = NL80211_CMD_CHANNEL_SWITCH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015071 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020015072 .doit = nl80211_channel_switch,
Martin Willi5617c6c2016-05-09 18:33:58 +020015073 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020015074 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15075 NL80211_FLAG_NEED_RTNL,
15076 },
Johannes Bergad7e7182013-11-13 13:37:47 +010015077 {
15078 .cmd = NL80211_CMD_VENDOR,
Johannes Bergef6243a2019-04-26 14:07:31 +020015079 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergad7e7182013-11-13 13:37:47 +010015080 .doit = nl80211_vendor_cmd,
Johannes Berg7bdbe402015-08-15 22:39:49 +030015081 .dumpit = nl80211_vendor_cmd_dump,
Martin Willi5617c6c2016-05-09 18:33:58 +020015082 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergad7e7182013-11-13 13:37:47 +010015083 .internal_flags = NL80211_FLAG_NEED_WIPHY |
Sunil Duttd6db02a2019-02-25 15:37:20 +053015084 NL80211_FLAG_NEED_RTNL |
15085 NL80211_FLAG_CLEAR_SKB,
Johannes Bergad7e7182013-11-13 13:37:47 +010015086 },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080015087 {
15088 .cmd = NL80211_CMD_SET_QOS_MAP,
Johannes Bergef6243a2019-04-26 14:07:31 +020015089 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080015090 .doit = nl80211_set_qos_map,
Martin Willi5617c6c2016-05-09 18:33:58 +020015091 .flags = GENL_UNS_ADMIN_PERM,
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080015092 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15093 NL80211_FLAG_NEED_RTNL,
15094 },
Johannes Berg960d01a2014-09-09 22:55:35 +030015095 {
15096 .cmd = NL80211_CMD_ADD_TX_TS,
Johannes Bergef6243a2019-04-26 14:07:31 +020015097 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg960d01a2014-09-09 22:55:35 +030015098 .doit = nl80211_add_tx_ts,
Martin Willi5617c6c2016-05-09 18:33:58 +020015099 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030015100 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15101 NL80211_FLAG_NEED_RTNL,
15102 },
15103 {
15104 .cmd = NL80211_CMD_DEL_TX_TS,
Johannes Bergef6243a2019-04-26 14:07:31 +020015105 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg960d01a2014-09-09 22:55:35 +030015106 .doit = nl80211_del_tx_ts,
Martin Willi5617c6c2016-05-09 18:33:58 +020015107 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030015108 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15109 NL80211_FLAG_NEED_RTNL,
15110 },
Arik Nemtsov1057d352014-11-19 12:54:26 +020015111 {
15112 .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015113 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arik Nemtsov1057d352014-11-19 12:54:26 +020015114 .doit = nl80211_tdls_channel_switch,
Martin Willi5617c6c2016-05-09 18:33:58 +020015115 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020015116 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15117 NL80211_FLAG_NEED_RTNL,
15118 },
15119 {
15120 .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015121 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arik Nemtsov1057d352014-11-19 12:54:26 +020015122 .doit = nl80211_tdls_cancel_channel_switch,
Martin Willi5617c6c2016-05-09 18:33:58 +020015123 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020015124 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15125 NL80211_FLAG_NEED_RTNL,
15126 },
Michael Braunce0ce132016-10-10 19:12:22 +020015127 {
15128 .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
Johannes Bergef6243a2019-04-26 14:07:31 +020015129 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Michael Braunce0ce132016-10-10 19:12:22 +020015130 .doit = nl80211_set_multicast_to_unicast,
Michael Braunce0ce132016-10-10 19:12:22 +020015131 .flags = GENL_UNS_ADMIN_PERM,
15132 .internal_flags = NL80211_FLAG_NEED_NETDEV |
15133 NL80211_FLAG_NEED_RTNL,
15134 },
Avraham Stern3a00df52017-06-09 13:08:43 +010015135 {
15136 .cmd = NL80211_CMD_SET_PMK,
Johannes Bergef6243a2019-04-26 14:07:31 +020015137 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Avraham Stern3a00df52017-06-09 13:08:43 +010015138 .doit = nl80211_set_pmk,
Avraham Stern3a00df52017-06-09 13:08:43 +010015139 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Sunil Duttd6db02a2019-02-25 15:37:20 +053015140 NL80211_FLAG_NEED_RTNL |
15141 NL80211_FLAG_CLEAR_SKB,
Avraham Stern3a00df52017-06-09 13:08:43 +010015142 },
15143 {
15144 .cmd = NL80211_CMD_DEL_PMK,
Johannes Bergef6243a2019-04-26 14:07:31 +020015145 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Avraham Stern3a00df52017-06-09 13:08:43 +010015146 .doit = nl80211_del_pmk,
Avraham Stern3a00df52017-06-09 13:08:43 +010015147 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15148 NL80211_FLAG_NEED_RTNL,
15149 },
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020015150 {
15151 .cmd = NL80211_CMD_EXTERNAL_AUTH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015152 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020015153 .doit = nl80211_external_auth,
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020015154 .flags = GENL_ADMIN_PERM,
15155 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15156 NL80211_FLAG_NEED_RTNL,
15157 },
Denis Kenzior2576a9a2018-03-26 12:52:42 -050015158 {
15159 .cmd = NL80211_CMD_CONTROL_PORT_FRAME,
Johannes Bergef6243a2019-04-26 14:07:31 +020015160 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Denis Kenzior2576a9a2018-03-26 12:52:42 -050015161 .doit = nl80211_tx_control_port,
Denis Kenzior2576a9a2018-03-26 12:52:42 -050015162 .flags = GENL_UNS_ADMIN_PERM,
15163 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15164 NL80211_FLAG_NEED_RTNL,
15165 },
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070015166 {
15167 .cmd = NL80211_CMD_GET_FTM_RESPONDER_STATS,
Johannes Bergef6243a2019-04-26 14:07:31 +020015168 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070015169 .doit = nl80211_get_ftm_responder_stats,
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070015170 .internal_flags = NL80211_FLAG_NEED_NETDEV |
15171 NL80211_FLAG_NEED_RTNL,
15172 },
Johannes Berg9bb7e0f2018-09-10 13:29:12 +020015173 {
15174 .cmd = NL80211_CMD_PEER_MEASUREMENT_START,
Johannes Bergef6243a2019-04-26 14:07:31 +020015175 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg9bb7e0f2018-09-10 13:29:12 +020015176 .doit = nl80211_pmsr_start,
Johannes Berg9bb7e0f2018-09-10 13:29:12 +020015177 .flags = GENL_UNS_ADMIN_PERM,
15178 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
15179 NL80211_FLAG_NEED_RTNL,
15180 },
Sriram R30c63112018-12-04 17:46:52 +053015181 {
15182 .cmd = NL80211_CMD_NOTIFY_RADAR,
Johannes Bergef6243a2019-04-26 14:07:31 +020015183 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Sriram R30c63112018-12-04 17:46:52 +053015184 .doit = nl80211_notify_radar_detection,
Sriram R30c63112018-12-04 17:46:52 +053015185 .flags = GENL_UNS_ADMIN_PERM,
15186 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15187 NL80211_FLAG_NEED_RTNL,
15188 },
Sunil Duttcb74e972019-02-20 16:18:07 +053015189 {
15190 .cmd = NL80211_CMD_UPDATE_OWE_INFO,
15191 .doit = nl80211_update_owe_info,
15192 .flags = GENL_ADMIN_PERM,
15193 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15194 NL80211_FLAG_NEED_RTNL,
15195 },
Rajkumar Manoharan5ab92e72019-04-11 13:47:24 -070015196 {
15197 .cmd = NL80211_CMD_PROBE_MESH_LINK,
15198 .doit = nl80211_probe_mesh_link,
15199 .flags = GENL_UNS_ADMIN_PERM,
15200 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
15201 NL80211_FLAG_NEED_RTNL,
15202 },
Tamizh chelvam77f576d2020-01-20 13:21:22 +053015203 {
15204 .cmd = NL80211_CMD_SET_TID_CONFIG,
15205 .doit = nl80211_set_tid_config,
15206 .flags = GENL_UNS_ADMIN_PERM,
15207 .internal_flags = NL80211_FLAG_NEED_NETDEV |
15208 NL80211_FLAG_NEED_RTNL,
15209 },
Johannes Berg55682962007-09-20 13:09:35 -040015210};
Jouni Malinen9588bbd2009-12-23 13:15:41 +010015211
Johannes Berg56989f62016-10-24 14:40:05 +020015212static struct genl_family nl80211_fam __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +020015213 .name = NL80211_GENL_NAME, /* have users key off the name instead */
15214 .hdrsize = 0, /* no private header */
15215 .version = 1, /* no particular meaning now */
15216 .maxattr = NL80211_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +010015217 .policy = nl80211_policy,
Johannes Berg489111e2016-10-24 14:40:03 +020015218 .netnsok = true,
15219 .pre_doit = nl80211_pre_doit,
15220 .post_doit = nl80211_post_doit,
15221 .module = THIS_MODULE,
15222 .ops = nl80211_ops,
15223 .n_ops = ARRAY_SIZE(nl80211_ops),
15224 .mcgrps = nl80211_mcgrps,
15225 .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
Johannes Berg50508d92019-07-29 16:31:09 +020015226 .parallel_ops = true,
Johannes Berg489111e2016-10-24 14:40:03 +020015227};
15228
Johannes Berg55682962007-09-20 13:09:35 -040015229/* notification functions */
15230
Johannes Berg3bb20552014-05-26 13:52:25 +020015231void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
15232 enum nl80211_commands cmd)
Johannes Berg55682962007-09-20 13:09:35 -040015233{
15234 struct sk_buff *msg;
Johannes Berg86e8cf92013-06-19 10:57:22 +020015235 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -040015236
Johannes Berg3bb20552014-05-26 13:52:25 +020015237 WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
15238 cmd != NL80211_CMD_DEL_WIPHY);
15239
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070015240 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040015241 if (!msg)
15242 return;
15243
Johannes Berg3bb20552014-05-26 13:52:25 +020015244 if (nl80211_send_wiphy(rdev, cmd, msg, 0, 0, 0, &state) < 0) {
Johannes Berg55682962007-09-20 13:09:35 -040015245 nlmsg_free(msg);
15246 return;
15247 }
15248
Johannes Berg68eb5502013-11-19 15:19:38 +010015249 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015250 NL80211_MCGRP_CONFIG, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040015251}
15252
Denis Kenzior896ff062016-08-03 16:58:33 -050015253void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
15254 struct wireless_dev *wdev,
15255 enum nl80211_commands cmd)
15256{
15257 struct sk_buff *msg;
15258
Denis Kenzior896ff062016-08-03 16:58:33 -050015259 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
15260 if (!msg)
15261 return;
15262
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +020015263 if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, cmd) < 0) {
Denis Kenzior896ff062016-08-03 16:58:33 -050015264 nlmsg_free(msg);
15265 return;
15266 }
15267
15268 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15269 NL80211_MCGRP_CONFIG, GFP_KERNEL);
15270}
15271
Johannes Berg362a4152009-05-24 16:43:15 +020015272static int nl80211_add_scan_req(struct sk_buff *msg,
15273 struct cfg80211_registered_device *rdev)
15274{
15275 struct cfg80211_scan_request *req = rdev->scan_req;
15276 struct nlattr *nest;
15277 int i;
15278
15279 if (WARN_ON(!req))
15280 return 0;
15281
Michal Kubecekae0be8d2019-04-26 11:13:06 +020015282 nest = nla_nest_start_noflag(msg, NL80211_ATTR_SCAN_SSIDS);
Johannes Berg362a4152009-05-24 16:43:15 +020015283 if (!nest)
15284 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040015285 for (i = 0; i < req->n_ssids; i++) {
15286 if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
15287 goto nla_put_failure;
15288 }
Johannes Berg362a4152009-05-24 16:43:15 +020015289 nla_nest_end(msg, nest);
15290
Thomas Pedersen2032f3b2020-04-30 10:25:52 -070015291 if (req->flags & NL80211_SCAN_FLAG_FREQ_KHZ) {
15292 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQ_KHZ);
15293 if (!nest)
David S. Miller9360ffd2012-03-29 04:41:26 -040015294 goto nla_put_failure;
Thomas Pedersen2032f3b2020-04-30 10:25:52 -070015295 for (i = 0; i < req->n_channels; i++) {
15296 if (nla_put_u32(msg, i,
15297 ieee80211_channel_to_khz(req->channels[i])))
15298 goto nla_put_failure;
15299 }
15300 nla_nest_end(msg, nest);
15301 } else {
15302 nest = nla_nest_start_noflag(msg,
15303 NL80211_ATTR_SCAN_FREQUENCIES);
15304 if (!nest)
15305 goto nla_put_failure;
15306 for (i = 0; i < req->n_channels; i++) {
15307 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
15308 goto nla_put_failure;
15309 }
15310 nla_nest_end(msg, nest);
David S. Miller9360ffd2012-03-29 04:41:26 -040015311 }
Johannes Berg362a4152009-05-24 16:43:15 +020015312
David S. Miller9360ffd2012-03-29 04:41:26 -040015313 if (req->ie &&
15314 nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
15315 goto nla_put_failure;
Johannes Berg362a4152009-05-24 16:43:15 +020015316
Johannes Bergae917c92013-10-25 11:05:22 +020015317 if (req->flags &&
15318 nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
15319 goto nla_put_failure;
Sam Lefflered4737712012-10-11 21:03:31 -070015320
Avraham Stern1d762502016-07-05 17:10:13 +030015321 if (req->info.scan_start_tsf &&
15322 (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
15323 req->info.scan_start_tsf, NL80211_BSS_PAD) ||
15324 nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
15325 req->info.tsf_bssid)))
15326 goto nla_put_failure;
15327
Johannes Berg362a4152009-05-24 16:43:15 +020015328 return 0;
15329 nla_put_failure:
15330 return -ENOBUFS;
15331}
15332
Arend Van Spriel505a2e82016-12-16 11:21:54 +000015333static int nl80211_prep_scan_msg(struct sk_buff *msg,
Johannes Berga538e2d2009-06-16 19:56:42 +020015334 struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020015335 struct wireless_dev *wdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000015336 u32 portid, u32 seq, int flags,
Johannes Berga538e2d2009-06-16 19:56:42 +020015337 u32 cmd)
Johannes Berg2a519312009-02-10 21:25:55 +010015338{
15339 void *hdr;
15340
Eric W. Biederman15e47302012-09-07 20:12:54 +000015341 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg2a519312009-02-10 21:25:55 +010015342 if (!hdr)
15343 return -1;
15344
David S. Miller9360ffd2012-03-29 04:41:26 -040015345 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Bergfd014282012-06-18 19:17:03 +020015346 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
15347 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015348 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15349 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040015350 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +010015351
Johannes Berg362a4152009-05-24 16:43:15 +020015352 /* ignore errors and send incomplete event anyway */
15353 nl80211_add_scan_req(msg, rdev);
Johannes Berg2a519312009-02-10 21:25:55 +010015354
Johannes Berg053c0952015-01-16 22:09:00 +010015355 genlmsg_end(msg, hdr);
15356 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +010015357
15358 nla_put_failure:
15359 genlmsg_cancel(msg, hdr);
15360 return -EMSGSIZE;
15361}
15362
Luciano Coelho807f8a82011-05-11 17:09:35 +030015363static int
Arend Van Spriel505a2e82016-12-16 11:21:54 +000015364nl80211_prep_sched_scan_msg(struct sk_buff *msg,
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010015365 struct cfg80211_sched_scan_request *req, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030015366{
15367 void *hdr;
15368
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010015369 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Luciano Coelho807f8a82011-05-11 17:09:35 +030015370 if (!hdr)
15371 return -1;
15372
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010015373 if (nla_put_u32(msg, NL80211_ATTR_WIPHY,
15374 wiphy_to_rdev(req->wiphy)->wiphy_idx) ||
15375 nla_put_u32(msg, NL80211_ATTR_IFINDEX, req->dev->ifindex) ||
15376 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->reqid,
15377 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040015378 goto nla_put_failure;
Luciano Coelho807f8a82011-05-11 17:09:35 +030015379
Johannes Berg053c0952015-01-16 22:09:00 +010015380 genlmsg_end(msg, hdr);
15381 return 0;
Luciano Coelho807f8a82011-05-11 17:09:35 +030015382
15383 nla_put_failure:
15384 genlmsg_cancel(msg, hdr);
15385 return -EMSGSIZE;
15386}
15387
Johannes Berga538e2d2009-06-16 19:56:42 +020015388void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020015389 struct wireless_dev *wdev)
Johannes Berga538e2d2009-06-16 19:56:42 +020015390{
15391 struct sk_buff *msg;
15392
Thomas Graf58050fc2012-06-28 03:57:45 +000015393 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020015394 if (!msg)
15395 return;
15396
Arend Van Spriel505a2e82016-12-16 11:21:54 +000015397 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Berga538e2d2009-06-16 19:56:42 +020015398 NL80211_CMD_TRIGGER_SCAN) < 0) {
15399 nlmsg_free(msg);
15400 return;
15401 }
15402
Johannes Berg68eb5502013-11-19 15:19:38 +010015403 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015404 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020015405}
15406
Johannes Bergf9d15d12014-01-22 11:14:19 +020015407struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
15408 struct wireless_dev *wdev, bool aborted)
Johannes Berg2a519312009-02-10 21:25:55 +010015409{
15410 struct sk_buff *msg;
15411
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070015412 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010015413 if (!msg)
Johannes Bergf9d15d12014-01-22 11:14:19 +020015414 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010015415
Arend Van Spriel505a2e82016-12-16 11:21:54 +000015416 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Bergf9d15d12014-01-22 11:14:19 +020015417 aborted ? NL80211_CMD_SCAN_ABORTED :
15418 NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +010015419 nlmsg_free(msg);
Johannes Bergf9d15d12014-01-22 11:14:19 +020015420 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010015421 }
15422
Johannes Bergf9d15d12014-01-22 11:14:19 +020015423 return msg;
Johannes Berg2a519312009-02-10 21:25:55 +010015424}
15425
Arend Van Spriel505a2e82016-12-16 11:21:54 +000015426/* send message created by nl80211_build_scan_msg() */
15427void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
15428 struct sk_buff *msg)
Johannes Berg2a519312009-02-10 21:25:55 +010015429{
Johannes Berg2a519312009-02-10 21:25:55 +010015430 if (!msg)
15431 return;
15432
Johannes Berg68eb5502013-11-19 15:19:38 +010015433 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015434 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010015435}
15436
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010015437void nl80211_send_sched_scan(struct cfg80211_sched_scan_request *req, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030015438{
15439 struct sk_buff *msg;
15440
Thomas Graf58050fc2012-06-28 03:57:45 +000015441 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030015442 if (!msg)
15443 return;
15444
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010015445 if (nl80211_prep_sched_scan_msg(msg, req, cmd) < 0) {
Luciano Coelho807f8a82011-05-11 17:09:35 +030015446 nlmsg_free(msg);
15447 return;
15448 }
15449
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010015450 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(req->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015451 NL80211_MCGRP_SCAN, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030015452}
15453
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020015454static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
15455 struct regulatory_request *request)
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040015456{
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040015457 /* Userspace can always count this one always being set */
David S. Miller9360ffd2012-03-29 04:41:26 -040015458 if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
15459 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040015460
David S. Miller9360ffd2012-03-29 04:41:26 -040015461 if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
15462 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
15463 NL80211_REGDOM_TYPE_WORLD))
15464 goto nla_put_failure;
15465 } else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
15466 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
15467 NL80211_REGDOM_TYPE_CUSTOM_WORLD))
15468 goto nla_put_failure;
15469 } else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
15470 request->intersect) {
15471 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
15472 NL80211_REGDOM_TYPE_INTERSECTION))
15473 goto nla_put_failure;
15474 } else {
15475 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
15476 NL80211_REGDOM_TYPE_COUNTRY) ||
15477 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
15478 request->alpha2))
15479 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040015480 }
15481
Arik Nemtsovad30ca22014-12-15 19:25:59 +020015482 if (request->wiphy_idx != WIPHY_IDX_INVALID) {
15483 struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
15484
15485 if (wiphy &&
15486 nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
15487 goto nla_put_failure;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +020015488
15489 if (wiphy &&
15490 wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
15491 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
15492 goto nla_put_failure;
Arik Nemtsovad30ca22014-12-15 19:25:59 +020015493 }
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040015494
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020015495 return true;
15496
15497nla_put_failure:
15498 return false;
15499}
15500
15501/*
15502 * This can happen on global regulatory changes or device specific settings
15503 * based on custom regulatory domains.
15504 */
15505void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
15506 struct regulatory_request *request)
15507{
15508 struct sk_buff *msg;
15509 void *hdr;
15510
15511 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
15512 if (!msg)
15513 return;
15514
15515 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
zhong jiang24f6d762019-09-05 12:25:37 +080015516 if (!hdr)
15517 goto nla_put_failure;
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020015518
zhong jiang24f6d762019-09-05 12:25:37 +080015519 if (!nl80211_reg_change_event_fill(msg, request))
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020015520 goto nla_put_failure;
15521
Johannes Berg3b7b72e2011-10-22 19:05:51 +020015522 genlmsg_end(msg, hdr);
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040015523
Johannes Bergbc43b282009-07-25 10:54:13 +020015524 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010015525 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015526 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Bergbc43b282009-07-25 10:54:13 +020015527 rcu_read_unlock();
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040015528
15529 return;
15530
15531nla_put_failure:
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040015532 nlmsg_free(msg);
15533}
15534
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015535static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
15536 struct net_device *netdev,
15537 const u8 *buf, size_t len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030015538 enum nl80211_commands cmd, gfp_t gfp,
Jouni Malinen4d9ec732019-02-15 02:14:33 +020015539 int uapsd_queues, const u8 *req_ies,
15540 size_t req_ies_len)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015541{
15542 struct sk_buff *msg;
15543 void *hdr;
15544
Jouni Malinen4d9ec732019-02-15 02:14:33 +020015545 msg = nlmsg_new(100 + len + req_ies_len, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015546 if (!msg)
15547 return;
15548
15549 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
15550 if (!hdr) {
15551 nlmsg_free(msg);
15552 return;
15553 }
15554
David S. Miller9360ffd2012-03-29 04:41:26 -040015555 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15556 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Jouni Malinen4d9ec732019-02-15 02:14:33 +020015557 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
15558 (req_ies &&
15559 nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies)))
David S. Miller9360ffd2012-03-29 04:41:26 -040015560 goto nla_put_failure;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015561
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030015562 if (uapsd_queues >= 0) {
15563 struct nlattr *nla_wmm =
Michal Kubecekae0be8d2019-04-26 11:13:06 +020015564 nla_nest_start_noflag(msg, NL80211_ATTR_STA_WME);
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030015565 if (!nla_wmm)
15566 goto nla_put_failure;
15567
15568 if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
15569 uapsd_queues))
15570 goto nla_put_failure;
15571
15572 nla_nest_end(msg, nla_wmm);
15573 }
15574
Johannes Berg3b7b72e2011-10-22 19:05:51 +020015575 genlmsg_end(msg, hdr);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015576
Johannes Berg68eb5502013-11-19 15:19:38 +010015577 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015578 NL80211_MCGRP_MLME, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015579 return;
15580
15581 nla_put_failure:
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015582 nlmsg_free(msg);
15583}
15584
15585void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020015586 struct net_device *netdev, const u8 *buf,
15587 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015588{
15589 nl80211_send_mlme_event(rdev, netdev, buf, len,
Jouni Malinen4d9ec732019-02-15 02:14:33 +020015590 NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015591}
15592
15593void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
15594 struct net_device *netdev, const u8 *buf,
Jouni Malinen4d9ec732019-02-15 02:14:33 +020015595 size_t len, gfp_t gfp, int uapsd_queues,
15596 const u8 *req_ies, size_t req_ies_len)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015597{
Johannes Berge6d6e342009-07-01 21:26:47 +020015598 nl80211_send_mlme_event(rdev, netdev, buf, len,
Jouni Malinen4d9ec732019-02-15 02:14:33 +020015599 NL80211_CMD_ASSOCIATE, gfp, uapsd_queues,
15600 req_ies, req_ies_len);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015601}
15602
Jouni Malinen53b46b82009-03-27 20:53:56 +020015603void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020015604 struct net_device *netdev, const u8 *buf,
15605 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015606{
15607 nl80211_send_mlme_event(rdev, netdev, buf, len,
Jouni Malinen4d9ec732019-02-15 02:14:33 +020015608 NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015609}
15610
Jouni Malinen53b46b82009-03-27 20:53:56 +020015611void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
15612 struct net_device *netdev, const u8 *buf,
Johannes Berge6d6e342009-07-01 21:26:47 +020015613 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015614{
15615 nl80211_send_mlme_event(rdev, netdev, buf, len,
Jouni Malinen4d9ec732019-02-15 02:14:33 +020015616 NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020015617}
15618
Johannes Berg6ff57cf2013-05-16 00:55:00 +020015619void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
15620 size_t len)
Jouni Malinencf4e5942010-12-16 00:52:40 +020015621{
Johannes Berg947add32013-02-22 22:05:20 +010015622 struct wireless_dev *wdev = dev->ieee80211_ptr;
15623 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015624 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg6ff57cf2013-05-16 00:55:00 +020015625 const struct ieee80211_mgmt *mgmt = (void *)buf;
15626 u32 cmd;
Jouni Malinencf4e5942010-12-16 00:52:40 +020015627
Johannes Berg6ff57cf2013-05-16 00:55:00 +020015628 if (WARN_ON(len < 2))
15629 return;
15630
Jouni Malinen4d797fc2020-04-01 17:25:47 +030015631 if (ieee80211_is_deauth(mgmt->frame_control)) {
Johannes Berg6ff57cf2013-05-16 00:55:00 +020015632 cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
Jouni Malinen4d797fc2020-04-01 17:25:47 +030015633 } else if (ieee80211_is_disassoc(mgmt->frame_control)) {
Johannes Berg6ff57cf2013-05-16 00:55:00 +020015634 cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
Jouni Malinen4d797fc2020-04-01 17:25:47 +030015635 } else if (ieee80211_is_beacon(mgmt->frame_control)) {
15636 if (wdev->unprot_beacon_reported &&
15637 elapsed_jiffies_msecs(wdev->unprot_beacon_reported) < 10000)
15638 return;
15639 cmd = NL80211_CMD_UNPROT_BEACON;
15640 wdev->unprot_beacon_reported = jiffies;
15641 } else {
15642 return;
15643 }
Johannes Berg6ff57cf2013-05-16 00:55:00 +020015644
15645 trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
Jouni Malinen4d9ec732019-02-15 02:14:33 +020015646 nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1,
15647 NULL, 0);
Jouni Malinencf4e5942010-12-16 00:52:40 +020015648}
Johannes Berg6ff57cf2013-05-16 00:55:00 +020015649EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
Jouni Malinencf4e5942010-12-16 00:52:40 +020015650
Luis R. Rodriguez1b06bb42009-05-02 00:34:48 -040015651static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
15652 struct net_device *netdev, int cmd,
Johannes Berge6d6e342009-07-01 21:26:47 +020015653 const u8 *addr, gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030015654{
15655 struct sk_buff *msg;
15656 void *hdr;
15657
Johannes Berge6d6e342009-07-01 21:26:47 +020015658 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030015659 if (!msg)
15660 return;
15661
15662 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
15663 if (!hdr) {
15664 nlmsg_free(msg);
15665 return;
15666 }
15667
David S. Miller9360ffd2012-03-29 04:41:26 -040015668 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15669 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15670 nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
15671 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
15672 goto nla_put_failure;
Jouni Malinen1965c852009-04-22 21:38:25 +030015673
Johannes Berg3b7b72e2011-10-22 19:05:51 +020015674 genlmsg_end(msg, hdr);
Jouni Malinen1965c852009-04-22 21:38:25 +030015675
Johannes Berg68eb5502013-11-19 15:19:38 +010015676 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015677 NL80211_MCGRP_MLME, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030015678 return;
15679
15680 nla_put_failure:
Jouni Malinen1965c852009-04-22 21:38:25 +030015681 nlmsg_free(msg);
15682}
15683
15684void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020015685 struct net_device *netdev, const u8 *addr,
15686 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030015687{
15688 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
Johannes Berge6d6e342009-07-01 21:26:47 +020015689 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030015690}
15691
15692void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020015693 struct net_device *netdev, const u8 *addr,
15694 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030015695{
Johannes Berge6d6e342009-07-01 21:26:47 +020015696 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
15697 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030015698}
15699
Samuel Ortizb23aa672009-07-01 21:26:54 +020015700void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030015701 struct net_device *netdev,
15702 struct cfg80211_connect_resp_params *cr,
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020015703 gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020015704{
15705 struct sk_buff *msg;
15706 void *hdr;
15707
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030015708 msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
Arend Van Spriel76804d22018-05-22 10:19:06 +020015709 cr->fils.kek_len + cr->fils.pmk_len +
15710 (cr->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015711 if (!msg)
15712 return;
15713
15714 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
15715 if (!hdr) {
15716 nlmsg_free(msg);
15717 return;
15718 }
15719
David S. Miller9360ffd2012-03-29 04:41:26 -040015720 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15721 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030015722 (cr->bssid &&
15723 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
Jouni Malinenbf1ecd22016-05-31 00:16:50 +030015724 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030015725 cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
15726 cr->status) ||
15727 (cr->status < 0 &&
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020015728 (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030015729 nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
15730 cr->timeout_reason))) ||
15731 (cr->req_ie &&
15732 nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
15733 (cr->resp_ie &&
15734 nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030015735 cr->resp_ie)) ||
Arend Van Spriel76804d22018-05-22 10:19:06 +020015736 (cr->fils.update_erp_next_seq_num &&
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030015737 nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
Arend Van Spriel76804d22018-05-22 10:19:06 +020015738 cr->fils.erp_next_seq_num)) ||
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030015739 (cr->status == WLAN_STATUS_SUCCESS &&
Arend Van Spriel76804d22018-05-22 10:19:06 +020015740 ((cr->fils.kek &&
15741 nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils.kek_len,
15742 cr->fils.kek)) ||
15743 (cr->fils.pmk &&
15744 nla_put(msg, NL80211_ATTR_PMK, cr->fils.pmk_len, cr->fils.pmk)) ||
15745 (cr->fils.pmkid &&
15746 nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->fils.pmkid)))))
David S. Miller9360ffd2012-03-29 04:41:26 -040015747 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020015748
Johannes Berg3b7b72e2011-10-22 19:05:51 +020015749 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015750
Johannes Berg68eb5502013-11-19 15:19:38 +010015751 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015752 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015753 return;
15754
15755 nla_put_failure:
Samuel Ortizb23aa672009-07-01 21:26:54 +020015756 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015757}
15758
15759void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
Avraham Stern29ce6ec2017-04-26 10:58:49 +030015760 struct net_device *netdev,
15761 struct cfg80211_roam_info *info, gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020015762{
15763 struct sk_buff *msg;
15764 void *hdr;
Avraham Stern29ce6ec2017-04-26 10:58:49 +030015765 const u8 *bssid = info->bss ? info->bss->bssid : info->bssid;
Samuel Ortizb23aa672009-07-01 21:26:54 +020015766
Arend Van Spriele841b7b2018-05-22 10:19:07 +020015767 msg = nlmsg_new(100 + info->req_ie_len + info->resp_ie_len +
15768 info->fils.kek_len + info->fils.pmk_len +
15769 (info->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015770 if (!msg)
15771 return;
15772
15773 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
15774 if (!hdr) {
15775 nlmsg_free(msg);
15776 return;
15777 }
15778
David S. Miller9360ffd2012-03-29 04:41:26 -040015779 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15780 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15781 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
Avraham Stern29ce6ec2017-04-26 10:58:49 +030015782 (info->req_ie &&
15783 nla_put(msg, NL80211_ATTR_REQ_IE, info->req_ie_len,
15784 info->req_ie)) ||
15785 (info->resp_ie &&
15786 nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
Arend Van Spriele841b7b2018-05-22 10:19:07 +020015787 info->resp_ie)) ||
15788 (info->fils.update_erp_next_seq_num &&
15789 nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
15790 info->fils.erp_next_seq_num)) ||
15791 (info->fils.kek &&
15792 nla_put(msg, NL80211_ATTR_FILS_KEK, info->fils.kek_len,
15793 info->fils.kek)) ||
15794 (info->fils.pmk &&
15795 nla_put(msg, NL80211_ATTR_PMK, info->fils.pmk_len, info->fils.pmk)) ||
15796 (info->fils.pmkid &&
15797 nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, info->fils.pmkid)))
David S. Miller9360ffd2012-03-29 04:41:26 -040015798 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020015799
Johannes Berg3b7b72e2011-10-22 19:05:51 +020015800 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015801
Johannes Berg68eb5502013-11-19 15:19:38 +010015802 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015803 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015804 return;
15805
15806 nla_put_failure:
Samuel Ortizb23aa672009-07-01 21:26:54 +020015807 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015808}
15809
Avraham Stern503c1fb2017-09-29 14:21:49 +020015810void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
15811 struct net_device *netdev, const u8 *bssid)
15812{
15813 struct sk_buff *msg;
15814 void *hdr;
15815
15816 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
15817 if (!msg)
15818 return;
15819
15820 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PORT_AUTHORIZED);
15821 if (!hdr) {
15822 nlmsg_free(msg);
15823 return;
15824 }
15825
Chung-Hsien Hsuf4d75992019-05-09 09:48:25 +000015826 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15827 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15828 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
Avraham Stern503c1fb2017-09-29 14:21:49 +020015829 goto nla_put_failure;
15830
15831 genlmsg_end(msg, hdr);
15832
15833 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15834 NL80211_MCGRP_MLME, GFP_KERNEL);
15835 return;
15836
15837 nla_put_failure:
Avraham Stern503c1fb2017-09-29 14:21:49 +020015838 nlmsg_free(msg);
15839}
15840
Samuel Ortizb23aa672009-07-01 21:26:54 +020015841void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
15842 struct net_device *netdev, u16 reason,
Johannes Berg667503d2009-07-07 03:56:11 +020015843 const u8 *ie, size_t ie_len, bool from_ap)
Samuel Ortizb23aa672009-07-01 21:26:54 +020015844{
15845 struct sk_buff *msg;
15846 void *hdr;
15847
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010015848 msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015849 if (!msg)
15850 return;
15851
15852 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
15853 if (!hdr) {
15854 nlmsg_free(msg);
15855 return;
15856 }
15857
David S. Miller9360ffd2012-03-29 04:41:26 -040015858 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15859 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
David Spinadel86b6c462017-12-18 12:14:05 +020015860 (reason &&
David S. Miller9360ffd2012-03-29 04:41:26 -040015861 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
15862 (from_ap &&
15863 nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
15864 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
15865 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020015866
Johannes Berg3b7b72e2011-10-22 19:05:51 +020015867 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015868
Johannes Berg68eb5502013-11-19 15:19:38 +010015869 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015870 NL80211_MCGRP_MLME, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015871 return;
15872
15873 nla_put_failure:
Samuel Ortizb23aa672009-07-01 21:26:54 +020015874 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020015875}
15876
Johannes Berg04a773a2009-04-19 21:24:32 +020015877void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
15878 struct net_device *netdev, const u8 *bssid,
15879 gfp_t gfp)
15880{
15881 struct sk_buff *msg;
15882 void *hdr;
15883
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070015884 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020015885 if (!msg)
15886 return;
15887
15888 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
15889 if (!hdr) {
15890 nlmsg_free(msg);
15891 return;
15892 }
15893
David S. Miller9360ffd2012-03-29 04:41:26 -040015894 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15895 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15896 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
15897 goto nla_put_failure;
Johannes Berg04a773a2009-04-19 21:24:32 +020015898
Johannes Berg3b7b72e2011-10-22 19:05:51 +020015899 genlmsg_end(msg, hdr);
Johannes Berg04a773a2009-04-19 21:24:32 +020015900
Johannes Berg68eb5502013-11-19 15:19:38 +010015901 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015902 NL80211_MCGRP_MLME, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020015903 return;
15904
15905 nla_put_failure:
Johannes Berg04a773a2009-04-19 21:24:32 +020015906 nlmsg_free(msg);
15907}
15908
Johannes Berg947add32013-02-22 22:05:20 +010015909void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
Bob Copelandecbc12a2018-10-26 10:03:50 -040015910 const u8 *ie, u8 ie_len,
15911 int sig_dbm, gfp_t gfp)
Javier Cardonac93b5e72011-04-07 15:08:34 -070015912{
Johannes Berg947add32013-02-22 22:05:20 +010015913 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015914 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Javier Cardonac93b5e72011-04-07 15:08:34 -070015915 struct sk_buff *msg;
15916 void *hdr;
15917
Johannes Berg947add32013-02-22 22:05:20 +010015918 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
15919 return;
15920
15921 trace_cfg80211_notify_new_peer_candidate(dev, addr);
15922
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010015923 msg = nlmsg_new(100 + ie_len, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070015924 if (!msg)
15925 return;
15926
15927 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
15928 if (!hdr) {
15929 nlmsg_free(msg);
15930 return;
15931 }
15932
David S. Miller9360ffd2012-03-29 04:41:26 -040015933 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010015934 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
15935 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040015936 (ie_len && ie &&
Bob Copelandecbc12a2018-10-26 10:03:50 -040015937 nla_put(msg, NL80211_ATTR_IE, ie_len, ie)) ||
15938 (sig_dbm &&
15939 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)))
David S. Miller9360ffd2012-03-29 04:41:26 -040015940 goto nla_put_failure;
Javier Cardonac93b5e72011-04-07 15:08:34 -070015941
Johannes Berg3b7b72e2011-10-22 19:05:51 +020015942 genlmsg_end(msg, hdr);
Javier Cardonac93b5e72011-04-07 15:08:34 -070015943
Johannes Berg68eb5502013-11-19 15:19:38 +010015944 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015945 NL80211_MCGRP_MLME, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070015946 return;
15947
15948 nla_put_failure:
Javier Cardonac93b5e72011-04-07 15:08:34 -070015949 nlmsg_free(msg);
15950}
Johannes Berg947add32013-02-22 22:05:20 +010015951EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
Javier Cardonac93b5e72011-04-07 15:08:34 -070015952
Jouni Malinena3b8b052009-03-27 21:59:49 +020015953void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
15954 struct net_device *netdev, const u8 *addr,
15955 enum nl80211_key_type key_type, int key_id,
Johannes Berge6d6e342009-07-01 21:26:47 +020015956 const u8 *tsc, gfp_t gfp)
Jouni Malinena3b8b052009-03-27 21:59:49 +020015957{
15958 struct sk_buff *msg;
15959 void *hdr;
15960
Johannes Berge6d6e342009-07-01 21:26:47 +020015961 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020015962 if (!msg)
15963 return;
15964
15965 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
15966 if (!hdr) {
15967 nlmsg_free(msg);
15968 return;
15969 }
15970
David S. Miller9360ffd2012-03-29 04:41:26 -040015971 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15972 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15973 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
15974 nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
15975 (key_id != -1 &&
15976 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
15977 (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
15978 goto nla_put_failure;
Jouni Malinena3b8b052009-03-27 21:59:49 +020015979
Johannes Berg3b7b72e2011-10-22 19:05:51 +020015980 genlmsg_end(msg, hdr);
Jouni Malinena3b8b052009-03-27 21:59:49 +020015981
Johannes Berg68eb5502013-11-19 15:19:38 +010015982 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015983 NL80211_MCGRP_MLME, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020015984 return;
15985
15986 nla_put_failure:
Jouni Malinena3b8b052009-03-27 21:59:49 +020015987 nlmsg_free(msg);
15988}
15989
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040015990void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
15991 struct ieee80211_channel *channel_before,
15992 struct ieee80211_channel *channel_after)
15993{
15994 struct sk_buff *msg;
15995 void *hdr;
15996 struct nlattr *nl_freq;
15997
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070015998 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040015999 if (!msg)
16000 return;
16001
16002 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
16003 if (!hdr) {
16004 nlmsg_free(msg);
16005 return;
16006 }
16007
16008 /*
16009 * Since we are applying the beacon hint to a wiphy we know its
16010 * wiphy_idx is valid
16011 */
David S. Miller9360ffd2012-03-29 04:41:26 -040016012 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
16013 goto nla_put_failure;
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016014
16015 /* Before */
Michal Kubecekae0be8d2019-04-26 11:13:06 +020016016 nl_freq = nla_nest_start_noflag(msg, NL80211_ATTR_FREQ_BEFORE);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016017 if (!nl_freq)
16018 goto nla_put_failure;
Haim Dreyfuss50f32712018-04-20 13:49:26 +030016019
16020 if (nl80211_msg_put_channel(msg, wiphy, channel_before, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016021 goto nla_put_failure;
16022 nla_nest_end(msg, nl_freq);
16023
16024 /* After */
Michal Kubecekae0be8d2019-04-26 11:13:06 +020016025 nl_freq = nla_nest_start_noflag(msg, NL80211_ATTR_FREQ_AFTER);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016026 if (!nl_freq)
16027 goto nla_put_failure;
Haim Dreyfuss50f32712018-04-20 13:49:26 +030016028
16029 if (nl80211_msg_put_channel(msg, wiphy, channel_after, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016030 goto nla_put_failure;
16031 nla_nest_end(msg, nl_freq);
16032
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016033 genlmsg_end(msg, hdr);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016034
Johannes Berg463d0182009-07-14 00:33:35 +020016035 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010016036 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016037 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Berg463d0182009-07-14 00:33:35 +020016038 rcu_read_unlock();
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016039
16040 return;
16041
16042nla_put_failure:
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016043 nlmsg_free(msg);
16044}
16045
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016046static void nl80211_send_remain_on_chan_event(
16047 int cmd, struct cfg80211_registered_device *rdev,
Johannes Berg71bbc992012-06-15 15:30:18 +020016048 struct wireless_dev *wdev, u64 cookie,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016049 struct ieee80211_channel *chan,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016050 unsigned int duration, gfp_t gfp)
16051{
16052 struct sk_buff *msg;
16053 void *hdr;
16054
16055 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16056 if (!msg)
16057 return;
16058
16059 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
16060 if (!hdr) {
16061 nlmsg_free(msg);
16062 return;
16063 }
16064
David S. Miller9360ffd2012-03-29 04:41:26 -040016065 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020016066 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
16067 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020016068 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
16069 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040016070 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
Johannes Berg42d97a52012-11-08 18:31:02 +010016071 nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
16072 NL80211_CHAN_NO_HT) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020016073 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
16074 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040016075 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016076
David S. Miller9360ffd2012-03-29 04:41:26 -040016077 if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
16078 nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
16079 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016080
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016081 genlmsg_end(msg, hdr);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016082
Johannes Berg68eb5502013-11-19 15:19:38 +010016083 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016084 NL80211_MCGRP_MLME, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016085 return;
16086
16087 nla_put_failure:
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016088 nlmsg_free(msg);
16089}
16090
Johannes Berg947add32013-02-22 22:05:20 +010016091void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
16092 struct ieee80211_channel *chan,
16093 unsigned int duration, gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016094{
Johannes Berg947add32013-02-22 22:05:20 +010016095 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016096 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010016097
16098 trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016099 nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
Johannes Berg71bbc992012-06-15 15:30:18 +020016100 rdev, wdev, cookie, chan,
Johannes Berg42d97a52012-11-08 18:31:02 +010016101 duration, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016102}
Johannes Berg947add32013-02-22 22:05:20 +010016103EXPORT_SYMBOL(cfg80211_ready_on_channel);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016104
Johannes Berg947add32013-02-22 22:05:20 +010016105void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
16106 struct ieee80211_channel *chan,
16107 gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016108{
Johannes Berg947add32013-02-22 22:05:20 +010016109 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016110 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010016111
16112 trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016113 nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
Johannes Berg42d97a52012-11-08 18:31:02 +010016114 rdev, wdev, cookie, chan, 0, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016115}
Johannes Berg947add32013-02-22 22:05:20 +010016116EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016117
James Prestwood1c38c7f2019-06-12 12:35:09 -070016118void cfg80211_tx_mgmt_expired(struct wireless_dev *wdev, u64 cookie,
16119 struct ieee80211_channel *chan,
16120 gfp_t gfp)
16121{
16122 struct wiphy *wiphy = wdev->wiphy;
16123 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
16124
16125 trace_cfg80211_tx_mgmt_expired(wdev, cookie, chan);
16126 nl80211_send_remain_on_chan_event(NL80211_CMD_FRAME_WAIT_CANCEL,
16127 rdev, wdev, cookie, chan, 0, gfp);
16128}
16129EXPORT_SYMBOL(cfg80211_tx_mgmt_expired);
16130
Johannes Berg947add32013-02-22 22:05:20 +010016131void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
16132 struct station_info *sinfo, gfp_t gfp)
Johannes Berg98b62182009-12-23 13:15:44 +010016133{
Johannes Berg947add32013-02-22 22:05:20 +010016134 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016135 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg98b62182009-12-23 13:15:44 +010016136 struct sk_buff *msg;
16137
Johannes Berg947add32013-02-22 22:05:20 +010016138 trace_cfg80211_new_sta(dev, mac_addr, sinfo);
16139
Thomas Graf58050fc2012-06-28 03:57:45 +000016140 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010016141 if (!msg)
16142 return;
16143
Johannes Bergcf5ead82014-11-14 17:14:00 +010016144 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
John W. Linville66266b32012-03-15 13:25:41 -040016145 rdev, dev, mac_addr, sinfo) < 0) {
Johannes Berg98b62182009-12-23 13:15:44 +010016146 nlmsg_free(msg);
16147 return;
16148 }
16149
Johannes Berg68eb5502013-11-19 15:19:38 +010016150 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016151 NL80211_MCGRP_MLME, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010016152}
Johannes Berg947add32013-02-22 22:05:20 +010016153EXPORT_SYMBOL(cfg80211_new_sta);
Johannes Berg98b62182009-12-23 13:15:44 +010016154
Johannes Bergcf5ead82014-11-14 17:14:00 +010016155void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
16156 struct station_info *sinfo, gfp_t gfp)
Jouni Malinenec15e682011-03-23 15:29:52 +020016157{
Johannes Berg947add32013-02-22 22:05:20 +010016158 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016159 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinenec15e682011-03-23 15:29:52 +020016160 struct sk_buff *msg;
Johannes Berg73887fd2018-05-18 09:57:55 +020016161 struct station_info empty_sinfo = {};
Johannes Bergcf5ead82014-11-14 17:14:00 +010016162
Johannes Berg73887fd2018-05-18 09:57:55 +020016163 if (!sinfo)
16164 sinfo = &empty_sinfo;
Jouni Malinenec15e682011-03-23 15:29:52 +020016165
Johannes Berg947add32013-02-22 22:05:20 +010016166 trace_cfg80211_del_sta(dev, mac_addr);
16167
Thomas Graf58050fc2012-06-28 03:57:45 +000016168 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg7ea3e112018-05-18 11:40:44 +020016169 if (!msg) {
16170 cfg80211_sinfo_release_content(sinfo);
Johannes Berg73887fd2018-05-18 09:57:55 +020016171 return;
Johannes Berg7ea3e112018-05-18 11:40:44 +020016172 }
Jouni Malinenec15e682011-03-23 15:29:52 +020016173
Johannes Bergcf5ead82014-11-14 17:14:00 +010016174 if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
Johannes Berg57007122015-01-16 21:05:02 +010016175 rdev, dev, mac_addr, sinfo) < 0) {
Jouni Malinenec15e682011-03-23 15:29:52 +020016176 nlmsg_free(msg);
Johannes Berg73887fd2018-05-18 09:57:55 +020016177 return;
Jouni Malinenec15e682011-03-23 15:29:52 +020016178 }
16179
Johannes Berg68eb5502013-11-19 15:19:38 +010016180 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016181 NL80211_MCGRP_MLME, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020016182}
Johannes Bergcf5ead82014-11-14 17:14:00 +010016183EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
Jouni Malinenec15e682011-03-23 15:29:52 +020016184
Johannes Berg947add32013-02-22 22:05:20 +010016185void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
16186 enum nl80211_connect_failed_reason reason,
16187 gfp_t gfp)
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053016188{
Johannes Berg947add32013-02-22 22:05:20 +010016189 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016190 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053016191 struct sk_buff *msg;
16192 void *hdr;
16193
16194 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
16195 if (!msg)
16196 return;
16197
16198 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED);
16199 if (!hdr) {
16200 nlmsg_free(msg);
16201 return;
16202 }
16203
16204 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
16205 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
16206 nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason))
16207 goto nla_put_failure;
16208
16209 genlmsg_end(msg, hdr);
16210
Johannes Berg68eb5502013-11-19 15:19:38 +010016211 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016212 NL80211_MCGRP_MLME, gfp);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053016213 return;
16214
16215 nla_put_failure:
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053016216 nlmsg_free(msg);
16217}
Johannes Berg947add32013-02-22 22:05:20 +010016218EXPORT_SYMBOL(cfg80211_conn_failed);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053016219
Johannes Bergb92ab5d2011-11-04 11:18:19 +010016220static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
16221 const u8 *addr, gfp_t gfp)
Johannes Berg28946da2011-11-04 11:18:12 +010016222{
16223 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016224 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg28946da2011-11-04 11:18:12 +010016225 struct sk_buff *msg;
16226 void *hdr;
Mark Rutland6aa7de02017-10-23 14:07:29 -070016227 u32 nlportid = READ_ONCE(wdev->ap_unexpected_nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010016228
Eric W. Biederman15e47302012-09-07 20:12:54 +000016229 if (!nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010016230 return false;
16231
16232 msg = nlmsg_new(100, gfp);
16233 if (!msg)
16234 return true;
16235
Johannes Bergb92ab5d2011-11-04 11:18:19 +010016236 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Johannes Berg28946da2011-11-04 11:18:12 +010016237 if (!hdr) {
16238 nlmsg_free(msg);
16239 return true;
16240 }
16241
David S. Miller9360ffd2012-03-29 04:41:26 -040016242 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16243 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
16244 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
16245 goto nla_put_failure;
Johannes Berg28946da2011-11-04 11:18:12 +010016246
Johannes Berg9c90a9f2013-06-04 12:46:03 +020016247 genlmsg_end(msg, hdr);
Eric W. Biederman15e47302012-09-07 20:12:54 +000016248 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010016249 return true;
16250
16251 nla_put_failure:
Johannes Berg28946da2011-11-04 11:18:12 +010016252 nlmsg_free(msg);
16253 return true;
16254}
16255
Johannes Berg947add32013-02-22 22:05:20 +010016256bool cfg80211_rx_spurious_frame(struct net_device *dev,
16257 const u8 *addr, gfp_t gfp)
Johannes Bergb92ab5d2011-11-04 11:18:19 +010016258{
Johannes Berg947add32013-02-22 22:05:20 +010016259 struct wireless_dev *wdev = dev->ieee80211_ptr;
16260 bool ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010016261
Johannes Berg947add32013-02-22 22:05:20 +010016262 trace_cfg80211_rx_spurious_frame(dev, addr);
16263
16264 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
16265 wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
16266 trace_cfg80211_return_bool(false);
16267 return false;
16268 }
16269 ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
16270 addr, gfp);
16271 trace_cfg80211_return_bool(ret);
16272 return ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010016273}
Johannes Berg947add32013-02-22 22:05:20 +010016274EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
16275
16276bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
16277 const u8 *addr, gfp_t gfp)
16278{
16279 struct wireless_dev *wdev = dev->ieee80211_ptr;
16280 bool ret;
16281
16282 trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
16283
16284 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
16285 wdev->iftype != NL80211_IFTYPE_P2P_GO &&
16286 wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
16287 trace_cfg80211_return_bool(false);
16288 return false;
16289 }
16290 ret = __nl80211_unexpected_frame(dev,
16291 NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
16292 addr, gfp);
16293 trace_cfg80211_return_bool(ret);
16294 return ret;
16295}
16296EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
Johannes Bergb92ab5d2011-11-04 11:18:19 +010016297
Johannes Berg2e161f782010-08-12 15:38:38 +020016298int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000016299 struct wireless_dev *wdev, u32 nlportid,
Johannes Berg804483e2012-03-05 22:18:41 +010016300 int freq, int sig_dbm,
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030016301 const u8 *buf, size_t len, u32 flags, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020016302{
Johannes Berg71bbc992012-06-15 15:30:18 +020016303 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020016304 struct sk_buff *msg;
16305 void *hdr;
Jouni Malinen026331c2010-02-15 12:53:10 +020016306
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010016307 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020016308 if (!msg)
16309 return -ENOMEM;
16310
Johannes Berg2e161f782010-08-12 15:38:38 +020016311 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
Jouni Malinen026331c2010-02-15 12:53:10 +020016312 if (!hdr) {
16313 nlmsg_free(msg);
16314 return -ENOMEM;
16315 }
16316
David S. Miller9360ffd2012-03-29 04:41:26 -040016317 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020016318 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
16319 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020016320 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
16321 NL80211_ATTR_PAD) ||
Thomas Pedersene76fede2020-04-30 10:25:50 -070016322 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(freq)) ||
Thomas Pedersen942ba882020-04-30 10:25:51 -070016323 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, freq % 1000) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040016324 (sig_dbm &&
16325 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030016326 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
16327 (flags &&
16328 nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
David S. Miller9360ffd2012-03-29 04:41:26 -040016329 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020016330
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016331 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020016332
Eric W. Biederman15e47302012-09-07 20:12:54 +000016333 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Jouni Malinen026331c2010-02-15 12:53:10 +020016334
16335 nla_put_failure:
Jouni Malinen026331c2010-02-15 12:53:10 +020016336 nlmsg_free(msg);
16337 return -ENOBUFS;
16338}
16339
Markus Theildca9ca22020-05-08 16:42:00 +020016340static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie,
16341 const u8 *buf, size_t len, bool ack,
16342 gfp_t gfp, enum nl80211_commands command)
Jouni Malinen026331c2010-02-15 12:53:10 +020016343{
Johannes Berg947add32013-02-22 22:05:20 +010016344 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016345 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg71bbc992012-06-15 15:30:18 +020016346 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020016347 struct sk_buff *msg;
16348 void *hdr;
16349
Markus Theildca9ca22020-05-08 16:42:00 +020016350 if (command == NL80211_CMD_FRAME_TX_STATUS)
16351 trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
16352 else
16353 trace_cfg80211_control_port_tx_status(wdev, cookie, ack);
Johannes Berg947add32013-02-22 22:05:20 +010016354
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010016355 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020016356 if (!msg)
16357 return;
16358
Markus Theildca9ca22020-05-08 16:42:00 +020016359 hdr = nl80211hdr_put(msg, 0, 0, 0, command);
Jouni Malinen026331c2010-02-15 12:53:10 +020016360 if (!hdr) {
16361 nlmsg_free(msg);
16362 return;
16363 }
16364
David S. Miller9360ffd2012-03-29 04:41:26 -040016365 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020016366 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
16367 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020016368 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
16369 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040016370 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020016371 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
16372 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040016373 (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
16374 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020016375
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016376 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020016377
Johannes Berg68eb5502013-11-19 15:19:38 +010016378 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016379 NL80211_MCGRP_MLME, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020016380 return;
16381
Markus Theildca9ca22020-05-08 16:42:00 +020016382nla_put_failure:
Jouni Malinen026331c2010-02-15 12:53:10 +020016383 nlmsg_free(msg);
16384}
Markus Theildca9ca22020-05-08 16:42:00 +020016385
16386void cfg80211_control_port_tx_status(struct wireless_dev *wdev, u64 cookie,
16387 const u8 *buf, size_t len, bool ack,
16388 gfp_t gfp)
16389{
16390 nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp,
16391 NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS);
16392}
16393EXPORT_SYMBOL(cfg80211_control_port_tx_status);
16394
16395void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
16396 const u8 *buf, size_t len, bool ack, gfp_t gfp)
16397{
16398 nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp,
16399 NL80211_CMD_FRAME_TX_STATUS);
16400}
Johannes Berg947add32013-02-22 22:05:20 +010016401EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
Jouni Malinen026331c2010-02-15 12:53:10 +020016402
Denis Kenzior6a671a52018-03-26 12:52:41 -050016403static int __nl80211_rx_control_port(struct net_device *dev,
Denis Kenziora948f712018-07-03 15:05:48 -050016404 struct sk_buff *skb,
Denis Kenzior6a671a52018-03-26 12:52:41 -050016405 bool unencrypted, gfp_t gfp)
16406{
16407 struct wireless_dev *wdev = dev->ieee80211_ptr;
16408 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Denis Kenziora948f712018-07-03 15:05:48 -050016409 struct ethhdr *ehdr = eth_hdr(skb);
Johannes Berg8d74a622020-02-24 10:19:12 +010016410 const u8 *addr = ehdr->h_source;
Denis Kenziora948f712018-07-03 15:05:48 -050016411 u16 proto = be16_to_cpu(skb->protocol);
Denis Kenzior6a671a52018-03-26 12:52:41 -050016412 struct sk_buff *msg;
16413 void *hdr;
Denis Kenziora948f712018-07-03 15:05:48 -050016414 struct nlattr *frame;
16415
Denis Kenzior6a671a52018-03-26 12:52:41 -050016416 u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid);
16417
16418 if (!nlportid)
16419 return -ENOENT;
16420
Denis Kenziora948f712018-07-03 15:05:48 -050016421 msg = nlmsg_new(100 + skb->len, gfp);
Denis Kenzior6a671a52018-03-26 12:52:41 -050016422 if (!msg)
16423 return -ENOMEM;
16424
16425 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME);
16426 if (!hdr) {
16427 nlmsg_free(msg);
16428 return -ENOBUFS;
16429 }
16430
16431 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16432 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
16433 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
16434 NL80211_ATTR_PAD) ||
Johannes Berg8d74a622020-02-24 10:19:12 +010016435 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Denis Kenzior6a671a52018-03-26 12:52:41 -050016436 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
16437 (unencrypted && nla_put_flag(msg,
16438 NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
16439 goto nla_put_failure;
16440
Denis Kenziora948f712018-07-03 15:05:48 -050016441 frame = nla_reserve(msg, NL80211_ATTR_FRAME, skb->len);
16442 if (!frame)
16443 goto nla_put_failure;
16444
16445 skb_copy_bits(skb, 0, nla_data(frame), skb->len);
Denis Kenzior6a671a52018-03-26 12:52:41 -050016446 genlmsg_end(msg, hdr);
16447
16448 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
16449
16450 nla_put_failure:
16451 nlmsg_free(msg);
16452 return -ENOBUFS;
16453}
16454
16455bool cfg80211_rx_control_port(struct net_device *dev,
Denis Kenziora948f712018-07-03 15:05:48 -050016456 struct sk_buff *skb, bool unencrypted)
Denis Kenzior6a671a52018-03-26 12:52:41 -050016457{
16458 int ret;
16459
Denis Kenziora948f712018-07-03 15:05:48 -050016460 trace_cfg80211_rx_control_port(dev, skb, unencrypted);
16461 ret = __nl80211_rx_control_port(dev, skb, unencrypted, GFP_ATOMIC);
Denis Kenzior6a671a52018-03-26 12:52:41 -050016462 trace_cfg80211_return_bool(ret == 0);
16463 return ret == 0;
16464}
16465EXPORT_SYMBOL(cfg80211_rx_control_port);
16466
Johannes Berg5b97f492014-11-26 12:37:43 +010016467static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
16468 const char *mac, gfp_t gfp)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016469{
Johannes Berg947add32013-02-22 22:05:20 +010016470 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg5b97f492014-11-26 12:37:43 +010016471 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
16472 struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16473 void **cb;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016474
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016475 if (!msg)
Johannes Berg5b97f492014-11-26 12:37:43 +010016476 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016477
Johannes Berg5b97f492014-11-26 12:37:43 +010016478 cb = (void **)msg->cb;
16479
16480 cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
16481 if (!cb[0]) {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016482 nlmsg_free(msg);
Johannes Berg5b97f492014-11-26 12:37:43 +010016483 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016484 }
16485
David S. Miller9360ffd2012-03-29 04:41:26 -040016486 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010016487 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
David S. Miller9360ffd2012-03-29 04:41:26 -040016488 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016489
Johannes Berg5b97f492014-11-26 12:37:43 +010016490 if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016491 goto nla_put_failure;
16492
Michal Kubecekae0be8d2019-04-26 11:13:06 +020016493 cb[1] = nla_nest_start_noflag(msg, NL80211_ATTR_CQM);
Johannes Berg5b97f492014-11-26 12:37:43 +010016494 if (!cb[1])
16495 goto nla_put_failure;
16496
16497 cb[2] = rdev;
16498
16499 return msg;
16500 nla_put_failure:
16501 nlmsg_free(msg);
16502 return NULL;
16503}
16504
16505static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
16506{
16507 void **cb = (void **)msg->cb;
16508 struct cfg80211_registered_device *rdev = cb[2];
16509
16510 nla_nest_end(msg, cb[1]);
16511 genlmsg_end(msg, cb[0]);
16512
16513 memset(msg->cb, 0, sizeof(msg->cb));
16514
16515 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16516 NL80211_MCGRP_MLME, gfp);
16517}
16518
16519void cfg80211_cqm_rssi_notify(struct net_device *dev,
16520 enum nl80211_cqm_rssi_threshold_event rssi_event,
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010016521 s32 rssi_level, gfp_t gfp)
Johannes Berg5b97f492014-11-26 12:37:43 +010016522{
16523 struct sk_buff *msg;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010016524 struct wireless_dev *wdev = dev->ieee80211_ptr;
16525 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg5b97f492014-11-26 12:37:43 +010016526
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010016527 trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
Johannes Berg5b97f492014-11-26 12:37:43 +010016528
Johannes Berg98f03342014-11-26 12:42:02 +010016529 if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
16530 rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
16531 return;
16532
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010016533 if (wdev->cqm_config) {
16534 wdev->cqm_config->last_rssi_event_value = rssi_level;
16535
16536 cfg80211_cqm_rssi_update(rdev, dev);
16537
16538 if (rssi_level == 0)
16539 rssi_level = wdev->cqm_config->last_rssi_event_value;
16540 }
16541
Johannes Berg5b97f492014-11-26 12:37:43 +010016542 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
16543 if (!msg)
16544 return;
16545
David S. Miller9360ffd2012-03-29 04:41:26 -040016546 if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
16547 rssi_event))
16548 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016549
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010016550 if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
16551 rssi_level))
16552 goto nla_put_failure;
16553
Johannes Berg5b97f492014-11-26 12:37:43 +010016554 cfg80211_send_cqm(msg, gfp);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016555
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016556 return;
16557
16558 nla_put_failure:
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016559 nlmsg_free(msg);
16560}
Johannes Berg947add32013-02-22 22:05:20 +010016561EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020016562
Johannes Berg5b97f492014-11-26 12:37:43 +010016563void cfg80211_cqm_txe_notify(struct net_device *dev,
16564 const u8 *peer, u32 num_packets,
16565 u32 rate, u32 intvl, gfp_t gfp)
16566{
16567 struct sk_buff *msg;
16568
16569 msg = cfg80211_prepare_cqm(dev, peer, gfp);
16570 if (!msg)
16571 return;
16572
16573 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
16574 goto nla_put_failure;
16575
16576 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
16577 goto nla_put_failure;
16578
16579 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
16580 goto nla_put_failure;
16581
16582 cfg80211_send_cqm(msg, gfp);
16583 return;
16584
16585 nla_put_failure:
16586 nlmsg_free(msg);
16587}
16588EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
16589
16590void cfg80211_cqm_pktloss_notify(struct net_device *dev,
16591 const u8 *peer, u32 num_packets, gfp_t gfp)
16592{
16593 struct sk_buff *msg;
16594
16595 trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
16596
16597 msg = cfg80211_prepare_cqm(dev, peer, gfp);
16598 if (!msg)
16599 return;
16600
16601 if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
16602 goto nla_put_failure;
16603
16604 cfg80211_send_cqm(msg, gfp);
16605 return;
16606
16607 nla_put_failure:
16608 nlmsg_free(msg);
16609}
16610EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
16611
Johannes Berg98f03342014-11-26 12:42:02 +010016612void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
16613{
16614 struct sk_buff *msg;
16615
16616 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
16617 if (!msg)
16618 return;
16619
16620 if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
16621 goto nla_put_failure;
16622
16623 cfg80211_send_cqm(msg, gfp);
16624 return;
16625
16626 nla_put_failure:
16627 nlmsg_free(msg);
16628}
16629EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
16630
Johannes Berg947add32013-02-22 22:05:20 +010016631static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
16632 struct net_device *netdev, const u8 *bssid,
16633 const u8 *replay_ctr, gfp_t gfp)
Johannes Berge5497d72011-07-05 16:35:40 +020016634{
16635 struct sk_buff *msg;
16636 struct nlattr *rekey_attr;
16637 void *hdr;
16638
Thomas Graf58050fc2012-06-28 03:57:45 +000016639 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020016640 if (!msg)
16641 return;
16642
16643 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
16644 if (!hdr) {
16645 nlmsg_free(msg);
16646 return;
16647 }
16648
David S. Miller9360ffd2012-03-29 04:41:26 -040016649 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16650 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
16651 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
16652 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020016653
Michal Kubecekae0be8d2019-04-26 11:13:06 +020016654 rekey_attr = nla_nest_start_noflag(msg, NL80211_ATTR_REKEY_DATA);
Johannes Berge5497d72011-07-05 16:35:40 +020016655 if (!rekey_attr)
16656 goto nla_put_failure;
16657
David S. Miller9360ffd2012-03-29 04:41:26 -040016658 if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
16659 NL80211_REPLAY_CTR_LEN, replay_ctr))
16660 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020016661
16662 nla_nest_end(msg, rekey_attr);
16663
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016664 genlmsg_end(msg, hdr);
Johannes Berge5497d72011-07-05 16:35:40 +020016665
Johannes Berg68eb5502013-11-19 15:19:38 +010016666 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016667 NL80211_MCGRP_MLME, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020016668 return;
16669
16670 nla_put_failure:
Johannes Berge5497d72011-07-05 16:35:40 +020016671 nlmsg_free(msg);
16672}
16673
Johannes Berg947add32013-02-22 22:05:20 +010016674void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
16675 const u8 *replay_ctr, gfp_t gfp)
16676{
16677 struct wireless_dev *wdev = dev->ieee80211_ptr;
16678 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016679 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010016680
16681 trace_cfg80211_gtk_rekey_notify(dev, bssid);
16682 nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
16683}
16684EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
16685
16686static void
16687nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
16688 struct net_device *netdev, int index,
16689 const u8 *bssid, bool preauth, gfp_t gfp)
Jouni Malinenc9df56b2011-09-16 18:56:23 +030016690{
16691 struct sk_buff *msg;
16692 struct nlattr *attr;
16693 void *hdr;
16694
Thomas Graf58050fc2012-06-28 03:57:45 +000016695 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030016696 if (!msg)
16697 return;
16698
16699 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
16700 if (!hdr) {
16701 nlmsg_free(msg);
16702 return;
16703 }
16704
David S. Miller9360ffd2012-03-29 04:41:26 -040016705 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16706 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
16707 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030016708
Michal Kubecekae0be8d2019-04-26 11:13:06 +020016709 attr = nla_nest_start_noflag(msg, NL80211_ATTR_PMKSA_CANDIDATE);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030016710 if (!attr)
16711 goto nla_put_failure;
16712
David S. Miller9360ffd2012-03-29 04:41:26 -040016713 if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
16714 nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
16715 (preauth &&
16716 nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
16717 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030016718
16719 nla_nest_end(msg, attr);
16720
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016721 genlmsg_end(msg, hdr);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030016722
Johannes Berg68eb5502013-11-19 15:19:38 +010016723 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016724 NL80211_MCGRP_MLME, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030016725 return;
16726
16727 nla_put_failure:
Jouni Malinenc9df56b2011-09-16 18:56:23 +030016728 nlmsg_free(msg);
16729}
16730
Johannes Berg947add32013-02-22 22:05:20 +010016731void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
16732 const u8 *bssid, bool preauth, gfp_t gfp)
16733{
16734 struct wireless_dev *wdev = dev->ieee80211_ptr;
16735 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016736 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010016737
16738 trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
16739 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
16740}
16741EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
16742
16743static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
16744 struct net_device *netdev,
16745 struct cfg80211_chan_def *chandef,
Luciano Coelhof8d75522014-11-07 14:31:35 +020016746 gfp_t gfp,
16747 enum nl80211_commands notif,
16748 u8 count)
Thomas Pedersen53145262012-04-06 13:35:47 -070016749{
16750 struct sk_buff *msg;
16751 void *hdr;
16752
Thomas Graf58050fc2012-06-28 03:57:45 +000016753 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070016754 if (!msg)
16755 return;
16756
Luciano Coelhof8d75522014-11-07 14:31:35 +020016757 hdr = nl80211hdr_put(msg, 0, 0, 0, notif);
Thomas Pedersen53145262012-04-06 13:35:47 -070016758 if (!hdr) {
16759 nlmsg_free(msg);
16760 return;
16761 }
16762
Johannes Berg683b6d32012-11-08 21:25:48 +010016763 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
16764 goto nla_put_failure;
16765
16766 if (nl80211_send_chandef(msg, chandef))
John W. Linville7eab0f62012-04-12 14:25:14 -040016767 goto nla_put_failure;
Thomas Pedersen53145262012-04-06 13:35:47 -070016768
Luciano Coelhof8d75522014-11-07 14:31:35 +020016769 if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) &&
16770 (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count)))
16771 goto nla_put_failure;
16772
Thomas Pedersen53145262012-04-06 13:35:47 -070016773 genlmsg_end(msg, hdr);
16774
Johannes Berg68eb5502013-11-19 15:19:38 +010016775 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016776 NL80211_MCGRP_MLME, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070016777 return;
16778
16779 nla_put_failure:
Thomas Pedersen53145262012-04-06 13:35:47 -070016780 nlmsg_free(msg);
16781}
16782
Johannes Berg947add32013-02-22 22:05:20 +010016783void cfg80211_ch_switch_notify(struct net_device *dev,
16784 struct cfg80211_chan_def *chandef)
Thomas Pedersen84f10702012-07-12 16:17:33 -070016785{
Johannes Berg947add32013-02-22 22:05:20 +010016786 struct wireless_dev *wdev = dev->ieee80211_ptr;
16787 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016788 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010016789
Simon Wunderliche487eae2013-11-21 18:19:51 +010016790 ASSERT_WDEV_LOCK(wdev);
Johannes Berg947add32013-02-22 22:05:20 +010016791
Simon Wunderliche487eae2013-11-21 18:19:51 +010016792 trace_cfg80211_ch_switch_notify(dev, chandef);
Johannes Berg947add32013-02-22 22:05:20 +010016793
Michal Kazior9e0e2962014-01-29 14:22:27 +010016794 wdev->chandef = *chandef;
Janusz Dziedzic96f55f12014-01-24 14:29:21 +010016795 wdev->preset_chandef = *chandef;
Sergey Matyukevich5dc8cdc2019-03-26 09:27:37 +000016796
16797 if (wdev->iftype == NL80211_IFTYPE_STATION &&
16798 !WARN_ON(!wdev->current_bss))
Sergey Matyukevich0afd4252019-07-26 16:39:34 +000016799 cfg80211_update_assoc_bss_entry(wdev, chandef->chan);
Sergey Matyukevich5dc8cdc2019-03-26 09:27:37 +000016800
Michael Vassernisd34990b2019-07-29 06:01:16 +000016801 cfg80211_sched_dfs_chan_update(rdev);
16802
Luciano Coelhof8d75522014-11-07 14:31:35 +020016803 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
16804 NL80211_CMD_CH_SWITCH_NOTIFY, 0);
Johannes Berg947add32013-02-22 22:05:20 +010016805}
16806EXPORT_SYMBOL(cfg80211_ch_switch_notify);
16807
Luciano Coelhof8d75522014-11-07 14:31:35 +020016808void cfg80211_ch_switch_started_notify(struct net_device *dev,
16809 struct cfg80211_chan_def *chandef,
16810 u8 count)
16811{
16812 struct wireless_dev *wdev = dev->ieee80211_ptr;
16813 struct wiphy *wiphy = wdev->wiphy;
16814 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
16815
16816 trace_cfg80211_ch_switch_started_notify(dev, chandef);
16817
16818 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
16819 NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count);
16820}
16821EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
16822
Thomas Pedersen84f10702012-07-12 16:17:33 -070016823void
Simon Wunderlich04f39042013-02-08 18:16:19 +010016824nl80211_radar_notify(struct cfg80211_registered_device *rdev,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +010016825 const struct cfg80211_chan_def *chandef,
Simon Wunderlich04f39042013-02-08 18:16:19 +010016826 enum nl80211_radar_event event,
16827 struct net_device *netdev, gfp_t gfp)
16828{
16829 struct sk_buff *msg;
16830 void *hdr;
16831
16832 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16833 if (!msg)
16834 return;
16835
16836 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
16837 if (!hdr) {
16838 nlmsg_free(msg);
16839 return;
16840 }
16841
16842 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
16843 goto nla_put_failure;
16844
16845 /* NOP and radar events don't need a netdev parameter */
16846 if (netdev) {
16847 struct wireless_dev *wdev = netdev->ieee80211_ptr;
16848
16849 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020016850 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
16851 NL80211_ATTR_PAD))
Simon Wunderlich04f39042013-02-08 18:16:19 +010016852 goto nla_put_failure;
16853 }
16854
16855 if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
16856 goto nla_put_failure;
16857
16858 if (nl80211_send_chandef(msg, chandef))
16859 goto nla_put_failure;
16860
Johannes Berg9c90a9f2013-06-04 12:46:03 +020016861 genlmsg_end(msg, hdr);
Simon Wunderlich04f39042013-02-08 18:16:19 +010016862
Johannes Berg68eb5502013-11-19 15:19:38 +010016863 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016864 NL80211_MCGRP_MLME, gfp);
Simon Wunderlich04f39042013-02-08 18:16:19 +010016865 return;
16866
16867 nla_put_failure:
Simon Wunderlich04f39042013-02-08 18:16:19 +010016868 nlmsg_free(msg);
16869}
16870
tamizhr@codeaurora.org466b9932018-01-31 16:24:49 +053016871void cfg80211_sta_opmode_change_notify(struct net_device *dev, const u8 *mac,
16872 struct sta_opmode_info *sta_opmode,
16873 gfp_t gfp)
16874{
16875 struct sk_buff *msg;
16876 struct wireless_dev *wdev = dev->ieee80211_ptr;
16877 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
16878 void *hdr;
16879
16880 if (WARN_ON(!mac))
16881 return;
16882
16883 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16884 if (!msg)
16885 return;
16886
16887 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STA_OPMODE_CHANGED);
16888 if (!hdr) {
16889 nlmsg_free(msg);
16890 return;
16891 }
16892
16893 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
16894 goto nla_put_failure;
16895
16896 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
16897 goto nla_put_failure;
16898
16899 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
16900 goto nla_put_failure;
16901
16902 if ((sta_opmode->changed & STA_OPMODE_SMPS_MODE_CHANGED) &&
16903 nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, sta_opmode->smps_mode))
16904 goto nla_put_failure;
16905
16906 if ((sta_opmode->changed & STA_OPMODE_MAX_BW_CHANGED) &&
Johannes Berg0016d322020-03-25 09:05:32 +010016907 nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, sta_opmode->bw))
tamizhr@codeaurora.org466b9932018-01-31 16:24:49 +053016908 goto nla_put_failure;
16909
16910 if ((sta_opmode->changed & STA_OPMODE_N_SS_CHANGED) &&
16911 nla_put_u8(msg, NL80211_ATTR_NSS, sta_opmode->rx_nss))
16912 goto nla_put_failure;
16913
16914 genlmsg_end(msg, hdr);
16915
16916 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16917 NL80211_MCGRP_MLME, gfp);
16918
16919 return;
16920
16921nla_put_failure:
16922 nlmsg_free(msg);
16923}
16924EXPORT_SYMBOL(cfg80211_sta_opmode_change_notify);
16925
Johannes Berg7f6cf312011-11-04 11:18:15 +010016926void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
Venkateswara Naralasettyc4b50cd2018-02-13 11:03:06 +053016927 u64 cookie, bool acked, s32 ack_signal,
16928 bool is_valid_ack_signal, gfp_t gfp)
Johannes Berg7f6cf312011-11-04 11:18:15 +010016929{
16930 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016931 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg7f6cf312011-11-04 11:18:15 +010016932 struct sk_buff *msg;
16933 void *hdr;
Johannes Berg7f6cf312011-11-04 11:18:15 +010016934
Beni Lev4ee3e062012-08-27 12:49:39 +030016935 trace_cfg80211_probe_status(dev, addr, cookie, acked);
16936
Thomas Graf58050fc2012-06-28 03:57:45 +000016937 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Beni Lev4ee3e062012-08-27 12:49:39 +030016938
Johannes Berg7f6cf312011-11-04 11:18:15 +010016939 if (!msg)
16940 return;
16941
16942 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
16943 if (!hdr) {
16944 nlmsg_free(msg);
16945 return;
16946 }
16947
David S. Miller9360ffd2012-03-29 04:41:26 -040016948 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16949 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
16950 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020016951 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
16952 NL80211_ATTR_PAD) ||
Venkateswara Naralasettyc4b50cd2018-02-13 11:03:06 +053016953 (acked && nla_put_flag(msg, NL80211_ATTR_ACK)) ||
16954 (is_valid_ack_signal && nla_put_s32(msg, NL80211_ATTR_ACK_SIGNAL,
16955 ack_signal)))
David S. Miller9360ffd2012-03-29 04:41:26 -040016956 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010016957
Johannes Berg9c90a9f2013-06-04 12:46:03 +020016958 genlmsg_end(msg, hdr);
Johannes Berg7f6cf312011-11-04 11:18:15 +010016959
Johannes Berg68eb5502013-11-19 15:19:38 +010016960 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016961 NL80211_MCGRP_MLME, gfp);
Johannes Berg7f6cf312011-11-04 11:18:15 +010016962 return;
16963
16964 nla_put_failure:
Johannes Berg7f6cf312011-11-04 11:18:15 +010016965 nlmsg_free(msg);
16966}
16967EXPORT_SYMBOL(cfg80211_probe_status);
16968
Thomas Pedersene76fede2020-04-30 10:25:50 -070016969void cfg80211_report_obss_beacon_khz(struct wiphy *wiphy, const u8 *frame,
16970 size_t len, int freq, int sig_dbm)
Johannes Berg5e760232011-11-04 11:18:17 +010016971{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016972 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg5e760232011-11-04 11:18:17 +010016973 struct sk_buff *msg;
16974 void *hdr;
Ben Greear37c73b52012-10-26 14:49:25 -070016975 struct cfg80211_beacon_registration *reg;
Johannes Berg5e760232011-11-04 11:18:17 +010016976
Beni Lev4ee3e062012-08-27 12:49:39 +030016977 trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
16978
Ben Greear37c73b52012-10-26 14:49:25 -070016979 spin_lock_bh(&rdev->beacon_registrations_lock);
16980 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
16981 msg = nlmsg_new(len + 100, GFP_ATOMIC);
16982 if (!msg) {
16983 spin_unlock_bh(&rdev->beacon_registrations_lock);
16984 return;
16985 }
Johannes Berg5e760232011-11-04 11:18:17 +010016986
Ben Greear37c73b52012-10-26 14:49:25 -070016987 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
16988 if (!hdr)
16989 goto nla_put_failure;
Johannes Berg5e760232011-11-04 11:18:17 +010016990
Ben Greear37c73b52012-10-26 14:49:25 -070016991 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16992 (freq &&
Thomas Pedersen942ba882020-04-30 10:25:51 -070016993 (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
16994 KHZ_TO_MHZ(freq)) ||
16995 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET,
16996 freq % 1000))) ||
Ben Greear37c73b52012-10-26 14:49:25 -070016997 (sig_dbm &&
16998 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
16999 nla_put(msg, NL80211_ATTR_FRAME, len, frame))
17000 goto nla_put_failure;
17001
17002 genlmsg_end(msg, hdr);
17003
17004 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
Johannes Berg5e760232011-11-04 11:18:17 +010017005 }
Ben Greear37c73b52012-10-26 14:49:25 -070017006 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010017007 return;
17008
17009 nla_put_failure:
Ben Greear37c73b52012-10-26 14:49:25 -070017010 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010017011 nlmsg_free(msg);
17012}
Thomas Pedersene76fede2020-04-30 10:25:50 -070017013EXPORT_SYMBOL(cfg80211_report_obss_beacon_khz);
Johannes Berg5e760232011-11-04 11:18:17 +010017014
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010017015#ifdef CONFIG_PM
Luciano Coelho8cd4d452014-09-17 11:55:28 +030017016static int cfg80211_net_detect_results(struct sk_buff *msg,
17017 struct cfg80211_wowlan_wakeup *wakeup)
17018{
17019 struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect;
17020 struct nlattr *nl_results, *nl_match, *nl_freqs;
17021 int i, j;
17022
Michal Kubecekae0be8d2019-04-26 11:13:06 +020017023 nl_results = nla_nest_start_noflag(msg,
17024 NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030017025 if (!nl_results)
17026 return -EMSGSIZE;
17027
17028 for (i = 0; i < nd->n_matches; i++) {
17029 struct cfg80211_wowlan_nd_match *match = nd->matches[i];
17030
Michal Kubecekae0be8d2019-04-26 11:13:06 +020017031 nl_match = nla_nest_start_noflag(msg, i);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030017032 if (!nl_match)
17033 break;
17034
17035 /* The SSID attribute is optional in nl80211, but for
17036 * simplicity reasons it's always present in the
17037 * cfg80211 structure. If a driver can't pass the
17038 * SSID, that needs to be changed. A zero length SSID
17039 * is still a valid SSID (wildcard), so it cannot be
17040 * used for this purpose.
17041 */
17042 if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len,
17043 match->ssid.ssid)) {
17044 nla_nest_cancel(msg, nl_match);
17045 goto out;
17046 }
17047
17048 if (match->n_channels) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020017049 nl_freqs = nla_nest_start_noflag(msg,
17050 NL80211_ATTR_SCAN_FREQUENCIES);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030017051 if (!nl_freqs) {
17052 nla_nest_cancel(msg, nl_match);
17053 goto out;
17054 }
17055
17056 for (j = 0; j < match->n_channels; j++) {
Samuel Tan5528fae82015-02-09 21:29:15 +020017057 if (nla_put_u32(msg, j, match->channels[j])) {
Luciano Coelho8cd4d452014-09-17 11:55:28 +030017058 nla_nest_cancel(msg, nl_freqs);
17059 nla_nest_cancel(msg, nl_match);
17060 goto out;
17061 }
17062 }
17063
17064 nla_nest_end(msg, nl_freqs);
17065 }
17066
17067 nla_nest_end(msg, nl_match);
17068 }
17069
17070out:
17071 nla_nest_end(msg, nl_results);
17072 return 0;
17073}
17074
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010017075void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
17076 struct cfg80211_wowlan_wakeup *wakeup,
17077 gfp_t gfp)
17078{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017079 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010017080 struct sk_buff *msg;
17081 void *hdr;
Johannes Berg9c90a9f2013-06-04 12:46:03 +020017082 int size = 200;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010017083
17084 trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
17085
17086 if (wakeup)
17087 size += wakeup->packet_present_len;
17088
17089 msg = nlmsg_new(size, gfp);
17090 if (!msg)
17091 return;
17092
17093 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN);
17094 if (!hdr)
17095 goto free_msg;
17096
17097 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020017098 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
17099 NL80211_ATTR_PAD))
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010017100 goto free_msg;
17101
17102 if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
17103 wdev->netdev->ifindex))
17104 goto free_msg;
17105
17106 if (wakeup) {
17107 struct nlattr *reasons;
17108
Michal Kubecekae0be8d2019-04-26 11:13:06 +020017109 reasons = nla_nest_start_noflag(msg,
17110 NL80211_ATTR_WOWLAN_TRIGGERS);
Johannes Berg7fa322c2013-10-25 11:16:58 +020017111 if (!reasons)
17112 goto free_msg;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010017113
17114 if (wakeup->disconnect &&
17115 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
17116 goto free_msg;
17117 if (wakeup->magic_pkt &&
17118 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT))
17119 goto free_msg;
17120 if (wakeup->gtk_rekey_failure &&
17121 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE))
17122 goto free_msg;
17123 if (wakeup->eap_identity_req &&
17124 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST))
17125 goto free_msg;
17126 if (wakeup->four_way_handshake &&
17127 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE))
17128 goto free_msg;
17129 if (wakeup->rfkill_release &&
17130 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))
17131 goto free_msg;
17132
17133 if (wakeup->pattern_idx >= 0 &&
17134 nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
17135 wakeup->pattern_idx))
17136 goto free_msg;
17137
Johannes Bergae917c92013-10-25 11:05:22 +020017138 if (wakeup->tcp_match &&
17139 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
17140 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010017141
Johannes Bergae917c92013-10-25 11:05:22 +020017142 if (wakeup->tcp_connlost &&
17143 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
17144 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010017145
Johannes Bergae917c92013-10-25 11:05:22 +020017146 if (wakeup->tcp_nomoretokens &&
17147 nla_put_flag(msg,
17148 NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
17149 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010017150
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010017151 if (wakeup->packet) {
17152 u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
17153 u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN;
17154
17155 if (!wakeup->packet_80211) {
17156 pkt_attr =
17157 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023;
17158 len_attr =
17159 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN;
17160 }
17161
17162 if (wakeup->packet_len &&
17163 nla_put_u32(msg, len_attr, wakeup->packet_len))
17164 goto free_msg;
17165
17166 if (nla_put(msg, pkt_attr, wakeup->packet_present_len,
17167 wakeup->packet))
17168 goto free_msg;
17169 }
17170
Luciano Coelho8cd4d452014-09-17 11:55:28 +030017171 if (wakeup->net_detect &&
17172 cfg80211_net_detect_results(msg, wakeup))
17173 goto free_msg;
17174
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010017175 nla_nest_end(msg, reasons);
17176 }
17177
Johannes Berg9c90a9f2013-06-04 12:46:03 +020017178 genlmsg_end(msg, hdr);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010017179
Johannes Berg68eb5502013-11-19 15:19:38 +010017180 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017181 NL80211_MCGRP_MLME, gfp);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010017182 return;
17183
17184 free_msg:
17185 nlmsg_free(msg);
17186}
17187EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup);
17188#endif
17189
Jouni Malinen3475b092012-11-16 22:49:57 +020017190void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
17191 enum nl80211_tdls_operation oper,
17192 u16 reason_code, gfp_t gfp)
17193{
17194 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017195 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Jouni Malinen3475b092012-11-16 22:49:57 +020017196 struct sk_buff *msg;
17197 void *hdr;
Jouni Malinen3475b092012-11-16 22:49:57 +020017198
17199 trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
17200 reason_code);
17201
17202 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
17203 if (!msg)
17204 return;
17205
17206 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
17207 if (!hdr) {
17208 nlmsg_free(msg);
17209 return;
17210 }
17211
17212 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17213 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
17214 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
17215 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
17216 (reason_code > 0 &&
17217 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
17218 goto nla_put_failure;
17219
Johannes Berg9c90a9f2013-06-04 12:46:03 +020017220 genlmsg_end(msg, hdr);
Jouni Malinen3475b092012-11-16 22:49:57 +020017221
Johannes Berg68eb5502013-11-19 15:19:38 +010017222 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017223 NL80211_MCGRP_MLME, gfp);
Jouni Malinen3475b092012-11-16 22:49:57 +020017224 return;
17225
17226 nla_put_failure:
Jouni Malinen3475b092012-11-16 22:49:57 +020017227 nlmsg_free(msg);
17228}
17229EXPORT_SYMBOL(cfg80211_tdls_oper_request);
17230
Jouni Malinen026331c2010-02-15 12:53:10 +020017231static int nl80211_netlink_notify(struct notifier_block * nb,
17232 unsigned long state,
17233 void *_notify)
17234{
17235 struct netlink_notify *notify = _notify;
17236 struct cfg80211_registered_device *rdev;
17237 struct wireless_dev *wdev;
Ben Greear37c73b52012-10-26 14:49:25 -070017238 struct cfg80211_beacon_registration *reg, *tmp;
Jouni Malinen026331c2010-02-15 12:53:10 +020017239
Dmitry Ivanov8f815cd2016-04-06 17:23:18 +030017240 if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
Jouni Malinen026331c2010-02-15 12:53:10 +020017241 return NOTIFY_DONE;
17242
17243 rcu_read_lock();
17244
Johannes Berg5e760232011-11-04 11:18:17 +010017245 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
Arend Van Sprielca986ad2017-04-21 13:05:00 +010017246 struct cfg80211_sched_scan_request *sched_scan_req;
Jukka Rissanen93a1e862014-12-15 13:25:39 +020017247
Arend Van Sprielca986ad2017-04-21 13:05:00 +010017248 list_for_each_entry_rcu(sched_scan_req,
17249 &rdev->sched_scan_req_list,
17250 list) {
17251 if (sched_scan_req->owner_nlportid == notify->portid) {
17252 sched_scan_req->nl_owner_dead = true;
Johannes Berg753aacf2017-01-05 10:57:14 +010017253 schedule_work(&rdev->sched_scan_stop_wk);
Arend Van Sprielca986ad2017-04-21 13:05:00 +010017254 }
Johannes Berg753aacf2017-01-05 10:57:14 +010017255 }
Johannes Berg78f22b62014-03-24 17:57:27 +010017256
Johannes Berg53873f12016-05-03 16:52:04 +030017257 list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
Eric W. Biederman15e47302012-09-07 20:12:54 +000017258 cfg80211_mlme_unregister_socket(wdev, notify->portid);
Ben Greear37c73b52012-10-26 14:49:25 -070017259
Johannes Bergab810072017-04-26 07:43:41 +020017260 if (wdev->owner_nlportid == notify->portid) {
17261 wdev->nl_owner_dead = true;
17262 schedule_work(&rdev->destroy_work);
17263 } else if (wdev->conn_owner_nlportid == notify->portid) {
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050017264 schedule_work(&wdev->disconnect_wk);
Johannes Bergab810072017-04-26 07:43:41 +020017265 }
Johannes Berg9bb7e0f2018-09-10 13:29:12 +020017266
17267 cfg80211_release_pmsr(wdev, notify->portid);
Johannes Berg78f22b62014-03-24 17:57:27 +010017268 }
17269
Ben Greear37c73b52012-10-26 14:49:25 -070017270 spin_lock_bh(&rdev->beacon_registrations_lock);
17271 list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
17272 list) {
17273 if (reg->nlportid == notify->portid) {
17274 list_del(&reg->list);
17275 kfree(reg);
17276 break;
17277 }
17278 }
17279 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010017280 }
Jouni Malinen026331c2010-02-15 12:53:10 +020017281
17282 rcu_read_unlock();
17283
Ilan peer05050752015-03-04 00:32:06 -050017284 /*
17285 * It is possible that the user space process that is controlling the
17286 * indoor setting disappeared, so notify the regulatory core.
17287 */
17288 regulatory_netlink_notify(notify->portid);
Zhao, Gang6784c7d2014-04-21 12:53:04 +080017289 return NOTIFY_OK;
Jouni Malinen026331c2010-02-15 12:53:10 +020017290}
17291
17292static struct notifier_block nl80211_netlink_notifier = {
17293 .notifier_call = nl80211_netlink_notify,
17294};
17295
Jouni Malinen355199e2013-02-27 17:14:27 +020017296void cfg80211_ft_event(struct net_device *netdev,
17297 struct cfg80211_ft_event_params *ft_event)
17298{
17299 struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017300 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinen355199e2013-02-27 17:14:27 +020017301 struct sk_buff *msg;
17302 void *hdr;
Jouni Malinen355199e2013-02-27 17:14:27 +020017303
17304 trace_cfg80211_ft_event(wiphy, netdev, ft_event);
17305
17306 if (!ft_event->target_ap)
17307 return;
17308
Dedy Lansky1039d082018-05-17 16:25:03 +030017309 msg = nlmsg_new(100 + ft_event->ies_len + ft_event->ric_ies_len,
17310 GFP_KERNEL);
Jouni Malinen355199e2013-02-27 17:14:27 +020017311 if (!msg)
17312 return;
17313
17314 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
Johannes Bergae917c92013-10-25 11:05:22 +020017315 if (!hdr)
17316 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020017317
Johannes Bergae917c92013-10-25 11:05:22 +020017318 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17319 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
17320 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
17321 goto out;
17322
17323 if (ft_event->ies &&
17324 nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
17325 goto out;
17326 if (ft_event->ric_ies &&
17327 nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
17328 ft_event->ric_ies))
17329 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020017330
Johannes Berg9c90a9f2013-06-04 12:46:03 +020017331 genlmsg_end(msg, hdr);
Jouni Malinen355199e2013-02-27 17:14:27 +020017332
Johannes Berg68eb5502013-11-19 15:19:38 +010017333 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017334 NL80211_MCGRP_MLME, GFP_KERNEL);
Johannes Bergae917c92013-10-25 11:05:22 +020017335 return;
17336 out:
17337 nlmsg_free(msg);
Jouni Malinen355199e2013-02-27 17:14:27 +020017338}
17339EXPORT_SYMBOL(cfg80211_ft_event);
17340
Arend van Spriel5de17982013-04-18 15:49:00 +020017341void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
17342{
17343 struct cfg80211_registered_device *rdev;
17344 struct sk_buff *msg;
17345 void *hdr;
17346 u32 nlportid;
17347
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017348 rdev = wiphy_to_rdev(wdev->wiphy);
Arend van Spriel5de17982013-04-18 15:49:00 +020017349 if (!rdev->crit_proto_nlportid)
17350 return;
17351
17352 nlportid = rdev->crit_proto_nlportid;
17353 rdev->crit_proto_nlportid = 0;
17354
17355 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
17356 if (!msg)
17357 return;
17358
17359 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
17360 if (!hdr)
17361 goto nla_put_failure;
17362
17363 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020017364 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
17365 NL80211_ATTR_PAD))
Arend van Spriel5de17982013-04-18 15:49:00 +020017366 goto nla_put_failure;
17367
17368 genlmsg_end(msg, hdr);
17369
17370 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
17371 return;
17372
17373 nla_put_failure:
Arend van Spriel5de17982013-04-18 15:49:00 +020017374 nlmsg_free(msg);
Arend van Spriel5de17982013-04-18 15:49:00 +020017375}
17376EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
17377
Johannes Berg348baf02014-01-24 14:06:29 +010017378void nl80211_send_ap_stopped(struct wireless_dev *wdev)
17379{
17380 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017381 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg348baf02014-01-24 14:06:29 +010017382 struct sk_buff *msg;
17383 void *hdr;
17384
17385 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
17386 if (!msg)
17387 return;
17388
17389 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
17390 if (!hdr)
17391 goto out;
17392
17393 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17394 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020017395 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
17396 NL80211_ATTR_PAD))
Johannes Berg348baf02014-01-24 14:06:29 +010017397 goto out;
17398
17399 genlmsg_end(msg, hdr);
17400
17401 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
17402 NL80211_MCGRP_MLME, GFP_KERNEL);
17403 return;
17404 out:
17405 nlmsg_free(msg);
17406}
17407
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020017408int cfg80211_external_auth_request(struct net_device *dev,
17409 struct cfg80211_external_auth_params *params,
17410 gfp_t gfp)
17411{
17412 struct wireless_dev *wdev = dev->ieee80211_ptr;
17413 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
17414 struct sk_buff *msg;
17415 void *hdr;
17416
17417 if (!wdev->conn_owner_nlportid)
17418 return -EINVAL;
17419
17420 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
17421 if (!msg)
17422 return -ENOMEM;
17423
17424 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_EXTERNAL_AUTH);
17425 if (!hdr)
17426 goto nla_put_failure;
17427
17428 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17429 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
17430 nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) ||
17431 nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION,
17432 params->action) ||
17433 nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) ||
17434 nla_put(msg, NL80211_ATTR_SSID, params->ssid.ssid_len,
17435 params->ssid.ssid))
17436 goto nla_put_failure;
17437
17438 genlmsg_end(msg, hdr);
17439 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
17440 wdev->conn_owner_nlportid);
17441 return 0;
17442
17443 nla_put_failure:
17444 nlmsg_free(msg);
17445 return -ENOBUFS;
17446}
17447EXPORT_SYMBOL(cfg80211_external_auth_request);
17448
Sunil Duttcb74e972019-02-20 16:18:07 +053017449void cfg80211_update_owe_info_event(struct net_device *netdev,
17450 struct cfg80211_update_owe_info *owe_info,
17451 gfp_t gfp)
17452{
17453 struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
17454 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
17455 struct sk_buff *msg;
17456 void *hdr;
17457
17458 trace_cfg80211_update_owe_info_event(wiphy, netdev, owe_info);
17459
17460 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
17461 if (!msg)
17462 return;
17463
17464 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UPDATE_OWE_INFO);
17465 if (!hdr)
17466 goto nla_put_failure;
17467
17468 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17469 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
17470 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, owe_info->peer))
17471 goto nla_put_failure;
17472
17473 if (!owe_info->ie_len ||
17474 nla_put(msg, NL80211_ATTR_IE, owe_info->ie_len, owe_info->ie))
17475 goto nla_put_failure;
17476
17477 genlmsg_end(msg, hdr);
17478
17479 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
17480 NL80211_MCGRP_MLME, gfp);
17481 return;
17482
17483nla_put_failure:
17484 genlmsg_cancel(msg, hdr);
17485 nlmsg_free(msg);
17486}
17487EXPORT_SYMBOL(cfg80211_update_owe_info_event);
17488
Johannes Berg55682962007-09-20 13:09:35 -040017489/* initialisation/exit functions */
17490
Johannes Berg56989f62016-10-24 14:40:05 +020017491int __init nl80211_init(void)
Johannes Berg55682962007-09-20 13:09:35 -040017492{
Michał Mirosław0d63cbb2009-05-21 10:34:06 +000017493 int err;
Johannes Berg55682962007-09-20 13:09:35 -040017494
Johannes Berg489111e2016-10-24 14:40:03 +020017495 err = genl_register_family(&nl80211_fam);
Johannes Berg55682962007-09-20 13:09:35 -040017496 if (err)
17497 return err;
17498
Jouni Malinen026331c2010-02-15 12:53:10 +020017499 err = netlink_register_notifier(&nl80211_netlink_notifier);
17500 if (err)
17501 goto err_out;
17502
Johannes Berg55682962007-09-20 13:09:35 -040017503 return 0;
17504 err_out:
17505 genl_unregister_family(&nl80211_fam);
17506 return err;
17507}
17508
17509void nl80211_exit(void)
17510{
Jouni Malinen026331c2010-02-15 12:53:10 +020017511 netlink_unregister_notifier(&nl80211_netlink_notifier);
Johannes Berg55682962007-09-20 13:09:35 -040017512 genl_unregister_family(&nl80211_fam);
17513}