blob: 81232b73df8f999b348bce66a4b41da9325461da [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
Johannes Bergabaf94e2021-04-08 14:28:34 +02008 * Copyright (C) 2018-2021 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 *
Johannes Berga05829a2021-01-22 16:19:43 +010067__cfg80211_wdev_from_attrs(struct cfg80211_registered_device *rdev,
68 struct net *netns, struct nlattr **attrs)
Johannes Berg55682962007-09-20 13:09:35 -040069{
Johannes Berg89a54e42012-06-15 14:33:17 +020070 struct wireless_dev *result = NULL;
71 bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
72 bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
Jarod Wilson239729a2021-03-12 11:36:51 -050073 u64 wdev_id = 0;
Johannes Berg89a54e42012-06-15 14:33:17 +020074 int wiphy_idx = -1;
75 int ifidx = -1;
Johannes Berg55682962007-09-20 13:09:35 -040076
Johannes Berg89a54e42012-06-15 14:33:17 +020077 if (!have_ifidx && !have_wdev_id)
78 return ERR_PTR(-EINVAL);
Johannes Berg55682962007-09-20 13:09:35 -040079
Johannes Berg89a54e42012-06-15 14:33:17 +020080 if (have_ifidx)
81 ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
82 if (have_wdev_id) {
83 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
84 wiphy_idx = wdev_id >> 32;
Johannes Berg55682962007-09-20 13:09:35 -040085 }
86
Johannes Berga05829a2021-01-22 16:19:43 +010087 if (rdev) {
88 struct wireless_dev *wdev;
89
90 lockdep_assert_held(&rdev->wiphy.mtx);
91
92 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
93 if (have_ifidx && wdev->netdev &&
94 wdev->netdev->ifindex == ifidx) {
95 result = wdev;
96 break;
97 }
98 if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
99 result = wdev;
100 break;
101 }
102 }
103
104 return result ?: ERR_PTR(-ENODEV);
105 }
106
107 ASSERT_RTNL();
108
Johannes Berg89a54e42012-06-15 14:33:17 +0200109 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
110 struct wireless_dev *wdev;
111
112 if (wiphy_net(&rdev->wiphy) != netns)
113 continue;
114
115 if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
116 continue;
117
Johannes Berg53873f12016-05-03 16:52:04 +0300118 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Berg89a54e42012-06-15 14:33:17 +0200119 if (have_ifidx && wdev->netdev &&
120 wdev->netdev->ifindex == ifidx) {
121 result = wdev;
122 break;
123 }
124 if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
125 result = wdev;
126 break;
127 }
128 }
Johannes Berg89a54e42012-06-15 14:33:17 +0200129
130 if (result)
131 break;
132 }
133
134 if (result)
135 return result;
136 return ERR_PTR(-ENODEV);
Johannes Berg55682962007-09-20 13:09:35 -0400137}
138
Johannes Berga9455402012-06-15 13:32:49 +0200139static struct cfg80211_registered_device *
Johannes Berg878d9ec2012-06-15 14:18:32 +0200140__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
Johannes Berga9455402012-06-15 13:32:49 +0200141{
Johannes Berg7fee47782012-06-15 14:09:58 +0200142 struct cfg80211_registered_device *rdev = NULL, *tmp;
143 struct net_device *netdev;
Johannes Berga9455402012-06-15 13:32:49 +0200144
Johannes Berg5fe231e2013-05-08 21:45:15 +0200145 ASSERT_RTNL();
Johannes Berga9455402012-06-15 13:32:49 +0200146
Johannes Berg878d9ec2012-06-15 14:18:32 +0200147 if (!attrs[NL80211_ATTR_WIPHY] &&
Johannes Berg89a54e42012-06-15 14:33:17 +0200148 !attrs[NL80211_ATTR_IFINDEX] &&
149 !attrs[NL80211_ATTR_WDEV])
Johannes Berg7fee47782012-06-15 14:09:58 +0200150 return ERR_PTR(-EINVAL);
151
Johannes Berg878d9ec2012-06-15 14:18:32 +0200152 if (attrs[NL80211_ATTR_WIPHY])
Johannes Berg7fee47782012-06-15 14:09:58 +0200153 rdev = cfg80211_rdev_by_wiphy_idx(
Johannes Berg878d9ec2012-06-15 14:18:32 +0200154 nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
Johannes Berga9455402012-06-15 13:32:49 +0200155
Johannes Berg89a54e42012-06-15 14:33:17 +0200156 if (attrs[NL80211_ATTR_WDEV]) {
157 u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
158 struct wireless_dev *wdev;
159 bool found = false;
160
161 tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
162 if (tmp) {
163 /* make sure wdev exists */
Johannes Berg53873f12016-05-03 16:52:04 +0300164 list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
Johannes Berg89a54e42012-06-15 14:33:17 +0200165 if (wdev->identifier != (u32)wdev_id)
166 continue;
167 found = true;
168 break;
169 }
Johannes Berg89a54e42012-06-15 14:33:17 +0200170
171 if (!found)
172 tmp = NULL;
173
174 if (rdev && tmp != rdev)
175 return ERR_PTR(-EINVAL);
176 rdev = tmp;
177 }
178 }
179
Johannes Berg878d9ec2012-06-15 14:18:32 +0200180 if (attrs[NL80211_ATTR_IFINDEX]) {
181 int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -0700182
Ying Xue7f2b8562014-01-15 10:23:45 +0800183 netdev = __dev_get_by_index(netns, ifindex);
Johannes Berg7fee47782012-06-15 14:09:58 +0200184 if (netdev) {
185 if (netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800186 tmp = wiphy_to_rdev(
187 netdev->ieee80211_ptr->wiphy);
Johannes Berg7fee47782012-06-15 14:09:58 +0200188 else
189 tmp = NULL;
190
Johannes Berg7fee47782012-06-15 14:09:58 +0200191 /* not wireless device -- return error */
192 if (!tmp)
193 return ERR_PTR(-EINVAL);
194
195 /* mismatch -- return error */
196 if (rdev && tmp != rdev)
197 return ERR_PTR(-EINVAL);
198
199 rdev = tmp;
Johannes Berga9455402012-06-15 13:32:49 +0200200 }
Johannes Berga9455402012-06-15 13:32:49 +0200201 }
202
Johannes Berg4f7eff12012-06-15 14:14:22 +0200203 if (!rdev)
204 return ERR_PTR(-ENODEV);
Johannes Berga9455402012-06-15 13:32:49 +0200205
Johannes Berg4f7eff12012-06-15 14:14:22 +0200206 if (netns != wiphy_net(&rdev->wiphy))
207 return ERR_PTR(-ENODEV);
208
209 return rdev;
Johannes Berga9455402012-06-15 13:32:49 +0200210}
211
212/*
213 * This function returns a pointer to the driver
214 * that the genl_info item that is passed refers to.
Johannes Berga9455402012-06-15 13:32:49 +0200215 *
216 * The result of this can be a PTR_ERR and hence must
217 * be checked with IS_ERR() for errors.
218 */
219static struct cfg80211_registered_device *
Johannes Berg4f7eff12012-06-15 14:14:22 +0200220cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
Johannes Berga9455402012-06-15 13:32:49 +0200221{
Johannes Berg5fe231e2013-05-08 21:45:15 +0200222 return __cfg80211_rdev_from_attrs(netns, info->attrs);
Johannes Berga9455402012-06-15 13:32:49 +0200223}
224
Johannes Bergf88eb7c2019-09-20 21:54:17 +0200225static int validate_beacon_head(const struct nlattr *attr,
226 struct netlink_ext_ack *extack)
227{
228 const u8 *data = nla_data(attr);
229 unsigned int len = nla_len(attr);
230 const struct element *elem;
231 const struct ieee80211_mgmt *mgmt = (void *)data;
Thomas Pedersen1d47f112020-09-08 12:03:05 -0700232 unsigned int fixedlen, hdrlen;
Johannes Berg9a6847b2021-04-08 15:45:20 +0200233 bool s1g_bcn;
Thomas Pedersen1d47f112020-09-08 12:03:05 -0700234
Johannes Berg9a6847b2021-04-08 15:45:20 +0200235 if (len < offsetofend(typeof(*mgmt), frame_control))
236 goto err;
237
238 s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
Thomas Pedersen1d47f112020-09-08 12:03:05 -0700239 if (s1g_bcn) {
240 fixedlen = offsetof(struct ieee80211_ext,
241 u.s1g_beacon.variable);
242 hdrlen = offsetof(struct ieee80211_ext, u.s1g_beacon);
243 } else {
244 fixedlen = offsetof(struct ieee80211_mgmt,
245 u.beacon.variable);
246 hdrlen = offsetof(struct ieee80211_mgmt, u.beacon);
247 }
Johannes Bergf88eb7c2019-09-20 21:54:17 +0200248
249 if (len < fixedlen)
250 goto err;
251
Thomas Pedersen1d47f112020-09-08 12:03:05 -0700252 if (ieee80211_hdrlen(mgmt->frame_control) != hdrlen)
Johannes Bergf88eb7c2019-09-20 21:54:17 +0200253 goto err;
254
255 data += fixedlen;
256 len -= fixedlen;
257
258 for_each_element(elem, data, len) {
259 /* nothing */
260 }
261
262 if (for_each_element_completed(elem, data, len))
263 return 0;
264
265err:
266 NL_SET_ERR_MSG_ATTR(extack, attr, "malformed beacon head");
267 return -EINVAL;
268}
269
Johannes Berg3d7af872018-10-02 10:00:08 +0200270static int validate_ie_attr(const struct nlattr *attr,
271 struct netlink_ext_ack *extack)
272{
Johannes Berg9f308612019-02-07 23:39:19 +0100273 const u8 *data = nla_data(attr);
274 unsigned int len = nla_len(attr);
Jouni Malinen7388afe2019-02-11 16:29:04 +0200275 const struct element *elem;
Johannes Berg3d7af872018-10-02 10:00:08 +0200276
Johannes Berg9f308612019-02-07 23:39:19 +0100277 for_each_element(elem, data, len) {
278 /* nothing */
Johannes Berg3d7af872018-10-02 10:00:08 +0200279 }
280
Johannes Berg9f308612019-02-07 23:39:19 +0100281 if (for_each_element_completed(elem, data, len))
282 return 0;
283
Johannes Berg3d7af872018-10-02 10:00:08 +0200284 NL_SET_ERR_MSG_ATTR(extack, attr, "malformed information elements");
285 return -EINVAL;
286}
287
Johannes Berg55682962007-09-20 13:09:35 -0400288/* policy for the attributes */
Johannes Bergd15da2a2020-04-30 22:13:07 +0200289static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR];
290
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -0700291static const struct nla_policy
292nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
293 [NL80211_FTM_RESP_ATTR_ENABLED] = { .type = NLA_FLAG, },
294 [NL80211_FTM_RESP_ATTR_LCI] = { .type = NLA_BINARY,
295 .len = U8_MAX },
296 [NL80211_FTM_RESP_ATTR_CIVICLOC] = { .type = NLA_BINARY,
297 .len = U8_MAX },
298};
299
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200300static const struct nla_policy
301nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = {
302 [NL80211_PMSR_FTM_REQ_ATTR_ASAP] = { .type = NLA_FLAG },
303 [NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] = { .type = NLA_U32 },
304 [NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP] =
305 NLA_POLICY_MAX(NLA_U8, 15),
306 [NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 },
307 [NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] =
308 NLA_POLICY_MAX(NLA_U8, 15),
309 [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] =
Aviya Erenfeldea187092019-02-06 13:17:08 +0200310 NLA_POLICY_MAX(NLA_U8, 31),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200311 [NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES] = { .type = NLA_U8 },
312 [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI] = { .type = NLA_FLAG },
313 [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC] = { .type = NLA_FLAG },
Avraham Sternefb55202020-01-31 13:12:38 +0200314 [NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED] = { .type = NLA_FLAG },
315 [NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED] = { .type = NLA_FLAG },
Avraham Stern73807522021-04-09 12:40:25 +0300316 [NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK] = { .type = NLA_FLAG },
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200317};
318
319static const struct nla_policy
320nl80211_pmsr_req_data_policy[NL80211_PMSR_TYPE_MAX + 1] = {
321 [NL80211_PMSR_TYPE_FTM] =
Johannes Berg23323282019-01-25 10:08:28 +0100322 NLA_POLICY_NESTED(nl80211_pmsr_ftm_req_attr_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200323};
324
325static const struct nla_policy
326nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = {
327 [NL80211_PMSR_REQ_ATTR_DATA] =
Johannes Berg23323282019-01-25 10:08:28 +0100328 NLA_POLICY_NESTED(nl80211_pmsr_req_data_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200329 [NL80211_PMSR_REQ_ATTR_GET_AP_TSF] = { .type = NLA_FLAG },
330};
331
332static const struct nla_policy
Sosthène Guédonaeddc052021-06-03 19:39:39 +0200333nl80211_pmsr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200334 [NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR,
Johannes Bergd15da2a2020-04-30 22:13:07 +0200335 [NL80211_PMSR_PEER_ATTR_CHAN] = NLA_POLICY_NESTED(nl80211_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200336 [NL80211_PMSR_PEER_ATTR_REQ] =
Johannes Berg23323282019-01-25 10:08:28 +0100337 NLA_POLICY_NESTED(nl80211_pmsr_req_attr_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200338 [NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_REJECT },
339};
340
341static const struct nla_policy
342nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
343 [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_REJECT },
344 [NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_REJECT },
345 [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT },
346 [NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_REJECT },
347 [NL80211_PMSR_ATTR_PEERS] =
Sosthène Guédonaeddc052021-06-03 19:39:39 +0200348 NLA_POLICY_NESTED_ARRAY(nl80211_pmsr_peer_attr_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200349};
350
John Crispin796e90f2019-07-30 18:37:00 +0200351static const struct nla_policy
352he_obss_pd_policy[NL80211_HE_OBSS_PD_ATTR_MAX + 1] = {
353 [NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET] =
354 NLA_POLICY_RANGE(NLA_U8, 1, 20),
355 [NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET] =
356 NLA_POLICY_RANGE(NLA_U8, 1, 20),
Rajkumar Manoharanf5bec332020-09-28 00:28:11 -0700357 [NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET] =
358 NLA_POLICY_RANGE(NLA_U8, 1, 20),
359 [NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP] =
360 NLA_POLICY_EXACT_LEN(8),
361 [NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP] =
362 NLA_POLICY_EXACT_LEN(8),
363 [NL80211_HE_OBSS_PD_ATTR_SR_CTRL] = { .type = NLA_U8 },
John Crispin796e90f2019-07-30 18:37:00 +0200364};
365
John Crispin5c5e52d2019-12-17 15:19:18 +0100366static const struct nla_policy
367he_bss_color_policy[NL80211_HE_BSS_COLOR_ATTR_MAX + 1] = {
368 [NL80211_HE_BSS_COLOR_ATTR_COLOR] = NLA_POLICY_RANGE(NLA_U8, 1, 63),
369 [NL80211_HE_BSS_COLOR_ATTR_DISABLED] = { .type = NLA_FLAG },
370 [NL80211_HE_BSS_COLOR_ATTR_PARTIAL] = { .type = NLA_FLAG },
371};
372
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +0530373static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
374 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
375 .len = NL80211_MAX_SUPP_RATES },
376 [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
377 .len = NL80211_MAX_SUPP_HT_RATES },
378 [NL80211_TXRATE_VHT] = NLA_POLICY_EXACT_LEN_WARN(sizeof(struct nl80211_txrate_vht)),
379 [NL80211_TXRATE_GI] = { .type = NLA_U8 },
Miles Hueb89a6a2020-08-04 10:16:29 +0200380 [NL80211_TXRATE_HE] = NLA_POLICY_EXACT_LEN(sizeof(struct nl80211_txrate_he)),
381 [NL80211_TXRATE_HE_GI] = NLA_POLICY_RANGE(NLA_U8,
382 NL80211_RATE_INFO_HE_GI_0_8,
383 NL80211_RATE_INFO_HE_GI_3_2),
384 [NL80211_TXRATE_HE_LTF] = NLA_POLICY_RANGE(NLA_U8,
385 NL80211_RATE_INFO_HE_1XLTF,
386 NL80211_RATE_INFO_HE_4XLTF),
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +0530387};
388
Tamizh chelvam77f576d2020-01-20 13:21:22 +0530389static const struct nla_policy
390nl80211_tid_config_attr_policy[NL80211_TID_CONFIG_ATTR_MAX + 1] = {
Johannes Berg3710a8a2020-02-24 11:34:25 +0100391 [NL80211_TID_CONFIG_ATTR_VIF_SUPP] = { .type = NLA_U64 },
392 [NL80211_TID_CONFIG_ATTR_PEER_SUPP] = { .type = NLA_U64 },
Tamizh chelvam77f576d2020-01-20 13:21:22 +0530393 [NL80211_TID_CONFIG_ATTR_OVERRIDE] = { .type = NLA_FLAG },
Johannes Berg3710a8a2020-02-24 11:34:25 +0100394 [NL80211_TID_CONFIG_ATTR_TIDS] = NLA_POLICY_RANGE(NLA_U16, 1, 0xff),
Tamizh chelvam77f576d2020-01-20 13:21:22 +0530395 [NL80211_TID_CONFIG_ATTR_NOACK] =
396 NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
Tamizh chelvam6a21d162020-01-20 13:21:23 +0530397 [NL80211_TID_CONFIG_ATTR_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
398 [NL80211_TID_CONFIG_ATTR_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
Tamizh chelvamade274b2020-01-20 13:21:24 +0530399 [NL80211_TID_CONFIG_ATTR_AMPDU_CTRL] =
400 NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
Tamizh chelvam04f7d142020-01-20 13:21:25 +0530401 [NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL] =
402 NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
Sergey Matyukevich33462e62020-04-24 14:29:03 +0300403 [NL80211_TID_CONFIG_ATTR_AMSDU_CTRL] =
404 NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +0530405 [NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE] =
406 NLA_POLICY_MAX(NLA_U8, NL80211_TX_RATE_FIXED),
407 [NL80211_TID_CONFIG_ATTR_TX_RATE] =
408 NLA_POLICY_NESTED(nl80211_txattr_policy),
Tamizh chelvam77f576d2020-01-20 13:21:22 +0530409};
410
Aloka Dixit291c49d2020-09-11 00:05:29 +0000411static const struct nla_policy
412nl80211_fils_discovery_policy[NL80211_FILS_DISCOVERY_ATTR_MAX + 1] = {
413 [NL80211_FILS_DISCOVERY_ATTR_INT_MIN] = NLA_POLICY_MAX(NLA_U32, 10000),
414 [NL80211_FILS_DISCOVERY_ATTR_INT_MAX] = NLA_POLICY_MAX(NLA_U32, 10000),
Aloka Dixit272cd0e2021-02-22 13:20:59 -0800415 [NL80211_FILS_DISCOVERY_ATTR_TMPL] =
416 NLA_POLICY_RANGE(NLA_BINARY,
417 NL80211_FILS_DISCOVERY_TMPL_MIN_LEN,
418 IEEE80211_MAX_DATA_LEN),
Aloka Dixit291c49d2020-09-11 00:05:29 +0000419};
420
Aloka Dixit7443dcd2020-09-11 00:33:00 +0000421static const struct nla_policy
422nl80211_unsol_bcast_probe_resp_policy[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX + 1] = {
423 [NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT] = NLA_POLICY_MAX(NLA_U32, 20),
424 [NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL] = { .type = NLA_BINARY,
425 .len = IEEE80211_MAX_DATA_LEN }
426};
427
Carl Huang6bdb68c2020-12-03 05:37:26 -0500428static const struct nla_policy
429sar_specs_policy[NL80211_SAR_ATTR_SPECS_MAX + 1] = {
430 [NL80211_SAR_ATTR_SPECS_POWER] = { .type = NLA_S32 },
431 [NL80211_SAR_ATTR_SPECS_RANGE_INDEX] = {.type = NLA_U32 },
432};
433
434static const struct nla_policy
435sar_policy[NL80211_SAR_ATTR_MAX + 1] = {
436 [NL80211_SAR_ATTR_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_SAR_TYPE),
437 [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy),
438};
439
John Crispindc1e3cb2021-09-15 19:54:34 -0700440static const struct nla_policy
441nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = {
442 [NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES] = NLA_POLICY_MIN(NLA_U8, 2),
443 [NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY] =
444 NLA_POLICY_MIN(NLA_U8, 1),
445 [NL80211_MBSSID_CONFIG_ATTR_INDEX] = { .type = NLA_U8 },
446 [NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 },
447 [NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG },
448};
449
Johannes Bergd15da2a2020-04-30 22:13:07 +0200450static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
Johannes Berg6d4dd4e2019-07-31 10:58:20 +0200451 [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
Johannes Berg55682962007-09-20 13:09:35 -0400452 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
453 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
David S. Miller079e24e2009-05-26 21:15:00 -0700454 .len = 20-1 },
Jouni Malinen31888482008-10-30 16:59:24 +0200455 [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100456
Jouni Malinen72bdcf32008-11-26 16:15:24 +0200457 [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
Sujith094d05d2008-12-12 11:57:43 +0530458 [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300459 [NL80211_ATTR_WIPHY_EDMG_CHANNELS] = NLA_POLICY_RANGE(NLA_U8,
460 NL80211_EDMG_CHANNELS_MIN,
461 NL80211_EDMG_CHANNELS_MAX),
462 [NL80211_ATTR_WIPHY_EDMG_BW_CONFIG] = NLA_POLICY_RANGE(NLA_U8,
463 NL80211_EDMG_BW_CONFIG_MIN,
464 NL80211_EDMG_BW_CONFIG_MAX),
465
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100466 [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
467 [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
Thomas Pedersen942ba882020-04-30 10:25:51 -0700468 [NL80211_ATTR_CENTER_FREQ1_OFFSET] = NLA_POLICY_RANGE(NLA_U32, 0, 999),
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100469 [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
470
Johannes Bergab0d76f2018-10-02 10:00:07 +0200471 [NL80211_ATTR_WIPHY_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
472 [NL80211_ATTR_WIPHY_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +0200473 [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
474 [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
Lukáš Turek81077e82009-12-21 22:50:47 +0100475 [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +0200476 [NL80211_ATTR_WIPHY_DYN_ACK] = { .type = NLA_FLAG },
Johannes Berg55682962007-09-20 13:09:35 -0400477
Johannes Bergab0d76f2018-10-02 10:00:07 +0200478 [NL80211_ATTR_IFTYPE] = NLA_POLICY_MAX(NLA_U32, NL80211_IFTYPE_MAX),
Johannes Berg55682962007-09-20 13:09:35 -0400479 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
480 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
Johannes Berg41ade002007-12-19 02:03:29 +0100481
Johannes Bergc7721c02020-04-30 22:13:10 +0200482 [NL80211_ATTR_MAC] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
483 [NL80211_ATTR_PREV_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Johannes Berg41ade002007-12-19 02:03:29 +0100484
Johannes Bergb9454e82009-07-08 13:29:08 +0200485 [NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
Johannes Berg41ade002007-12-19 02:03:29 +0100486 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
487 .len = WLAN_MAX_KEY_LEN },
Jouni Malinen56be3932020-02-22 15:25:43 +0200488 [NL80211_ATTR_KEY_IDX] = NLA_POLICY_MAX(NLA_U8, 7),
Johannes Berg41ade002007-12-19 02:03:29 +0100489 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
490 [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
Jouni Malinen81962262011-11-02 23:36:31 +0200491 [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200492 [NL80211_ATTR_KEY_TYPE] =
493 NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES),
Johannes Berged1b6cc2007-12-19 02:03:32 +0100494
495 [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
496 [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
Johannes Bergf88eb7c2019-09-20 21:54:17 +0200497 [NL80211_ATTR_BEACON_HEAD] =
498 NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_beacon_head,
499 IEEE80211_MAX_DATA_LEN),
Johannes Berg3d7af872018-10-02 10:00:08 +0200500 [NL80211_ATTR_BEACON_TAIL] =
501 NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
502 IEEE80211_MAX_DATA_LEN),
Johannes Bergab0d76f2018-10-02 10:00:07 +0200503 [NL80211_ATTR_STA_AID] =
504 NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
Johannes Berg5727ef12007-12-19 02:03:34 +0100505 [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
506 [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
507 [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
508 .len = NL80211_MAX_SUPP_RATES },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200509 [NL80211_ATTR_STA_PLINK_ACTION] =
510 NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_ACTIONS - 1),
Ashok Raj Nagarajane96d1cd2019-03-29 16:18:21 +0530511 [NL80211_ATTR_STA_TX_POWER_SETTING] =
512 NLA_POLICY_RANGE(NLA_U8,
513 NL80211_TX_POWER_AUTOMATIC,
514 NL80211_TX_POWER_FIXED),
515 [NL80211_ATTR_STA_TX_POWER] = { .type = NLA_S16 },
Johannes Berg5727ef12007-12-19 02:03:34 +0100516 [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
Johannes Berg0a9542e2008-10-15 11:54:04 +0200517 [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100518 [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +0800519 .len = IEEE80211_MAX_MESH_ID_LEN },
Markus Theil1fab1b82019-10-29 10:30:03 +0100520 [NL80211_ATTR_MPATH_NEXT_HOP] = NLA_POLICY_ETH_ADDR_COMPAT,
Jouni Malinen9f1ba902008-08-07 20:07:01 +0300521
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700522 [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
523 [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
524
Jouni Malinen9f1ba902008-08-07 20:07:01 +0300525 [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
526 [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
527 [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
Jouni Malinen90c97a02008-10-30 16:59:22 +0200528 [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY,
529 .len = NL80211_MAX_SUPP_RATES },
Helmut Schaa50b12f52010-11-19 12:40:25 +0100530 [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 },
Jouni Malinen36aedc92008-08-25 11:58:58 +0300531
Javier Cardona24bdd9f2010-12-16 17:37:48 -0800532 [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
Javier Cardona15d5dda2011-04-07 15:08:28 -0700533 [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -0700534
Johannes Bergc7721c02020-04-30 22:13:10 +0200535 [NL80211_ATTR_HT_CAPABILITY] = NLA_POLICY_EXACT_LEN_WARN(NL80211_HT_CAPABILITY_LEN),
Jouni Malinen9aed3cc2009-01-13 16:03:29 +0200536
537 [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
Johannes Berg3d7af872018-10-02 10:00:08 +0200538 [NL80211_ATTR_IE] = NLA_POLICY_VALIDATE_FN(NLA_BINARY,
539 validate_ie_attr,
540 IEEE80211_MAX_DATA_LEN),
Johannes Berg2a519312009-02-10 21:25:55 +0100541 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
542 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
Jouni Malinen636a5d32009-03-19 13:39:22 +0200543
544 [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
545 .len = IEEE80211_MAX_SSID_LEN },
546 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
547 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
Johannes Berg04a773a2009-04-19 21:24:32 +0200548 [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
Jouni Malinen1965c852009-04-22 21:38:25 +0300549 [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200550 [NL80211_ATTR_USE_MFP] = NLA_POLICY_RANGE(NLA_U32,
551 NL80211_MFP_NO,
552 NL80211_MFP_OPTIONAL),
Johannes Bergeccb8e82009-05-11 21:57:56 +0300553 [NL80211_ATTR_STA_FLAGS2] = {
554 .len = sizeof(struct nl80211_sta_flag_update),
555 },
Jouni Malinen3f77316c2009-05-11 21:57:57 +0300556 [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
Johannes Bergc0692b82010-08-27 14:26:53 +0300557 [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
558 [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
Denis Kenzior64bf3d42018-03-26 12:52:43 -0500559 [NL80211_ATTR_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG },
Samuel Ortizb23aa672009-07-01 21:26:54 +0200560 [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
Sergey Matyukevichea750802020-02-13 13:16:16 +0000561 [NL80211_ATTR_STATUS_CODE] = { .type = NLA_U16 },
Samuel Ortizb23aa672009-07-01 21:26:54 +0200562 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
563 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
Johannes Berg463d0182009-07-14 00:33:35 +0200564 [NL80211_ATTR_PID] = { .type = NLA_U32 },
Felix Fietkau8b787642009-11-10 18:53:10 +0100565 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
Johannes Bergc7721c02020-04-30 22:13:10 +0200566 [NL80211_ATTR_PMKID] = NLA_POLICY_EXACT_LEN_WARN(WLAN_PMKID_LEN),
Jouni Malinen9588bbd2009-12-23 13:15:41 +0100567 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
568 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +0200569 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
Jouni Malinen026331c2010-02-15 12:53:10 +0200570 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
571 .len = IEEE80211_MAX_DATA_LEN },
572 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200573 [NL80211_ATTR_PS_STATE] = NLA_POLICY_RANGE(NLA_U32,
574 NL80211_PS_DISABLED,
575 NL80211_PS_ENABLED),
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +0200576 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
Jouni Malinend5cdfac2010-04-04 09:37:19 +0300577 [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +0200578 [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +0300579 [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
580 [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
Johannes Berg2e161f782010-08-12 15:38:38 +0200581 [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
Bruno Randolfafe0cbf2010-11-10 12:50:50 +0900582 [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 },
583 [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
Felix Fietkau885a46d2010-11-11 15:07:22 +0100584 [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
Johannes Bergf7ca38d2010-11-25 10:02:29 +0100585 [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100586 [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200587 [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200588 [NL80211_ATTR_STA_PLINK_STATE] =
589 NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_STATES - 1),
Jakub Kicinski056e9372020-03-02 21:10:57 -0800590 [NL80211_ATTR_MEASUREMENT_DURATION] = { .type = NLA_U16 },
591 [NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY] = { .type = NLA_FLAG },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200592 [NL80211_ATTR_MESH_PEER_AID] =
593 NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
Luciano Coelhobbe6ad62011-05-11 17:09:37 +0300594 [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
Johannes Berge5497d72011-07-05 16:35:40 +0200595 [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
Johannes Berg34850ab2011-07-18 18:08:35 +0200596 [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200597 [NL80211_ATTR_HIDDEN_SSID] =
598 NLA_POLICY_RANGE(NLA_U32,
599 NL80211_HIDDEN_SSID_NOT_IN_USE,
600 NL80211_HIDDEN_SSID_ZERO_CONTENTS),
Johannes Berg3d7af872018-10-02 10:00:08 +0200601 [NL80211_ATTR_IE_PROBE_RESP] =
602 NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
603 IEEE80211_MAX_DATA_LEN),
604 [NL80211_ATTR_IE_ASSOC_RESP] =
605 NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
606 IEEE80211_MAX_DATA_LEN),
Vivek Natarajanf4b34b52011-08-29 14:23:03 +0530607 [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300608 [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +0530609 [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
Arik Nemtsov109086c2011-09-28 14:12:50 +0300610 [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
611 [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
612 [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
613 [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
614 [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
Arik Nemtsov31fa97c2014-06-11 17:18:21 +0300615 [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG },
Johannes Berge247bd902011-11-04 11:18:21 +0100616 [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
Arik Nemtsov00f740e2011-11-10 11:28:56 +0200617 [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
618 .len = IEEE80211_MAX_DATA_LEN },
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -0700619 [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
Ben Greear7e7c8922011-11-18 11:31:59 -0800620 [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
621 [NL80211_ATTR_HT_CAPABILITY_MASK] = {
622 .len = NL80211_HT_CAPABILITY_LEN
623 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +0100624 [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +0530625 [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
Bala Shanmugam4486ea92012-03-07 17:27:12 +0530626 [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
Johannes Berg89a54e42012-06-15 14:33:17 +0200627 [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -0700628 [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
Johannes Bergcb9abd42020-08-05 15:47:16 +0200629
630 /* need to include at least Auth Transaction and Status Code */
631 [NL80211_ATTR_AUTH_DATA] = NLA_POLICY_MIN_LEN(4),
632
Johannes Bergc7721c02020-04-30 22:13:10 +0200633 [NL80211_ATTR_VHT_CAPABILITY] = NLA_POLICY_EXACT_LEN_WARN(NL80211_VHT_CAPABILITY_LEN),
Sam Lefflered4737712012-10-11 21:03:31 -0700634 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200635 [NL80211_ATTR_P2P_CTWINDOW] = NLA_POLICY_MAX(NLA_U8, 127),
636 [NL80211_ATTR_P2P_OPPPS] = NLA_POLICY_MAX(NLA_U8, 1),
637 [NL80211_ATTR_LOCAL_MESH_POWER_MODE] =
638 NLA_POLICY_RANGE(NLA_U32,
639 NL80211_MESH_POWER_UNKNOWN + 1,
640 NL80211_MESH_POWER_MAX),
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +0530641 [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
642 [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
Jouni Malinen9d62a982013-02-14 21:10:13 +0200643 [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
644 [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
Johannes Berg3713b4e2013-02-14 16:19:38 +0100645 [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
Johannes Bergee2aca32013-02-21 17:36:01 +0100646 [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG },
647 [NL80211_ATTR_VHT_CAPABILITY_MASK] = {
648 .len = NL80211_VHT_CAPABILITY_LEN,
649 },
Jouni Malinen355199e2013-02-27 17:14:27 +0200650 [NL80211_ATTR_MDID] = { .type = NLA_U16 },
651 [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
652 .len = IEEE80211_MAX_DATA_LEN },
Jakub Kicinski0e1a1d82020-03-02 21:10:56 -0800653 [NL80211_ATTR_CRIT_PROT_ID] = { .type = NLA_U16 },
Johannes Bergcb9abd42020-08-05 15:47:16 +0200654 [NL80211_ATTR_MAX_CRIT_PROT_DURATION] =
655 NLA_POLICY_MAX(NLA_U16, NL80211_CRIT_PROTO_MAX_DURATION),
Johannes Bergab0d76f2018-10-02 10:00:07 +0200656 [NL80211_ATTR_PEER_AID] =
657 NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +0200658 [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
659 [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
660 [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
John Crispin00c207e2020-08-11 10:01:03 +0200661 [NL80211_ATTR_CNTDWN_OFFS_BEACON] = { .type = NLA_BINARY },
662 [NL80211_ATTR_CNTDWN_OFFS_PRESP] = { .type = NLA_BINARY },
Johannes Bergcb9abd42020-08-05 15:47:16 +0200663 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = NLA_POLICY_MIN_LEN(2),
Johannes Bergc8b82802020-08-19 08:56:43 +0200664 /*
665 * The value of the Length field of the Supported Operating
666 * Classes element is between 2 and 253.
667 */
668 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] =
669 NLA_POLICY_RANGE(NLA_BINARY, 2, 253),
Simon Wunderlich5336fa82013-10-07 18:41:05 +0200670 [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +0100671 [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
Johannes Bergad7e7182013-11-13 13:37:47 +0100672 [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
673 [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
674 [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
Johannes Bergc8b82802020-08-19 08:56:43 +0200675 [NL80211_ATTR_QOS_MAP] = NLA_POLICY_RANGE(NLA_BINARY,
676 IEEE80211_QOS_MAP_LEN_MIN,
677 IEEE80211_QOS_MAP_LEN_MAX),
Johannes Bergc7721c02020-04-30 22:13:10 +0200678 [NL80211_ATTR_MAC_HINT] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Jouni Malinen1df4a512014-01-15 00:00:47 +0200679 [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +0530680 [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
Jukka Rissanen18e5ca62014-11-13 17:25:14 +0200681 [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +0300682 [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
Assaf Kraussbab5ab72014-09-03 15:25:01 +0300683 [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200684 [NL80211_ATTR_TSID] = NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_TIDS - 1),
685 [NL80211_ATTR_USER_PRIO] =
686 NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_UPS - 1),
Johannes Berg960d01a2014-09-09 22:55:35 +0300687 [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
Eliad Peller18998c32014-09-10 14:07:34 +0300688 [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
Jakub Kicinski5cde05c2020-03-02 21:10:58 -0800689 [NL80211_ATTR_OPER_CLASS] = { .type = NLA_U8 },
Johannes Bergc7721c02020-04-30 22:13:10 +0200690 [NL80211_ATTR_MAC_MASK] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Arik Nemtsov1bdd7162014-12-15 19:26:01 +0200691 [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
Vadim Kochan4b681c82015-01-12 16:34:05 +0200692 [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
Luciano Coelho9c748932015-01-16 16:04:09 +0200693 [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
Ilan peer05050752015-03-04 00:32:06 -0500694 [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
Lior David34d50512016-01-28 10:58:25 +0200695 [NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
Arend van Spriel38de03d2016-03-02 20:37:18 +0100696 [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200697 [NL80211_ATTR_STA_SUPPORT_P2P_PS] =
698 NLA_POLICY_MAX(NLA_U8, NUM_NL80211_P2P_PS_STATUS - 1),
Aviya Erenfeldc6e6a0c2016-07-05 15:23:08 +0300699 [NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
700 .len = VHT_MUMIMO_GROUPS_DATA_LEN
701 },
Johannes Bergc7721c02020-04-30 22:13:10 +0200702 [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Johannes Bergab0d76f2018-10-02 10:00:07 +0200703 [NL80211_ATTR_NAN_MASTER_PREF] = NLA_POLICY_MIN(NLA_U8, 1),
Luca Coelho85859892017-02-08 15:00:34 +0200704 [NL80211_ATTR_BANDS] = { .type = NLA_U32 },
Ayala Bekera442b762016-09-20 17:31:15 +0300705 [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
Jouni Malinen348bd452016-10-27 00:42:03 +0300706 [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
707 .len = FILS_MAX_KEK_LEN },
Johannes Bergc7721c02020-04-30 22:13:10 +0200708 [NL80211_ATTR_FILS_NONCES] = NLA_POLICY_EXACT_LEN_WARN(2 * FILS_NONCE_LEN),
Michael Braunce0ce132016-10-10 19:12:22 +0200709 [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
Johannes Bergc7721c02020-04-30 22:13:10 +0200710 [NL80211_ATTR_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
vamsi krishnabf95ecd2017-01-13 01:12:20 +0200711 [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
712 [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
713 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
714 },
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +0200715 [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +0300716 [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
717 .len = FILS_ERP_MAX_USERNAME_LEN },
718 [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
719 .len = FILS_ERP_MAX_REALM_LEN },
720 [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
721 [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
722 .len = FILS_ERP_MAX_RRK_LEN },
Johannes Bergc7721c02020-04-30 22:13:10 +0200723 [NL80211_ATTR_FILS_CACHE_ID] = NLA_POLICY_EXACT_LEN_WARN(2),
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +0300724 [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
Johannes Bergcb9abd42020-08-05 15:47:16 +0200725 [NL80211_ATTR_PMKR0_NAME] = NLA_POLICY_EXACT_LEN(WLAN_PMK_NAME_LEN),
Arend Van Sprielca986ad2017-04-21 13:05:00 +0100726 [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
Srinivas Dasari40cbfa92018-01-25 17:13:38 +0200727 [NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +0200728
729 [NL80211_ATTR_TXQ_LIMIT] = { .type = NLA_U32 },
730 [NL80211_ATTR_TXQ_MEMORY_LIMIT] = { .type = NLA_U32 },
731 [NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
Johannes Bergc8b82802020-08-19 08:56:43 +0200732 [NL80211_ATTR_HE_CAPABILITY] =
733 NLA_POLICY_RANGE(NLA_BINARY,
734 NL80211_HE_MIN_CAPABILITY_LEN,
735 NL80211_HE_MAX_CAPABILITY_LEN),
Johannes Berg0e012b42020-04-12 00:40:30 +0200736 [NL80211_ATTR_FTM_RESPONDER] =
737 NLA_POLICY_NESTED(nl80211_ftm_responder_policy),
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200738 [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1),
739 [NL80211_ATTR_PEER_MEASUREMENTS] =
Johannes Berg23323282019-01-25 10:08:28 +0100740 NLA_POLICY_NESTED(nl80211_pmsr_attr_policy),
Toke Høiland-Jørgensen36647052018-12-18 17:02:07 -0800741 [NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
Chung-Hsien Hsu26f70442019-05-09 09:49:06 +0000742 [NL80211_ATTR_SAE_PASSWORD] = { .type = NLA_BINARY,
743 .len = SAE_PASSWORD_MAX_LEN },
John Crispina0de1ca32019-05-28 13:49:48 +0200744 [NL80211_ATTR_TWT_RESPONDER] = { .type = NLA_FLAG },
John Crispin796e90f2019-07-30 18:37:00 +0200745 [NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy),
Gurumoorthi Gnanasambandhan14f34e362019-10-31 23:46:40 +0200746 [NL80211_ATTR_VLAN_ID] = NLA_POLICY_RANGE(NLA_U16, 1, VLAN_N_VID - 2),
John Crispin5c5e52d2019-12-17 15:19:18 +0100747 [NL80211_ATTR_HE_BSS_COLOR] = NLA_POLICY_NESTED(he_bss_color_policy),
Tamizh chelvam77f576d2020-01-20 13:21:22 +0530748 [NL80211_ATTR_TID_CONFIG] =
749 NLA_POLICY_NESTED_ARRAY(nl80211_tid_config_attr_policy),
Markus Theil5631d962020-03-12 10:10:53 +0100750 [NL80211_ATTR_CONTROL_PORT_NO_PREAUTH] = { .type = NLA_FLAG },
Veerendranath Jakkam7fc82af2020-03-13 01:59:03 +0200751 [NL80211_ATTR_PMK_LIFETIME] = NLA_POLICY_MIN(NLA_U32, 1),
752 [NL80211_ATTR_PMK_REAUTH_THRESHOLD] = NLA_POLICY_RANGE(NLA_U8, 1, 100),
Johannes Berg9dba48a2020-04-17 12:40:15 +0200753 [NL80211_ATTR_RECEIVE_MULTICAST] = { .type = NLA_FLAG },
Thomas Pedersen942ba882020-04-30 10:25:51 -0700754 [NL80211_ATTR_WIPHY_FREQ_OFFSET] = NLA_POLICY_RANGE(NLA_U32, 0, 999),
Thomas Pedersen2032f3b2020-04-30 10:25:52 -0700755 [NL80211_ATTR_SCAN_FREQ_KHZ] = { .type = NLA_NESTED },
Johannes Berg81408602020-08-18 10:17:31 +0200756 [NL80211_ATTR_HE_6GHZ_CAPABILITY] =
757 NLA_POLICY_EXACT_LEN(sizeof(struct ieee80211_he_6ghz_capa)),
Aloka Dixit291c49d2020-09-11 00:05:29 +0000758 [NL80211_ATTR_FILS_DISCOVERY] =
759 NLA_POLICY_NESTED(nl80211_fils_discovery_policy),
Aloka Dixit7443dcd2020-09-11 00:33:00 +0000760 [NL80211_ATTR_UNSOL_BCAST_PROBE_RESP] =
761 NLA_POLICY_NESTED(nl80211_unsol_bcast_probe_resp_policy),
Thomas Pedersend2b75882020-09-21 19:28:04 -0700762 [NL80211_ATTR_S1G_CAPABILITY] =
763 NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
764 [NL80211_ATTR_S1G_CAPABILITY_MASK] =
765 NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
Rohan Dutta9f0ffa42020-10-27 12:09:10 +0200766 [NL80211_ATTR_SAE_PWE] =
767 NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK,
768 NL80211_SAE_PWE_BOTH),
Johannes Berg3bb02142020-12-06 14:54:42 +0200769 [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
Carl Huang6bdb68c2020-12-03 05:37:26 -0500770 [NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
Ben Greearb6db0f82021-02-04 06:46:10 -0800771 [NL80211_ATTR_DISABLE_HE] = { .type = NLA_FLAG },
John Crispin0d2ab3ae2021-07-02 19:44:07 +0200772 [NL80211_ATTR_OBSS_COLOR_BITMAP] = { .type = NLA_U64 },
773 [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 },
774 [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 },
775 [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy),
John Crispindc1e3cb2021-09-15 19:54:34 -0700776 [NL80211_ATTR_MBSSID_CONFIG] =
777 NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
778 [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
Johannes Berg55682962007-09-20 13:09:35 -0400779};
780
Johannes Berge31b8212010-10-05 19:39:30 +0200781/* policy for the key attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000782static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
Johannes Bergfffd0932009-07-08 14:22:54 +0200783 [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
Johannes Bergb9454e82009-07-08 13:29:08 +0200784 [NL80211_KEY_IDX] = { .type = NLA_U8 },
785 [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
Jouni Malinen81962262011-11-02 23:36:31 +0200786 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Bergb9454e82009-07-08 13:29:08 +0200787 [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
788 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200789 [NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1),
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100790 [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
Alexander Wetzel6cdd3972019-03-19 21:34:07 +0100791 [NL80211_KEY_MODE] = NLA_POLICY_RANGE(NLA_U8, 0, NL80211_KEY_SET_TX),
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100792};
793
794/* policy for the key default flags */
795static const struct nla_policy
796nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
797 [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
798 [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
Johannes Bergb9454e82009-07-08 13:29:08 +0200799};
800
Johannes Bergf83ace32016-10-17 08:04:07 +0200801#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +0200802/* policy for WoWLAN attributes */
803static const struct nla_policy
804nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
805 [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
806 [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
807 [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
808 [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
Johannes Berg77dbbb12011-07-13 10:48:55 +0200809 [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG },
810 [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG },
811 [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG },
812 [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100813 [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED },
Luciano Coelho8cd4d452014-09-17 11:55:28 +0300814 [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100815};
816
817static const struct nla_policy
818nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
819 [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
820 [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
Johannes Bergc7721c02020-04-30 22:13:10 +0200821 [NL80211_WOWLAN_TCP_DST_MAC] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Johannes Berg2a0e0472013-01-23 22:57:40 +0100822 [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
823 [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
Johannes Bergbc043582020-08-18 10:17:32 +0200824 [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = NLA_POLICY_MIN_LEN(1),
Johannes Berg2a0e0472013-01-23 22:57:40 +0100825 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
826 .len = sizeof(struct nl80211_wowlan_tcp_data_seq)
827 },
828 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = {
829 .len = sizeof(struct nl80211_wowlan_tcp_data_token)
830 },
831 [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
Johannes Bergbc043582020-08-18 10:17:32 +0200832 [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = NLA_POLICY_MIN_LEN(1),
833 [NL80211_WOWLAN_TCP_WAKE_MASK] = NLA_POLICY_MIN_LEN(1),
Johannes Bergff1b6e62011-05-04 15:37:28 +0200834};
Johannes Bergf83ace32016-10-17 08:04:07 +0200835#endif /* CONFIG_PM */
Johannes Bergff1b6e62011-05-04 15:37:28 +0200836
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -0700837/* policy for coalesce rule attributes */
838static const struct nla_policy
839nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
840 [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
Johannes Bergab0d76f2018-10-02 10:00:07 +0200841 [NL80211_ATTR_COALESCE_RULE_CONDITION] =
842 NLA_POLICY_RANGE(NLA_U32,
843 NL80211_COALESCE_CONDITION_MATCH,
844 NL80211_COALESCE_CONDITION_NO_MATCH),
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -0700845 [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
846};
847
Johannes Berge5497d72011-07-05 16:35:40 +0200848/* policy for GTK rekey offload attributes */
849static const struct nla_policy
850nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
Nathan Errera093a48d2020-05-28 21:22:38 +0200851 [NL80211_REKEY_DATA_KEK] = {
852 .type = NLA_BINARY,
853 .len = NL80211_KEK_EXT_LEN
854 },
855 [NL80211_REKEY_DATA_KCK] = {
856 .type = NLA_BINARY,
857 .len = NL80211_KCK_EXT_LEN
858 },
Johannes Bergcb9abd42020-08-05 15:47:16 +0200859 [NL80211_REKEY_DATA_REPLAY_CTR] = NLA_POLICY_EXACT_LEN(NL80211_REPLAY_CTR_LEN),
Nathan Errera093a48d2020-05-28 21:22:38 +0200860 [NL80211_REKEY_DATA_AKM] = { .type = NLA_U32 },
Johannes Berge5497d72011-07-05 16:35:40 +0200861};
862
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300863static const struct nla_policy
vamsi krishna1e1b11b2019-02-01 18:34:51 +0530864nl80211_match_band_rssi_policy[NUM_NL80211_BANDS] = {
865 [NL80211_BAND_2GHZ] = { .type = NLA_S32 },
866 [NL80211_BAND_5GHZ] = { .type = NLA_S32 },
Arend van Spriele548a1c2019-08-02 13:31:02 +0200867 [NL80211_BAND_6GHZ] = { .type = NLA_S32 },
vamsi krishna1e1b11b2019-02-01 18:34:51 +0530868 [NL80211_BAND_60GHZ] = { .type = NLA_S32 },
Srinivasan Raju63fa0422021-10-18 11:00:54 +0100869 [NL80211_BAND_LC] = { .type = NLA_S32 },
vamsi krishna1e1b11b2019-02-01 18:34:51 +0530870};
871
872static const struct nla_policy
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300873nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
Johannes Berg4a4ab0d2012-06-13 11:17:11 +0200874 [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300875 .len = IEEE80211_MAX_SSID_LEN },
Johannes Bergc7721c02020-04-30 22:13:10 +0200876 [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Thomas Pedersen88e920b2012-06-21 11:09:54 -0700877 [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
vamsi krishna1e1b11b2019-02-01 18:34:51 +0530878 [NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] =
879 NLA_POLICY_NESTED(nl80211_match_band_rssi_policy),
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300880};
881
Avraham Stern3b06d272015-10-12 09:51:34 +0300882static const struct nla_policy
883nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
884 [NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
885 [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
886};
887
Arend van Spriel38de03d2016-03-02 20:37:18 +0100888static const struct nla_policy
889nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
890 [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
891 [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
892 [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
893 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
894 },
895};
896
Ayala Bekera442b762016-09-20 17:31:15 +0300897/* policy for NAN function attributes */
898static const struct nla_policy
899nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
Johannes Bergcb9abd42020-08-05 15:47:16 +0200900 [NL80211_NAN_FUNC_TYPE] =
901 NLA_POLICY_MAX(NLA_U8, NL80211_NAN_FUNC_MAX_TYPE),
Srinivas Dasari0a278442017-07-07 01:43:40 +0300902 [NL80211_NAN_FUNC_SERVICE_ID] = {
Ayala Bekera442b762016-09-20 17:31:15 +0300903 .len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
904 [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
905 [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
906 [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
907 [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
908 [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
Johannes Bergc7721c02020-04-30 22:13:10 +0200909 [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
Ayala Bekera442b762016-09-20 17:31:15 +0300910 [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
911 [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
912 [NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
913 .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN },
914 [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
915 [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
916 [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
917 [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8 },
918 [NL80211_NAN_FUNC_TERM_REASON] = { .type = NLA_U8 },
919};
920
921/* policy for Service Response Filter attributes */
922static const struct nla_policy
923nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
924 [NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG },
925 [NL80211_NAN_SRF_BF] = { .type = NLA_BINARY,
926 .len = NL80211_NAN_FUNC_SRF_MAX_LEN },
927 [NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 },
928 [NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED },
929};
930
Peng Xuad670232017-10-03 23:21:51 +0300931/* policy for packet pattern attributes */
932static const struct nla_policy
933nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
934 [NL80211_PKTPAT_MASK] = { .type = NLA_BINARY, },
935 [NL80211_PKTPAT_PATTERN] = { .type = NLA_BINARY, },
936 [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 },
937};
938
Johannes Berg9bb7e0f2018-09-10 13:29:12 +0200939int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
940 struct cfg80211_registered_device **rdev,
941 struct wireless_dev **wdev)
Holger Schuriga0438972009-11-11 11:30:02 +0100942{
Johannes Berg67748892010-10-04 21:14:06 +0200943 int err;
944
Johannes Berg97990a02013-04-19 01:02:55 +0200945 if (!cb->args[0]) {
Johannes Berg50508d92019-07-29 16:31:09 +0200946 struct nlattr **attrbuf;
947
948 attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
949 GFP_KERNEL);
950 if (!attrbuf)
951 return -ENOMEM;
952
Johannes Berg8cb08172019-04-26 14:07:28 +0200953 err = nlmsg_parse_deprecated(cb->nlh,
954 GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Berg50508d92019-07-29 16:31:09 +0200955 attrbuf, nl80211_fam.maxattr,
Johannes Berg8cb08172019-04-26 14:07:28 +0200956 nl80211_policy, NULL);
Johannes Berg50508d92019-07-29 16:31:09 +0200957 if (err) {
958 kfree(attrbuf);
Johannes Bergea90e0d2017-03-15 14:26:04 +0100959 return err;
Johannes Berg50508d92019-07-29 16:31:09 +0200960 }
Johannes Berg97990a02013-04-19 01:02:55 +0200961
Johannes Berga05829a2021-01-22 16:19:43 +0100962 rtnl_lock();
963 *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(cb->skb->sk),
Johannes Berg50508d92019-07-29 16:31:09 +0200964 attrbuf);
965 kfree(attrbuf);
Johannes Berga05829a2021-01-22 16:19:43 +0100966 if (IS_ERR(*wdev)) {
967 rtnl_unlock();
Johannes Bergea90e0d2017-03-15 14:26:04 +0100968 return PTR_ERR(*wdev);
Johannes Berga05829a2021-01-22 16:19:43 +0100969 }
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800970 *rdev = wiphy_to_rdev((*wdev)->wiphy);
Johannes Berga05829a2021-01-22 16:19:43 +0100971 mutex_lock(&(*rdev)->wiphy.mtx);
972 rtnl_unlock();
Johannes Bergc319d502013-07-30 22:34:28 +0200973 /* 0 is the first index - add 1 to parse only once */
974 cb->args[0] = (*rdev)->wiphy_idx + 1;
Johannes Berg97990a02013-04-19 01:02:55 +0200975 cb->args[1] = (*wdev)->identifier;
976 } else {
Johannes Bergc319d502013-07-30 22:34:28 +0200977 /* subtract the 1 again here */
Johannes Berga05829a2021-01-22 16:19:43 +0100978 struct wiphy *wiphy;
Johannes Berg97990a02013-04-19 01:02:55 +0200979 struct wireless_dev *tmp;
980
Johannes Berga05829a2021-01-22 16:19:43 +0100981 rtnl_lock();
982 wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
983 if (!wiphy) {
984 rtnl_unlock();
Johannes Bergea90e0d2017-03-15 14:26:04 +0100985 return -ENODEV;
Johannes Berga05829a2021-01-22 16:19:43 +0100986 }
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800987 *rdev = wiphy_to_rdev(wiphy);
Johannes Berg97990a02013-04-19 01:02:55 +0200988 *wdev = NULL;
989
Johannes Berg53873f12016-05-03 16:52:04 +0300990 list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
Johannes Berg97990a02013-04-19 01:02:55 +0200991 if (tmp->identifier == cb->args[1]) {
992 *wdev = tmp;
993 break;
994 }
995 }
Johannes Berg97990a02013-04-19 01:02:55 +0200996
Johannes Berga05829a2021-01-22 16:19:43 +0100997 if (!*wdev) {
998 rtnl_unlock();
Johannes Bergea90e0d2017-03-15 14:26:04 +0100999 return -ENODEV;
Johannes Berga05829a2021-01-22 16:19:43 +01001000 }
1001 mutex_lock(&(*rdev)->wiphy.mtx);
1002 rtnl_unlock();
Johannes Berg67748892010-10-04 21:14:06 +02001003 }
1004
Johannes Berg67748892010-10-04 21:14:06 +02001005 return 0;
Johannes Berg67748892010-10-04 21:14:06 +02001006}
1007
Johannes Berg55682962007-09-20 13:09:35 -04001008/* message building helper */
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02001009void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
1010 int flags, u8 cmd)
Johannes Berg55682962007-09-20 13:09:35 -04001011{
1012 /* since there is no private header just add the generic one */
Eric W. Biederman15e47302012-09-07 20:12:54 +00001013 return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04001014}
1015
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001016static int nl80211_msg_put_wmm_rules(struct sk_buff *msg,
1017 const struct ieee80211_reg_rule *rule)
1018{
1019 int j;
1020 struct nlattr *nl_wmm_rules =
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001021 nla_nest_start_noflag(msg, NL80211_FREQUENCY_ATTR_WMM);
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001022
1023 if (!nl_wmm_rules)
1024 goto nla_put_failure;
1025
1026 for (j = 0; j < IEEE80211_NUM_ACS; j++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001027 struct nlattr *nl_wmm_rule = nla_nest_start_noflag(msg, j);
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001028
1029 if (!nl_wmm_rule)
1030 goto nla_put_failure;
1031
1032 if (nla_put_u16(msg, NL80211_WMMR_CW_MIN,
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +02001033 rule->wmm_rule.client[j].cw_min) ||
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001034 nla_put_u16(msg, NL80211_WMMR_CW_MAX,
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +02001035 rule->wmm_rule.client[j].cw_max) ||
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001036 nla_put_u8(msg, NL80211_WMMR_AIFSN,
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +02001037 rule->wmm_rule.client[j].aifsn) ||
Haim Dreyfussd3c89bb2018-08-21 09:22:19 +03001038 nla_put_u16(msg, NL80211_WMMR_TXOP,
1039 rule->wmm_rule.client[j].cot))
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001040 goto nla_put_failure;
1041
1042 nla_nest_end(msg, nl_wmm_rule);
1043 }
1044 nla_nest_end(msg, nl_wmm_rules);
1045
1046 return 0;
1047
1048nla_put_failure:
1049 return -ENOBUFS;
1050}
1051
1052static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
Johannes Bergcdc89b92013-02-18 23:54:36 +01001053 struct ieee80211_channel *chan,
1054 bool large)
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -04001055{
Rostislav Lisovyea077c12014-04-15 14:37:55 +02001056 /* Some channels must be completely excluded from the
1057 * list to protect old user-space tools from breaking
1058 */
1059 if (!large && chan->flags &
1060 (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
1061 return 0;
Johannes Bergf8d504c2020-09-28 13:06:56 +02001062 if (!large && chan->freq_offset)
1063 return 0;
Rostislav Lisovyea077c12014-04-15 14:37:55 +02001064
David S. Miller9360ffd2012-03-29 04:41:26 -04001065 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
1066 chan->center_freq))
1067 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -04001068
Thomas Pedersen942ba882020-04-30 10:25:51 -07001069 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_OFFSET, chan->freq_offset))
1070 goto nla_put_failure;
1071
David S. Miller9360ffd2012-03-29 04:41:26 -04001072 if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
1073 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
1074 goto nla_put_failure;
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +02001075 if (chan->flags & IEEE80211_CHAN_NO_IR) {
1076 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
1077 goto nla_put_failure;
1078 if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
1079 goto nla_put_failure;
1080 }
Johannes Bergcdc89b92013-02-18 23:54:36 +01001081 if (chan->flags & IEEE80211_CHAN_RADAR) {
1082 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
1083 goto nla_put_failure;
1084 if (large) {
1085 u32 time;
1086
1087 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
1088
1089 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
1090 chan->dfs_state))
1091 goto nla_put_failure;
1092 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
1093 time))
1094 goto nla_put_failure;
Janusz Dziedzic089027e2014-02-21 19:46:12 +01001095 if (nla_put_u32(msg,
1096 NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
1097 chan->dfs_cac_ms))
1098 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +01001099 }
1100 }
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -04001101
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001102 if (large) {
1103 if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
1104 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
1105 goto nla_put_failure;
1106 if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
1107 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
1108 goto nla_put_failure;
1109 if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
1110 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
1111 goto nla_put_failure;
1112 if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
1113 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
1114 goto nla_put_failure;
David Spinadel570dbde2014-02-23 09:12:59 +02001115 if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
1116 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
1117 goto nla_put_failure;
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001118 if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
1119 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
David Spinadel570dbde2014-02-23 09:12:59 +02001120 goto nla_put_failure;
Rostislav Lisovyea077c12014-04-15 14:37:55 +02001121 if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
1122 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
1123 goto nla_put_failure;
1124 if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
1125 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
1126 goto nla_put_failure;
Haim Dreyfuss1e61d822020-01-21 10:12:13 +02001127 if ((chan->flags & IEEE80211_CHAN_NO_HE) &&
1128 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HE))
1129 goto nla_put_failure;
Thomas Pedersend65a9772020-09-08 12:03:03 -07001130 if ((chan->flags & IEEE80211_CHAN_1MHZ) &&
1131 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_1MHZ))
1132 goto nla_put_failure;
1133 if ((chan->flags & IEEE80211_CHAN_2MHZ) &&
1134 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_2MHZ))
1135 goto nla_put_failure;
1136 if ((chan->flags & IEEE80211_CHAN_4MHZ) &&
1137 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_4MHZ))
1138 goto nla_put_failure;
1139 if ((chan->flags & IEEE80211_CHAN_8MHZ) &&
1140 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_8MHZ))
1141 goto nla_put_failure;
1142 if ((chan->flags & IEEE80211_CHAN_16MHZ) &&
1143 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_16MHZ))
1144 goto nla_put_failure;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001145 }
1146
David S. Miller9360ffd2012-03-29 04:41:26 -04001147 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
1148 DBM_TO_MBM(chan->max_power)))
1149 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -04001150
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001151 if (large) {
1152 const struct ieee80211_reg_rule *rule =
Haim Dreyfussb88d26d2018-08-21 09:22:20 +03001153 freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001154
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +02001155 if (!IS_ERR_OR_NULL(rule) && rule->has_wmm) {
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001156 if (nl80211_msg_put_wmm_rules(msg, rule))
1157 goto nla_put_failure;
1158 }
1159 }
1160
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -04001161 return 0;
1162
1163 nla_put_failure:
1164 return -ENOBUFS;
1165}
1166
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02001167static bool nl80211_put_txq_stats(struct sk_buff *msg,
1168 struct cfg80211_txq_stats *txqstats,
1169 int attrtype)
1170{
1171 struct nlattr *txqattr;
1172
1173#define PUT_TXQVAL_U32(attr, memb) do { \
1174 if (txqstats->filled & BIT(NL80211_TXQ_STATS_ ## attr) && \
1175 nla_put_u32(msg, NL80211_TXQ_STATS_ ## attr, txqstats->memb)) \
1176 return false; \
1177 } while (0)
1178
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001179 txqattr = nla_nest_start_noflag(msg, attrtype);
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02001180 if (!txqattr)
1181 return false;
1182
1183 PUT_TXQVAL_U32(BACKLOG_BYTES, backlog_bytes);
1184 PUT_TXQVAL_U32(BACKLOG_PACKETS, backlog_packets);
1185 PUT_TXQVAL_U32(FLOWS, flows);
1186 PUT_TXQVAL_U32(DROPS, drops);
1187 PUT_TXQVAL_U32(ECN_MARKS, ecn_marks);
1188 PUT_TXQVAL_U32(OVERLIMIT, overlimit);
1189 PUT_TXQVAL_U32(OVERMEMORY, overmemory);
1190 PUT_TXQVAL_U32(COLLISIONS, collisions);
1191 PUT_TXQVAL_U32(TX_BYTES, tx_bytes);
1192 PUT_TXQVAL_U32(TX_PACKETS, tx_packets);
1193 PUT_TXQVAL_U32(MAX_FLOWS, max_flows);
1194 nla_nest_end(msg, txqattr);
1195
1196#undef PUT_TXQVAL_U32
1197 return true;
1198}
1199
Johannes Berg55682962007-09-20 13:09:35 -04001200/* netlink command implementations */
1201
Johannes Bergb9454e82009-07-08 13:29:08 +02001202struct key_parse {
1203 struct key_params p;
1204 int idx;
Johannes Berge31b8212010-10-05 19:39:30 +02001205 int type;
Jouni Malinen56be3932020-02-22 15:25:43 +02001206 bool def, defmgmt, defbeacon;
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001207 bool def_uni, def_multi;
Johannes Bergb9454e82009-07-08 13:29:08 +02001208};
1209
Johannes Berg768075e2017-11-13 15:35:06 +01001210static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
1211 struct key_parse *k)
Johannes Bergb9454e82009-07-08 13:29:08 +02001212{
1213 struct nlattr *tb[NL80211_KEY_MAX + 1];
Johannes Berg8cb08172019-04-26 14:07:28 +02001214 int err = nla_parse_nested_deprecated(tb, NL80211_KEY_MAX, key,
1215 nl80211_key_policy,
1216 info->extack);
Johannes Bergb9454e82009-07-08 13:29:08 +02001217 if (err)
1218 return err;
1219
1220 k->def = !!tb[NL80211_KEY_DEFAULT];
1221 k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
Jouni Malinen56be3932020-02-22 15:25:43 +02001222 k->defbeacon = !!tb[NL80211_KEY_DEFAULT_BEACON];
Johannes Bergb9454e82009-07-08 13:29:08 +02001223
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001224 if (k->def) {
1225 k->def_uni = true;
1226 k->def_multi = true;
1227 }
Jouni Malinen56be3932020-02-22 15:25:43 +02001228 if (k->defmgmt || k->defbeacon)
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001229 k->def_multi = true;
1230
Johannes Bergb9454e82009-07-08 13:29:08 +02001231 if (tb[NL80211_KEY_IDX])
1232 k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
1233
1234 if (tb[NL80211_KEY_DATA]) {
1235 k->p.key = nla_data(tb[NL80211_KEY_DATA]);
1236 k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
1237 }
1238
1239 if (tb[NL80211_KEY_SEQ]) {
1240 k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
1241 k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
1242 }
1243
1244 if (tb[NL80211_KEY_CIPHER])
1245 k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
1246
Johannes Bergab0d76f2018-10-02 10:00:07 +02001247 if (tb[NL80211_KEY_TYPE])
Johannes Berge31b8212010-10-05 19:39:30 +02001248 k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
Johannes Berge31b8212010-10-05 19:39:30 +02001249
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001250 if (tb[NL80211_KEY_DEFAULT_TYPES]) {
1251 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07001252
Johannes Berg8cb08172019-04-26 14:07:28 +02001253 err = nla_parse_nested_deprecated(kdt,
1254 NUM_NL80211_KEY_DEFAULT_TYPES - 1,
1255 tb[NL80211_KEY_DEFAULT_TYPES],
1256 nl80211_key_default_policy,
1257 info->extack);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001258 if (err)
1259 return err;
1260
1261 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
1262 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
1263 }
1264
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01001265 if (tb[NL80211_KEY_MODE])
1266 k->p.mode = nla_get_u8(tb[NL80211_KEY_MODE]);
1267
Johannes Bergb9454e82009-07-08 13:29:08 +02001268 return 0;
1269}
1270
1271static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
1272{
1273 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
1274 k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
1275 k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
1276 }
1277
1278 if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
1279 k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
1280 k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
1281 }
1282
1283 if (info->attrs[NL80211_ATTR_KEY_IDX])
1284 k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
1285
1286 if (info->attrs[NL80211_ATTR_KEY_CIPHER])
1287 k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
1288
1289 k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
1290 k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
1291
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001292 if (k->def) {
1293 k->def_uni = true;
1294 k->def_multi = true;
1295 }
1296 if (k->defmgmt)
1297 k->def_multi = true;
1298
Johannes Bergab0d76f2018-10-02 10:00:07 +02001299 if (info->attrs[NL80211_ATTR_KEY_TYPE])
Johannes Berge31b8212010-10-05 19:39:30 +02001300 k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Johannes Berge31b8212010-10-05 19:39:30 +02001301
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001302 if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
1303 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Johannes Berg8cb08172019-04-26 14:07:28 +02001304 int err = nla_parse_nested_deprecated(kdt,
1305 NUM_NL80211_KEY_DEFAULT_TYPES - 1,
1306 info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
1307 nl80211_key_default_policy,
1308 info->extack);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001309 if (err)
1310 return err;
1311
1312 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
1313 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
1314 }
1315
Johannes Bergb9454e82009-07-08 13:29:08 +02001316 return 0;
1317}
1318
1319static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
1320{
1321 int err;
1322
1323 memset(k, 0, sizeof(*k));
1324 k->idx = -1;
Johannes Berge31b8212010-10-05 19:39:30 +02001325 k->type = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +02001326
1327 if (info->attrs[NL80211_ATTR_KEY])
Johannes Berg768075e2017-11-13 15:35:06 +01001328 err = nl80211_parse_key_new(info, info->attrs[NL80211_ATTR_KEY], k);
Johannes Bergb9454e82009-07-08 13:29:08 +02001329 else
1330 err = nl80211_parse_key_old(info, k);
1331
1332 if (err)
1333 return err;
1334
Jouni Malinen56be3932020-02-22 15:25:43 +02001335 if ((k->def ? 1 : 0) + (k->defmgmt ? 1 : 0) +
1336 (k->defbeacon ? 1 : 0) > 1) {
1337 GENL_SET_ERR_MSG(info,
1338 "key with multiple default flags is invalid");
Johannes Bergb9454e82009-07-08 13:29:08 +02001339 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001340 }
Johannes Bergb9454e82009-07-08 13:29:08 +02001341
Jouni Malinen56be3932020-02-22 15:25:43 +02001342 if (k->defmgmt || k->defbeacon) {
Johannes Berg768075e2017-11-13 15:35:06 +01001343 if (k->def_uni || !k->def_multi) {
Jouni Malinen56be3932020-02-22 15:25:43 +02001344 GENL_SET_ERR_MSG(info,
1345 "defmgmt/defbeacon key must be mcast");
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001346 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001347 }
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001348 }
1349
Johannes Bergb9454e82009-07-08 13:29:08 +02001350 if (k->idx != -1) {
1351 if (k->defmgmt) {
Johannes Berg768075e2017-11-13 15:35:06 +01001352 if (k->idx < 4 || k->idx > 5) {
1353 GENL_SET_ERR_MSG(info,
1354 "defmgmt key idx not 4 or 5");
Johannes Bergb9454e82009-07-08 13:29:08 +02001355 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001356 }
Jouni Malinen56be3932020-02-22 15:25:43 +02001357 } else if (k->defbeacon) {
1358 if (k->idx < 6 || k->idx > 7) {
1359 GENL_SET_ERR_MSG(info,
1360 "defbeacon key idx not 6 or 7");
1361 return -EINVAL;
1362 }
Johannes Bergb9454e82009-07-08 13:29:08 +02001363 } else if (k->def) {
Johannes Berg768075e2017-11-13 15:35:06 +01001364 if (k->idx < 0 || k->idx > 3) {
1365 GENL_SET_ERR_MSG(info, "def key idx not 0-3");
Johannes Bergb9454e82009-07-08 13:29:08 +02001366 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001367 }
Johannes Bergb9454e82009-07-08 13:29:08 +02001368 } else {
Jouni Malinen56be3932020-02-22 15:25:43 +02001369 if (k->idx < 0 || k->idx > 7) {
1370 GENL_SET_ERR_MSG(info, "key idx not 0-7");
Johannes Bergb9454e82009-07-08 13:29:08 +02001371 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001372 }
Johannes Bergb9454e82009-07-08 13:29:08 +02001373 }
1374 }
1375
1376 return 0;
1377}
1378
Johannes Bergfffd0932009-07-08 14:22:54 +02001379static struct cfg80211_cached_keys *
1380nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
Johannes Berg768075e2017-11-13 15:35:06 +01001381 struct genl_info *info, bool *no_ht)
Johannes Bergfffd0932009-07-08 14:22:54 +02001382{
Johannes Berg768075e2017-11-13 15:35:06 +01001383 struct nlattr *keys = info->attrs[NL80211_ATTR_KEYS];
Johannes Bergfffd0932009-07-08 14:22:54 +02001384 struct key_parse parse;
1385 struct nlattr *key;
1386 struct cfg80211_cached_keys *result;
1387 int rem, err, def = 0;
Johannes Bergf1c1f172016-09-13 17:08:23 +02001388 bool have_key = false;
1389
1390 nla_for_each_nested(key, keys, rem) {
1391 have_key = true;
1392 break;
1393 }
1394
1395 if (!have_key)
1396 return NULL;
Johannes Bergfffd0932009-07-08 14:22:54 +02001397
1398 result = kzalloc(sizeof(*result), GFP_KERNEL);
1399 if (!result)
1400 return ERR_PTR(-ENOMEM);
1401
1402 result->def = -1;
Johannes Bergfffd0932009-07-08 14:22:54 +02001403
1404 nla_for_each_nested(key, keys, rem) {
1405 memset(&parse, 0, sizeof(parse));
1406 parse.idx = -1;
1407
Johannes Berg768075e2017-11-13 15:35:06 +01001408 err = nl80211_parse_key_new(info, key, &parse);
Johannes Bergfffd0932009-07-08 14:22:54 +02001409 if (err)
1410 goto error;
1411 err = -EINVAL;
1412 if (!parse.p.key)
1413 goto error;
Johannes Berg768075e2017-11-13 15:35:06 +01001414 if (parse.idx < 0 || parse.idx > 3) {
1415 GENL_SET_ERR_MSG(info, "key index out of range [0-3]");
Johannes Bergfffd0932009-07-08 14:22:54 +02001416 goto error;
Johannes Berg768075e2017-11-13 15:35:06 +01001417 }
Johannes Bergfffd0932009-07-08 14:22:54 +02001418 if (parse.def) {
Johannes Berg768075e2017-11-13 15:35:06 +01001419 if (def) {
1420 GENL_SET_ERR_MSG(info,
1421 "only one key can be default");
Johannes Bergfffd0932009-07-08 14:22:54 +02001422 goto error;
Johannes Berg768075e2017-11-13 15:35:06 +01001423 }
Johannes Bergfffd0932009-07-08 14:22:54 +02001424 def = 1;
1425 result->def = parse.idx;
Johannes Bergdbd2fd62010-12-09 19:58:59 +01001426 if (!parse.def_uni || !parse.def_multi)
1427 goto error;
Johannes Bergfffd0932009-07-08 14:22:54 +02001428 } else if (parse.defmgmt)
1429 goto error;
1430 err = cfg80211_validate_key_settings(rdev, &parse.p,
Johannes Berge31b8212010-10-05 19:39:30 +02001431 parse.idx, false, NULL);
Johannes Bergfffd0932009-07-08 14:22:54 +02001432 if (err)
1433 goto error;
Johannes Berg386b1f22016-09-13 16:10:02 +02001434 if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
1435 parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) {
Johannes Berg768075e2017-11-13 15:35:06 +01001436 GENL_SET_ERR_MSG(info, "connect key must be WEP");
Johannes Berg386b1f22016-09-13 16:10:02 +02001437 err = -EINVAL;
1438 goto error;
1439 }
Johannes Bergfffd0932009-07-08 14:22:54 +02001440 result->params[parse.idx].cipher = parse.p.cipher;
1441 result->params[parse.idx].key_len = parse.p.key_len;
1442 result->params[parse.idx].key = result->data[parse.idx];
1443 memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
Sujith Manoharande7044e2012-10-18 10:19:28 +05301444
Johannes Berg386b1f22016-09-13 16:10:02 +02001445 /* must be WEP key if we got here */
1446 if (no_ht)
1447 *no_ht = true;
Johannes Bergfffd0932009-07-08 14:22:54 +02001448 }
1449
Johannes Bergf1c1f172016-09-13 17:08:23 +02001450 if (result->def < 0) {
1451 err = -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001452 GENL_SET_ERR_MSG(info, "need a default/TX key");
Johannes Bergf1c1f172016-09-13 17:08:23 +02001453 goto error;
1454 }
1455
Johannes Bergfffd0932009-07-08 14:22:54 +02001456 return result;
1457 error:
1458 kfree(result);
1459 return ERR_PTR(err);
1460}
1461
1462static int nl80211_key_allowed(struct wireless_dev *wdev)
1463{
1464 ASSERT_WDEV_LOCK(wdev);
1465
Johannes Bergfffd0932009-07-08 14:22:54 +02001466 switch (wdev->iftype) {
1467 case NL80211_IFTYPE_AP:
1468 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02001469 case NL80211_IFTYPE_P2P_GO:
Thomas Pedersenff973af2011-05-03 16:57:12 -07001470 case NL80211_IFTYPE_MESH_POINT:
Johannes Bergfffd0932009-07-08 14:22:54 +02001471 break;
1472 case NL80211_IFTYPE_ADHOC:
Johannes Bergfffd0932009-07-08 14:22:54 +02001473 case NL80211_IFTYPE_STATION:
Johannes Berg074ac8d2010-09-16 14:58:22 +02001474 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Bergceca7b72013-05-16 00:55:45 +02001475 if (!wdev->current_bss)
Johannes Bergfffd0932009-07-08 14:22:54 +02001476 return -ENOLINK;
1477 break;
Johannes Bergde4fcba2014-10-31 14:16:12 +01001478 case NL80211_IFTYPE_UNSPECIFIED:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01001479 case NL80211_IFTYPE_OCB:
Johannes Bergde4fcba2014-10-31 14:16:12 +01001480 case NL80211_IFTYPE_MONITOR:
Ayala Bekercb3b7d82016-09-20 17:31:13 +03001481 case NL80211_IFTYPE_NAN:
Johannes Bergde4fcba2014-10-31 14:16:12 +01001482 case NL80211_IFTYPE_P2P_DEVICE:
1483 case NL80211_IFTYPE_WDS:
1484 case NUM_NL80211_IFTYPES:
Johannes Bergfffd0932009-07-08 14:22:54 +02001485 return -EINVAL;
1486 }
1487
1488 return 0;
1489}
1490
Jouni Malinen664834d2014-01-15 00:01:44 +02001491static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
Thomas Pedersen942ba882020-04-30 10:25:51 -07001492 u32 freq)
Jouni Malinen664834d2014-01-15 00:01:44 +02001493{
1494 struct ieee80211_channel *chan;
1495
Thomas Pedersen942ba882020-04-30 10:25:51 -07001496 chan = ieee80211_get_channel_khz(wiphy, freq);
Jouni Malinen664834d2014-01-15 00:01:44 +02001497 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
1498 return NULL;
1499 return chan;
1500}
1501
Johannes Berg7527a782011-05-13 10:58:57 +02001502static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
1503{
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001504 struct nlattr *nl_modes = nla_nest_start_noflag(msg, attr);
Johannes Berg7527a782011-05-13 10:58:57 +02001505 int i;
1506
1507 if (!nl_modes)
1508 goto nla_put_failure;
1509
1510 i = 0;
1511 while (ifmodes) {
David S. Miller9360ffd2012-03-29 04:41:26 -04001512 if ((ifmodes & 1) && nla_put_flag(msg, i))
1513 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001514 ifmodes >>= 1;
1515 i++;
1516 }
1517
1518 nla_nest_end(msg, nl_modes);
1519 return 0;
1520
1521nla_put_failure:
1522 return -ENOBUFS;
1523}
1524
1525static int nl80211_put_iface_combinations(struct wiphy *wiphy,
Johannes Bergcdc89b92013-02-18 23:54:36 +01001526 struct sk_buff *msg,
1527 bool large)
Johannes Berg7527a782011-05-13 10:58:57 +02001528{
1529 struct nlattr *nl_combis;
1530 int i, j;
1531
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001532 nl_combis = nla_nest_start_noflag(msg,
1533 NL80211_ATTR_INTERFACE_COMBINATIONS);
Johannes Berg7527a782011-05-13 10:58:57 +02001534 if (!nl_combis)
1535 goto nla_put_failure;
1536
1537 for (i = 0; i < wiphy->n_iface_combinations; i++) {
1538 const struct ieee80211_iface_combination *c;
1539 struct nlattr *nl_combi, *nl_limits;
1540
1541 c = &wiphy->iface_combinations[i];
1542
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001543 nl_combi = nla_nest_start_noflag(msg, i + 1);
Johannes Berg7527a782011-05-13 10:58:57 +02001544 if (!nl_combi)
1545 goto nla_put_failure;
1546
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001547 nl_limits = nla_nest_start_noflag(msg,
1548 NL80211_IFACE_COMB_LIMITS);
Johannes Berg7527a782011-05-13 10:58:57 +02001549 if (!nl_limits)
1550 goto nla_put_failure;
1551
1552 for (j = 0; j < c->n_limits; j++) {
1553 struct nlattr *nl_limit;
1554
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001555 nl_limit = nla_nest_start_noflag(msg, j + 1);
Johannes Berg7527a782011-05-13 10:58:57 +02001556 if (!nl_limit)
1557 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04001558 if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
1559 c->limits[j].max))
1560 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001561 if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
1562 c->limits[j].types))
1563 goto nla_put_failure;
1564 nla_nest_end(msg, nl_limit);
1565 }
1566
1567 nla_nest_end(msg, nl_limits);
1568
David S. Miller9360ffd2012-03-29 04:41:26 -04001569 if (c->beacon_int_infra_match &&
1570 nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
1571 goto nla_put_failure;
1572 if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
1573 c->num_different_channels) ||
1574 nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
1575 c->max_interfaces))
1576 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +01001577 if (large &&
Felix Fietkau8c48b502014-05-05 11:48:40 +02001578 (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
1579 c->radar_detect_widths) ||
1580 nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
1581 c->radar_detect_regions)))
Johannes Bergcdc89b92013-02-18 23:54:36 +01001582 goto nla_put_failure;
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05301583 if (c->beacon_int_min_gcd &&
1584 nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
1585 c->beacon_int_min_gcd))
1586 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001587
1588 nla_nest_end(msg, nl_combi);
1589 }
1590
1591 nla_nest_end(msg, nl_combis);
1592
1593 return 0;
1594nla_put_failure:
1595 return -ENOBUFS;
1596}
1597
Johannes Berg3713b4e2013-02-14 16:19:38 +01001598#ifdef CONFIG_PM
Johannes Bergb56cf722013-02-20 01:02:38 +01001599static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
1600 struct sk_buff *msg)
1601{
Johannes Berg964dc9e2013-06-03 17:25:34 +02001602 const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
Johannes Bergb56cf722013-02-20 01:02:38 +01001603 struct nlattr *nl_tcp;
1604
1605 if (!tcp)
1606 return 0;
1607
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001608 nl_tcp = nla_nest_start_noflag(msg,
1609 NL80211_WOWLAN_TRIG_TCP_CONNECTION);
Johannes Bergb56cf722013-02-20 01:02:38 +01001610 if (!nl_tcp)
1611 return -ENOBUFS;
1612
1613 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1614 tcp->data_payload_max))
1615 return -ENOBUFS;
1616
1617 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1618 tcp->data_payload_max))
1619 return -ENOBUFS;
1620
1621 if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
1622 return -ENOBUFS;
1623
1624 if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
1625 sizeof(*tcp->tok), tcp->tok))
1626 return -ENOBUFS;
1627
1628 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
1629 tcp->data_interval_max))
1630 return -ENOBUFS;
1631
1632 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
1633 tcp->wake_payload_max))
1634 return -ENOBUFS;
1635
1636 nla_nest_end(msg, nl_tcp);
1637 return 0;
1638}
1639
Johannes Berg3713b4e2013-02-14 16:19:38 +01001640static int nl80211_send_wowlan(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001641 struct cfg80211_registered_device *rdev,
Johannes Bergb56cf722013-02-20 01:02:38 +01001642 bool large)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001643{
1644 struct nlattr *nl_wowlan;
1645
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001646 if (!rdev->wiphy.wowlan)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001647 return 0;
1648
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001649 nl_wowlan = nla_nest_start_noflag(msg,
1650 NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001651 if (!nl_wowlan)
1652 return -ENOBUFS;
1653
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001654 if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001655 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001656 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001657 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001658 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001659 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001660 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001661 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001662 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001663 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001664 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001665 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001666 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001667 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001668 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001669 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
1670 return -ENOBUFS;
1671
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001672 if (rdev->wiphy.wowlan->n_patterns) {
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07001673 struct nl80211_pattern_support pat = {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001674 .max_patterns = rdev->wiphy.wowlan->n_patterns,
1675 .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
1676 .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
1677 .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001678 };
1679
1680 if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
1681 sizeof(pat), &pat))
1682 return -ENOBUFS;
1683 }
1684
Luciano Coelho75453cc2015-01-09 14:06:37 +02001685 if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
1686 nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
1687 rdev->wiphy.wowlan->max_nd_match_sets))
1688 return -ENOBUFS;
1689
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001690 if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
Johannes Bergb56cf722013-02-20 01:02:38 +01001691 return -ENOBUFS;
1692
Johannes Berg3713b4e2013-02-14 16:19:38 +01001693 nla_nest_end(msg, nl_wowlan);
1694
1695 return 0;
1696}
1697#endif
1698
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001699static int nl80211_send_coalesce(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001700 struct cfg80211_registered_device *rdev)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001701{
1702 struct nl80211_coalesce_rule_support rule;
1703
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001704 if (!rdev->wiphy.coalesce)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001705 return 0;
1706
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001707 rule.max_rules = rdev->wiphy.coalesce->n_rules;
1708 rule.max_delay = rdev->wiphy.coalesce->max_delay;
1709 rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
1710 rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
1711 rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
1712 rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001713
1714 if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
1715 return -ENOBUFS;
1716
1717 return 0;
1718}
1719
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001720static int
1721nl80211_send_iftype_data(struct sk_buff *msg,
Johannes Berg22395212020-05-28 21:34:31 +02001722 const struct ieee80211_supported_band *sband,
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001723 const struct ieee80211_sband_iftype_data *iftdata)
1724{
1725 const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap;
1726
1727 if (nl80211_put_iftypes(msg, NL80211_BAND_IFTYPE_ATTR_IFTYPES,
1728 iftdata->types_mask))
1729 return -ENOBUFS;
1730
1731 if (he_cap->has_he) {
1732 if (nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
1733 sizeof(he_cap->he_cap_elem.mac_cap_info),
1734 he_cap->he_cap_elem.mac_cap_info) ||
1735 nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
1736 sizeof(he_cap->he_cap_elem.phy_cap_info),
1737 he_cap->he_cap_elem.phy_cap_info) ||
1738 nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
1739 sizeof(he_cap->he_mcs_nss_supp),
1740 &he_cap->he_mcs_nss_supp) ||
1741 nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
1742 sizeof(he_cap->ppe_thres), he_cap->ppe_thres))
1743 return -ENOBUFS;
1744 }
1745
Johannes Berg22395212020-05-28 21:34:31 +02001746 if (sband->band == NL80211_BAND_6GHZ &&
1747 nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
1748 sizeof(iftdata->he_6ghz_capa),
1749 &iftdata->he_6ghz_capa))
1750 return -ENOBUFS;
1751
Johannes Bergf4f86502021-06-18 13:41:52 +03001752 if (iftdata->vendor_elems.data && iftdata->vendor_elems.len &&
1753 nla_put(msg, NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS,
1754 iftdata->vendor_elems.len, iftdata->vendor_elems.data))
1755 return -ENOBUFS;
1756
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001757 return 0;
1758}
1759
Johannes Berg3713b4e2013-02-14 16:19:38 +01001760static int nl80211_send_band_rateinfo(struct sk_buff *msg,
Johannes Bergf8d504c2020-09-28 13:06:56 +02001761 struct ieee80211_supported_band *sband,
1762 bool large)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001763{
1764 struct nlattr *nl_rates, *nl_rate;
1765 struct ieee80211_rate *rate;
1766 int i;
1767
1768 /* add HT info */
1769 if (sband->ht_cap.ht_supported &&
1770 (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
1771 sizeof(sband->ht_cap.mcs),
1772 &sband->ht_cap.mcs) ||
1773 nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
1774 sband->ht_cap.cap) ||
1775 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
1776 sband->ht_cap.ampdu_factor) ||
1777 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
1778 sband->ht_cap.ampdu_density)))
1779 return -ENOBUFS;
1780
1781 /* add VHT info */
1782 if (sband->vht_cap.vht_supported &&
1783 (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
1784 sizeof(sband->vht_cap.vht_mcs),
1785 &sband->vht_cap.vht_mcs) ||
1786 nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
1787 sband->vht_cap.cap)))
1788 return -ENOBUFS;
1789
Johannes Bergf8d504c2020-09-28 13:06:56 +02001790 if (large && sband->n_iftype_data) {
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001791 struct nlattr *nl_iftype_data =
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001792 nla_nest_start_noflag(msg,
1793 NL80211_BAND_ATTR_IFTYPE_DATA);
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001794 int err;
1795
1796 if (!nl_iftype_data)
1797 return -ENOBUFS;
1798
1799 for (i = 0; i < sband->n_iftype_data; i++) {
1800 struct nlattr *iftdata;
1801
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001802 iftdata = nla_nest_start_noflag(msg, i + 1);
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001803 if (!iftdata)
1804 return -ENOBUFS;
1805
Johannes Berg22395212020-05-28 21:34:31 +02001806 err = nl80211_send_iftype_data(msg, sband,
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03001807 &sband->iftype_data[i]);
1808 if (err)
1809 return err;
1810
1811 nla_nest_end(msg, iftdata);
1812 }
1813
1814 nla_nest_end(msg, nl_iftype_data);
1815 }
1816
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +03001817 /* add EDMG info */
Johannes Bergf8d504c2020-09-28 13:06:56 +02001818 if (large && sband->edmg_cap.channels &&
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +03001819 (nla_put_u8(msg, NL80211_BAND_ATTR_EDMG_CHANNELS,
1820 sband->edmg_cap.channels) ||
1821 nla_put_u8(msg, NL80211_BAND_ATTR_EDMG_BW_CONFIG,
1822 sband->edmg_cap.bw_config)))
1823
1824 return -ENOBUFS;
1825
Johannes Berg3713b4e2013-02-14 16:19:38 +01001826 /* add bitrates */
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001827 nl_rates = nla_nest_start_noflag(msg, NL80211_BAND_ATTR_RATES);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001828 if (!nl_rates)
1829 return -ENOBUFS;
1830
1831 for (i = 0; i < sband->n_bitrates; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001832 nl_rate = nla_nest_start_noflag(msg, i);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001833 if (!nl_rate)
1834 return -ENOBUFS;
1835
1836 rate = &sband->bitrates[i];
1837 if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
1838 rate->bitrate))
1839 return -ENOBUFS;
1840 if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
1841 nla_put_flag(msg,
1842 NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
1843 return -ENOBUFS;
1844
1845 nla_nest_end(msg, nl_rate);
1846 }
1847
1848 nla_nest_end(msg, nl_rates);
1849
1850 return 0;
1851}
1852
1853static int
1854nl80211_send_mgmt_stypes(struct sk_buff *msg,
1855 const struct ieee80211_txrx_stypes *mgmt_stypes)
1856{
1857 u16 stypes;
1858 struct nlattr *nl_ftypes, *nl_ifs;
1859 enum nl80211_iftype ift;
1860 int i;
1861
1862 if (!mgmt_stypes)
1863 return 0;
1864
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001865 nl_ifs = nla_nest_start_noflag(msg, NL80211_ATTR_TX_FRAME_TYPES);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001866 if (!nl_ifs)
1867 return -ENOBUFS;
1868
1869 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001870 nl_ftypes = nla_nest_start_noflag(msg, ift);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001871 if (!nl_ftypes)
1872 return -ENOBUFS;
1873 i = 0;
1874 stypes = mgmt_stypes[ift].tx;
1875 while (stypes) {
1876 if ((stypes & 1) &&
1877 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1878 (i << 4) | IEEE80211_FTYPE_MGMT))
1879 return -ENOBUFS;
1880 stypes >>= 1;
1881 i++;
1882 }
1883 nla_nest_end(msg, nl_ftypes);
1884 }
1885
1886 nla_nest_end(msg, nl_ifs);
1887
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001888 nl_ifs = nla_nest_start_noflag(msg, NL80211_ATTR_RX_FRAME_TYPES);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001889 if (!nl_ifs)
1890 return -ENOBUFS;
1891
1892 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001893 nl_ftypes = nla_nest_start_noflag(msg, ift);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001894 if (!nl_ftypes)
1895 return -ENOBUFS;
1896 i = 0;
1897 stypes = mgmt_stypes[ift].rx;
1898 while (stypes) {
1899 if ((stypes & 1) &&
1900 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1901 (i << 4) | IEEE80211_FTYPE_MGMT))
1902 return -ENOBUFS;
1903 stypes >>= 1;
1904 i++;
1905 }
1906 nla_nest_end(msg, nl_ftypes);
1907 }
1908 nla_nest_end(msg, nl_ifs);
1909
1910 return 0;
1911}
1912
Johannes Berg17948992016-10-26 11:42:04 +02001913#define CMD(op, n) \
1914 do { \
1915 if (rdev->ops->op) { \
1916 i++; \
1917 if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
1918 goto nla_put_failure; \
1919 } \
1920 } while (0)
1921
1922static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
1923 struct sk_buff *msg)
1924{
1925 int i = 0;
1926
1927 /*
1928 * do *NOT* add anything into this function, new things need to be
1929 * advertised only to new versions of userspace that can deal with
1930 * the split (and they can't possibly care about new features...
1931 */
1932 CMD(add_virtual_intf, NEW_INTERFACE);
1933 CMD(change_virtual_intf, SET_INTERFACE);
1934 CMD(add_key, NEW_KEY);
1935 CMD(start_ap, START_AP);
1936 CMD(add_station, NEW_STATION);
1937 CMD(add_mpath, NEW_MPATH);
1938 CMD(update_mesh_config, SET_MESH_CONFIG);
1939 CMD(change_bss, SET_BSS);
1940 CMD(auth, AUTHENTICATE);
1941 CMD(assoc, ASSOCIATE);
1942 CMD(deauth, DEAUTHENTICATE);
1943 CMD(disassoc, DISASSOCIATE);
1944 CMD(join_ibss, JOIN_IBSS);
1945 CMD(join_mesh, JOIN_MESH);
1946 CMD(set_pmksa, SET_PMKSA);
1947 CMD(del_pmksa, DEL_PMKSA);
1948 CMD(flush_pmksa, FLUSH_PMKSA);
1949 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
1950 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
1951 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
1952 CMD(mgmt_tx, FRAME);
1953 CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
1954 if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
1955 i++;
1956 if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
1957 goto nla_put_failure;
1958 }
1959 if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
1960 rdev->ops->join_mesh) {
1961 i++;
1962 if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
1963 goto nla_put_failure;
1964 }
Johannes Berg17948992016-10-26 11:42:04 +02001965 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
1966 CMD(tdls_mgmt, TDLS_MGMT);
1967 CMD(tdls_oper, TDLS_OPER);
1968 }
Arend Van Sprielca986ad2017-04-21 13:05:00 +01001969 if (rdev->wiphy.max_sched_scan_reqs)
Johannes Berg17948992016-10-26 11:42:04 +02001970 CMD(sched_scan_start, START_SCHED_SCAN);
1971 CMD(probe_client, PROBE_CLIENT);
1972 CMD(set_noack_map, SET_NOACK_MAP);
1973 if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
1974 i++;
1975 if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1976 goto nla_put_failure;
1977 }
1978 CMD(start_p2p_device, START_P2P_DEVICE);
1979 CMD(set_mcast_rate, SET_MCAST_RATE);
1980#ifdef CONFIG_NL80211_TESTMODE
1981 CMD(testmode_cmd, TESTMODE);
1982#endif
1983
1984 if (rdev->ops->connect || rdev->ops->auth) {
1985 i++;
1986 if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
1987 goto nla_put_failure;
1988 }
1989
1990 if (rdev->ops->disconnect || rdev->ops->deauth) {
1991 i++;
1992 if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
1993 goto nla_put_failure;
1994 }
1995
1996 return i;
1997 nla_put_failure:
1998 return -ENOBUFS;
1999}
2000
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02002001static int
2002nl80211_send_pmsr_ftm_capa(const struct cfg80211_pmsr_capabilities *cap,
2003 struct sk_buff *msg)
2004{
2005 struct nlattr *ftm;
2006
2007 if (!cap->ftm.supported)
2008 return 0;
2009
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002010 ftm = nla_nest_start_noflag(msg, NL80211_PMSR_TYPE_FTM);
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02002011 if (!ftm)
2012 return -ENOBUFS;
2013
2014 if (cap->ftm.asap && nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_ASAP))
2015 return -ENOBUFS;
2016 if (cap->ftm.non_asap &&
2017 nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP))
2018 return -ENOBUFS;
2019 if (cap->ftm.request_lci &&
2020 nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI))
2021 return -ENOBUFS;
2022 if (cap->ftm.request_civicloc &&
2023 nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC))
2024 return -ENOBUFS;
2025 if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES,
2026 cap->ftm.preambles))
2027 return -ENOBUFS;
2028 if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
2029 cap->ftm.bandwidths))
2030 return -ENOBUFS;
2031 if (cap->ftm.max_bursts_exponent >= 0 &&
2032 nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
2033 cap->ftm.max_bursts_exponent))
2034 return -ENOBUFS;
2035 if (cap->ftm.max_ftms_per_burst &&
2036 nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
2037 cap->ftm.max_ftms_per_burst))
2038 return -ENOBUFS;
Avraham Sternefb55202020-01-31 13:12:38 +02002039 if (cap->ftm.trigger_based &&
2040 nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED))
2041 return -ENOBUFS;
2042 if (cap->ftm.non_trigger_based &&
2043 nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED))
2044 return -ENOBUFS;
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02002045
2046 nla_nest_end(msg, ftm);
2047 return 0;
2048}
2049
2050static int nl80211_send_pmsr_capa(struct cfg80211_registered_device *rdev,
2051 struct sk_buff *msg)
2052{
2053 const struct cfg80211_pmsr_capabilities *cap = rdev->wiphy.pmsr_capa;
2054 struct nlattr *pmsr, *caps;
2055
2056 if (!cap)
2057 return 0;
2058
2059 /*
2060 * we don't need to clean up anything here since the caller
2061 * will genlmsg_cancel() if we fail
2062 */
2063
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002064 pmsr = nla_nest_start_noflag(msg, NL80211_ATTR_PEER_MEASUREMENTS);
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02002065 if (!pmsr)
2066 return -ENOBUFS;
2067
2068 if (nla_put_u32(msg, NL80211_PMSR_ATTR_MAX_PEERS, cap->max_peers))
2069 return -ENOBUFS;
2070
2071 if (cap->report_ap_tsf &&
2072 nla_put_flag(msg, NL80211_PMSR_ATTR_REPORT_AP_TSF))
2073 return -ENOBUFS;
2074
2075 if (cap->randomize_mac_addr &&
2076 nla_put_flag(msg, NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR))
2077 return -ENOBUFS;
2078
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002079 caps = nla_nest_start_noflag(msg, NL80211_PMSR_ATTR_TYPE_CAPA);
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02002080 if (!caps)
2081 return -ENOBUFS;
2082
2083 if (nl80211_send_pmsr_ftm_capa(cap, msg))
2084 return -ENOBUFS;
2085
2086 nla_nest_end(msg, caps);
2087 nla_nest_end(msg, pmsr);
2088
2089 return 0;
2090}
2091
Veerendranath Jakkamd6039a32020-01-27 02:00:32 +05302092static int
2093nl80211_put_iftype_akm_suites(struct cfg80211_registered_device *rdev,
2094 struct sk_buff *msg)
2095{
2096 int i;
2097 struct nlattr *nested, *nested_akms;
2098 const struct wiphy_iftype_akm_suites *iftype_akms;
2099
2100 if (!rdev->wiphy.num_iftype_akm_suites ||
2101 !rdev->wiphy.iftype_akm_suites)
2102 return 0;
2103
2104 nested = nla_nest_start(msg, NL80211_ATTR_IFTYPE_AKM_SUITES);
2105 if (!nested)
2106 return -ENOBUFS;
2107
2108 for (i = 0; i < rdev->wiphy.num_iftype_akm_suites; i++) {
2109 nested_akms = nla_nest_start(msg, i + 1);
2110 if (!nested_akms)
2111 return -ENOBUFS;
2112
2113 iftype_akms = &rdev->wiphy.iftype_akm_suites[i];
2114
2115 if (nl80211_put_iftypes(msg, NL80211_IFTYPE_AKM_ATTR_IFTYPES,
2116 iftype_akms->iftypes_mask))
2117 return -ENOBUFS;
2118
2119 if (nla_put(msg, NL80211_IFTYPE_AKM_ATTR_SUITES,
2120 sizeof(u32) * iftype_akms->n_akm_suites,
2121 iftype_akms->akm_suites)) {
2122 return -ENOBUFS;
2123 }
2124 nla_nest_end(msg, nested_akms);
2125 }
2126
2127 nla_nest_end(msg, nested);
2128
2129 return 0;
2130}
2131
Johannes Berg3710a8a2020-02-24 11:34:25 +01002132static int
2133nl80211_put_tid_config_support(struct cfg80211_registered_device *rdev,
2134 struct sk_buff *msg)
2135{
2136 struct nlattr *supp;
2137
2138 if (!rdev->wiphy.tid_config_support.vif &&
2139 !rdev->wiphy.tid_config_support.peer)
2140 return 0;
2141
2142 supp = nla_nest_start(msg, NL80211_ATTR_TID_CONFIG);
2143 if (!supp)
2144 return -ENOSPC;
2145
2146 if (rdev->wiphy.tid_config_support.vif &&
2147 nla_put_u64_64bit(msg, NL80211_TID_CONFIG_ATTR_VIF_SUPP,
2148 rdev->wiphy.tid_config_support.vif,
2149 NL80211_TID_CONFIG_ATTR_PAD))
2150 goto fail;
2151
2152 if (rdev->wiphy.tid_config_support.peer &&
2153 nla_put_u64_64bit(msg, NL80211_TID_CONFIG_ATTR_PEER_SUPP,
2154 rdev->wiphy.tid_config_support.peer,
2155 NL80211_TID_CONFIG_ATTR_PAD))
2156 goto fail;
2157
Tamizh chelvam6a21d162020-01-20 13:21:23 +05302158 /* for now we just use the same value ... makes more sense */
2159 if (nla_put_u8(msg, NL80211_TID_CONFIG_ATTR_RETRY_SHORT,
2160 rdev->wiphy.tid_config_support.max_retry))
2161 goto fail;
2162 if (nla_put_u8(msg, NL80211_TID_CONFIG_ATTR_RETRY_LONG,
2163 rdev->wiphy.tid_config_support.max_retry))
2164 goto fail;
2165
Johannes Berg3710a8a2020-02-24 11:34:25 +01002166 nla_nest_end(msg, supp);
2167
2168 return 0;
2169fail:
2170 nla_nest_cancel(msg, supp);
2171 return -ENOBUFS;
2172}
2173
Carl Huang6bdb68c2020-12-03 05:37:26 -05002174static int
2175nl80211_put_sar_specs(struct cfg80211_registered_device *rdev,
2176 struct sk_buff *msg)
2177{
2178 struct nlattr *sar_capa, *specs, *sub_freq_range;
2179 u8 num_freq_ranges;
2180 int i;
2181
2182 if (!rdev->wiphy.sar_capa)
2183 return 0;
2184
2185 num_freq_ranges = rdev->wiphy.sar_capa->num_freq_ranges;
2186
2187 sar_capa = nla_nest_start(msg, NL80211_ATTR_SAR_SPEC);
2188 if (!sar_capa)
2189 return -ENOSPC;
2190
2191 if (nla_put_u32(msg, NL80211_SAR_ATTR_TYPE, rdev->wiphy.sar_capa->type))
2192 goto fail;
2193
2194 specs = nla_nest_start(msg, NL80211_SAR_ATTR_SPECS);
2195 if (!specs)
2196 goto fail;
2197
2198 /* report supported freq_ranges */
2199 for (i = 0; i < num_freq_ranges; i++) {
2200 sub_freq_range = nla_nest_start(msg, i + 1);
2201 if (!sub_freq_range)
2202 goto fail;
2203
2204 if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_START_FREQ,
2205 rdev->wiphy.sar_capa->freq_ranges[i].start_freq))
2206 goto fail;
2207
2208 if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_END_FREQ,
2209 rdev->wiphy.sar_capa->freq_ranges[i].end_freq))
2210 goto fail;
2211
2212 nla_nest_end(msg, sub_freq_range);
2213 }
2214
2215 nla_nest_end(msg, specs);
2216 nla_nest_end(msg, sar_capa);
2217
2218 return 0;
2219fail:
2220 nla_nest_cancel(msg, sar_capa);
2221 return -ENOBUFS;
2222}
2223
John Crispindc1e3cb2021-09-15 19:54:34 -07002224static int nl80211_put_mbssid_support(struct wiphy *wiphy, struct sk_buff *msg)
2225{
2226 struct nlattr *config;
2227
2228 if (!wiphy->mbssid_max_interfaces)
2229 return 0;
2230
2231 config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG);
2232 if (!config)
2233 return -ENOBUFS;
2234
2235 if (nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES,
2236 wiphy->mbssid_max_interfaces))
2237 goto fail;
2238
2239 if (wiphy->ema_max_profile_periodicity &&
2240 nla_put_u8(msg,
2241 NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY,
2242 wiphy->ema_max_profile_periodicity))
2243 goto fail;
2244
2245 nla_nest_end(msg, config);
2246 return 0;
2247
2248fail:
2249 nla_nest_cancel(msg, config);
2250 return -ENOBUFS;
2251}
2252
Johannes Berg86e8cf92013-06-19 10:57:22 +02002253struct nl80211_dump_wiphy_state {
2254 s64 filter_wiphy;
2255 long start;
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05302256 long split_start, band_start, chan_start, capa_start;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002257 bool split;
2258};
2259
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002260static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
Johannes Berg3bb20552014-05-26 13:52:25 +02002261 enum nl80211_commands cmd,
Johannes Berg3713b4e2013-02-14 16:19:38 +01002262 struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002263 int flags, struct nl80211_dump_wiphy_state *state)
Johannes Berg55682962007-09-20 13:09:35 -04002264{
2265 void *hdr;
Johannes Bergee688b002008-01-24 19:38:39 +01002266 struct nlattr *nl_bands, *nl_band;
2267 struct nlattr *nl_freqs, *nl_freq;
Johannes Berg8fdc6212009-03-14 09:34:01 +01002268 struct nlattr *nl_cmds;
Johannes Berg57fbcce2016-04-12 15:56:15 +02002269 enum nl80211_band band;
Johannes Bergee688b002008-01-24 19:38:39 +01002270 struct ieee80211_channel *chan;
Johannes Bergee688b002008-01-24 19:38:39 +01002271 int i;
Johannes Berg2e161f782010-08-12 15:38:38 +02002272 const struct ieee80211_txrx_stypes *mgmt_stypes =
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002273 rdev->wiphy.mgmt_stypes;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002274 u32 features;
Johannes Berg55682962007-09-20 13:09:35 -04002275
Johannes Berg3bb20552014-05-26 13:52:25 +02002276 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04002277 if (!hdr)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002278 return -ENOBUFS;
2279
Johannes Berg86e8cf92013-06-19 10:57:22 +02002280 if (WARN_ON(!state))
2281 return -EINVAL;
Johannes Berg55682962007-09-20 13:09:35 -04002282
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002283 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002284 nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002285 wiphy_name(&rdev->wiphy)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04002286 nla_put_u32(msg, NL80211_ATTR_GENERATION,
Johannes Berg3713b4e2013-02-14 16:19:38 +01002287 cfg80211_rdev_list_generation))
David S. Miller9360ffd2012-03-29 04:41:26 -04002288 goto nla_put_failure;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002289
Johannes Berg3bb20552014-05-26 13:52:25 +02002290 if (cmd != NL80211_CMD_NEW_WIPHY)
2291 goto finish;
2292
Johannes Berg86e8cf92013-06-19 10:57:22 +02002293 switch (state->split_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01002294 case 0:
2295 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002296 rdev->wiphy.retry_short) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002297 nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002298 rdev->wiphy.retry_long) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002299 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002300 rdev->wiphy.frag_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002301 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002302 rdev->wiphy.rts_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002303 nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002304 rdev->wiphy.coverage_class) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002305 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002306 rdev->wiphy.max_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002307 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002308 rdev->wiphy.max_sched_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002309 nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002310 rdev->wiphy.max_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002311 nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002312 rdev->wiphy.max_sched_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002313 nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
Johannes Bergf8d504c2020-09-28 13:06:56 +02002314 rdev->wiphy.max_match_sets))
Johannes Bergee688b002008-01-24 19:38:39 +01002315 goto nla_put_failure;
2316
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002317 if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002318 nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
2319 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002320 if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002321 nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
2322 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002323 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002324 nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
2325 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002326 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002327 nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
2328 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002329 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002330 nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
2331 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002332 if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002333 nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
David S. Miller9360ffd2012-03-29 04:41:26 -04002334 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002335 state->split_start++;
2336 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002337 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002338 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002339 case 1:
2340 if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002341 sizeof(u32) * rdev->wiphy.n_cipher_suites,
2342 rdev->wiphy.cipher_suites))
Mahesh Palivelabf0c111e2012-06-22 07:27:46 +00002343 goto nla_put_failure;
2344
Johannes Berg3713b4e2013-02-14 16:19:38 +01002345 if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002346 rdev->wiphy.max_num_pmkids))
Johannes Bergee688b002008-01-24 19:38:39 +01002347 goto nla_put_failure;
2348
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002349 if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002350 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
2351 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01002352
Johannes Berg3713b4e2013-02-14 16:19:38 +01002353 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002354 rdev->wiphy.available_antennas_tx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01002355 nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002356 rdev->wiphy.available_antennas_rx))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002357 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01002358
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002359 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002360 nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002361 rdev->wiphy.probe_resp_offload))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002362 goto nla_put_failure;
Jouni Malinene2f367f262008-11-21 19:01:30 +02002363
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002364 if ((rdev->wiphy.available_antennas_tx ||
2365 rdev->wiphy.available_antennas_rx) &&
2366 rdev->ops->get_antenna) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01002367 u32 tx_ant = 0, rx_ant = 0;
2368 int res;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07002369
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002370 res = rdev_get_antenna(rdev, &tx_ant, &rx_ant);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002371 if (!res) {
2372 if (nla_put_u32(msg,
2373 NL80211_ATTR_WIPHY_ANTENNA_TX,
2374 tx_ant) ||
2375 nla_put_u32(msg,
2376 NL80211_ATTR_WIPHY_ANTENNA_RX,
2377 rx_ant))
2378 goto nla_put_failure;
2379 }
Johannes Bergee688b002008-01-24 19:38:39 +01002380 }
2381
Johannes Berg86e8cf92013-06-19 10:57:22 +02002382 state->split_start++;
2383 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002384 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002385 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002386 case 2:
2387 if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002388 rdev->wiphy.interface_modes))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002389 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002390 state->split_start++;
2391 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002392 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002393 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002394 case 3:
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002395 nl_bands = nla_nest_start_noflag(msg,
2396 NL80211_ATTR_WIPHY_BANDS);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002397 if (!nl_bands)
Johannes Bergee688b002008-01-24 19:38:39 +01002398 goto nla_put_failure;
2399
Johannes Berg86e8cf92013-06-19 10:57:22 +02002400 for (band = state->band_start;
Johannes Berg0d059962021-07-12 21:53:30 +02002401 band < (state->split ?
2402 NUM_NL80211_BANDS :
2403 NL80211_BAND_60GHZ + 1);
2404 band++) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01002405 struct ieee80211_supported_band *sband;
2406
Johannes Bergf8d504c2020-09-28 13:06:56 +02002407 /* omit higher bands for ancient software */
2408 if (band > NL80211_BAND_5GHZ && !state->split)
2409 break;
2410
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002411 sband = rdev->wiphy.bands[band];
Johannes Berg3713b4e2013-02-14 16:19:38 +01002412
2413 if (!sband)
2414 continue;
2415
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002416 nl_band = nla_nest_start_noflag(msg, band);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002417 if (!nl_band)
Johannes Bergee688b002008-01-24 19:38:39 +01002418 goto nla_put_failure;
2419
Johannes Berg86e8cf92013-06-19 10:57:22 +02002420 switch (state->chan_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01002421 case 0:
Johannes Bergf8d504c2020-09-28 13:06:56 +02002422 if (nl80211_send_band_rateinfo(msg, sband,
2423 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002424 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002425 state->chan_start++;
2426 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002427 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002428 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002429 default:
2430 /* add frequencies */
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002431 nl_freqs = nla_nest_start_noflag(msg,
2432 NL80211_BAND_ATTR_FREQS);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002433 if (!nl_freqs)
2434 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01002435
Johannes Berg86e8cf92013-06-19 10:57:22 +02002436 for (i = state->chan_start - 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002437 i < sband->n_channels;
2438 i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002439 nl_freq = nla_nest_start_noflag(msg,
2440 i);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002441 if (!nl_freq)
2442 goto nla_put_failure;
2443
2444 chan = &sband->channels[i];
2445
Johannes Berg86e8cf92013-06-19 10:57:22 +02002446 if (nl80211_msg_put_channel(
Haim Dreyfuss50f32712018-04-20 13:49:26 +03002447 msg, &rdev->wiphy, chan,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002448 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002449 goto nla_put_failure;
2450
2451 nla_nest_end(msg, nl_freq);
Johannes Berg86e8cf92013-06-19 10:57:22 +02002452 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002453 break;
2454 }
2455 if (i < sband->n_channels)
Johannes Berg86e8cf92013-06-19 10:57:22 +02002456 state->chan_start = i + 2;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002457 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02002458 state->chan_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002459 nla_nest_end(msg, nl_freqs);
2460 }
2461
2462 nla_nest_end(msg, nl_band);
2463
Johannes Berg86e8cf92013-06-19 10:57:22 +02002464 if (state->split) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01002465 /* start again here */
Johannes Berg86e8cf92013-06-19 10:57:22 +02002466 if (state->chan_start)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002467 band--;
2468 break;
2469 }
Johannes Bergee688b002008-01-24 19:38:39 +01002470 }
Johannes Berg3713b4e2013-02-14 16:19:38 +01002471 nla_nest_end(msg, nl_bands);
Johannes Bergee688b002008-01-24 19:38:39 +01002472
Johannes Berg57fbcce2016-04-12 15:56:15 +02002473 if (band < NUM_NL80211_BANDS)
Johannes Berg86e8cf92013-06-19 10:57:22 +02002474 state->band_start = band + 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002475 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02002476 state->band_start = 0;
Johannes Bergee688b002008-01-24 19:38:39 +01002477
Johannes Berg3713b4e2013-02-14 16:19:38 +01002478 /* if bands & channels are done, continue outside */
Johannes Berg86e8cf92013-06-19 10:57:22 +02002479 if (state->band_start == 0 && state->chan_start == 0)
2480 state->split_start++;
2481 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002482 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002483 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002484 case 4:
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002485 nl_cmds = nla_nest_start_noflag(msg,
2486 NL80211_ATTR_SUPPORTED_COMMANDS);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002487 if (!nl_cmds)
David S. Miller9360ffd2012-03-29 04:41:26 -04002488 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002489
Johannes Berg17948992016-10-26 11:42:04 +02002490 i = nl80211_add_commands_unsplit(rdev, msg);
2491 if (i < 0)
2492 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002493 if (state->split) {
Arend van Spriel5de17982013-04-18 15:49:00 +02002494 CMD(crit_proto_start, CRIT_PROTOCOL_START);
2495 CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002496 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02002497 CMD(channel_switch, CHANNEL_SWITCH);
Johannes Berg02df00e2014-06-10 14:06:25 +02002498 CMD(set_qos_map, SET_QOS_MAP);
Johannes Berg723e73a2014-10-22 09:25:06 +02002499 if (rdev->wiphy.features &
2500 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
Johannes Berg960d01a2014-09-09 22:55:35 +03002501 CMD(add_tx_ts, ADD_TX_TS);
Michael Braunce0ce132016-10-10 19:12:22 +02002502 CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
vamsi krishna088e8df2016-10-27 16:51:11 +03002503 CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
Matthew Wang70109982019-08-22 10:48:06 -07002504 CMD(update_ft_ies, UPDATE_FT_IES);
Carl Huang6bdb68c2020-12-03 05:37:26 -05002505 if (rdev->wiphy.sar_capa)
2506 CMD(set_sar_specs, SET_SAR_SPECS);
Arend van Spriel5de17982013-04-18 15:49:00 +02002507 }
Johannes Berg8fdc6212009-03-14 09:34:01 +01002508#undef CMD
Samuel Ortizb23aa672009-07-01 21:26:54 +02002509
Johannes Berg3713b4e2013-02-14 16:19:38 +01002510 nla_nest_end(msg, nl_cmds);
Johannes Berg86e8cf92013-06-19 10:57:22 +02002511 state->split_start++;
2512 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002513 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002514 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002515 case 5:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002516 if (rdev->ops->remain_on_channel &&
2517 (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002518 nla_put_u32(msg,
2519 NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002520 rdev->wiphy.max_remain_on_channel_duration))
Johannes Berg2e161f782010-08-12 15:38:38 +02002521 goto nla_put_failure;
2522
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002523 if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002524 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
2525 goto nla_put_failure;
Johannes Berg2e161f782010-08-12 15:38:38 +02002526
Johannes Berg86e8cf92013-06-19 10:57:22 +02002527 state->split_start++;
2528 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002529 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002530 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002531 case 6:
Johannes Bergdfb89c52012-06-27 09:23:48 +02002532#ifdef CONFIG_PM
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002533 if (nl80211_send_wowlan(msg, rdev, state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002534 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002535 state->split_start++;
2536 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002537 break;
2538#else
Johannes Berg86e8cf92013-06-19 10:57:22 +02002539 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002540#endif
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002541 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002542 case 7:
2543 if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002544 rdev->wiphy.software_iftypes))
Johannes Bergff1b6e62011-05-04 15:37:28 +02002545 goto nla_put_failure;
2546
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002547 if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002548 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002549 goto nla_put_failure;
Johannes Bergff1b6e62011-05-04 15:37:28 +02002550
Johannes Berg86e8cf92013-06-19 10:57:22 +02002551 state->split_start++;
2552 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002553 break;
Miaohe Lin7b506ff2020-08-22 04:23:23 -04002554 fallthrough;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002555 case 8:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002556 if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002557 nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002558 rdev->wiphy.ap_sme_capa))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002559 goto nla_put_failure;
2560
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002561 features = rdev->wiphy.features;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002562 /*
2563 * We can only add the per-channel limit information if the
2564 * dump is split, otherwise it makes it too big. Therefore
2565 * only advertise it in that case.
2566 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02002567 if (state->split)
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002568 features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
2569 if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002570 goto nla_put_failure;
2571
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002572 if (rdev->wiphy.ht_capa_mod_mask &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002573 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002574 sizeof(*rdev->wiphy.ht_capa_mod_mask),
2575 rdev->wiphy.ht_capa_mod_mask))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002576 goto nla_put_failure;
2577
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002578 if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
2579 rdev->wiphy.max_acl_mac_addrs &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002580 nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002581 rdev->wiphy.max_acl_mac_addrs))
Johannes Berg3713b4e2013-02-14 16:19:38 +01002582 goto nla_put_failure;
2583
2584 /*
2585 * Any information below this point is only available to
2586 * applications that can deal with it being split. This
2587 * helps ensure that newly added capabilities don't break
2588 * older tools by overrunning their buffers.
2589 *
2590 * We still increment split_start so that in the split
2591 * case we'll continue with more data in the next round,
2592 * but break unconditionally so unsplit data stops here.
2593 */
Johannes Bergab10c222020-09-28 13:07:18 +02002594 if (state->split)
2595 state->split_start++;
2596 else
2597 state->split_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002598 break;
2599 case 9:
Johannes Bergf8d504c2020-09-28 13:06:56 +02002600 if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
2601 goto nla_put_failure;
2602
2603 if (nla_put_u32(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
2604 rdev->wiphy.max_sched_scan_plans) ||
2605 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
2606 rdev->wiphy.max_sched_scan_plan_interval) ||
2607 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
2608 rdev->wiphy.max_sched_scan_plan_iterations))
2609 goto nla_put_failure;
2610
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002611 if (rdev->wiphy.extended_capabilities &&
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002612 (nla_put(msg, NL80211_ATTR_EXT_CAPA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002613 rdev->wiphy.extended_capabilities_len,
2614 rdev->wiphy.extended_capabilities) ||
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002615 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002616 rdev->wiphy.extended_capabilities_len,
2617 rdev->wiphy.extended_capabilities_mask)))
Johannes Bergfe1abaf2013-02-27 15:39:45 +01002618 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002619
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002620 if (rdev->wiphy.vht_capa_mod_mask &&
Johannes Bergee2aca32013-02-21 17:36:01 +01002621 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002622 sizeof(*rdev->wiphy.vht_capa_mod_mask),
2623 rdev->wiphy.vht_capa_mod_mask))
Johannes Bergee2aca32013-02-21 17:36:01 +01002624 goto nla_put_failure;
2625
Denis Kenziorae6fa4d2019-07-22 06:33:12 -05002626 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
2627 rdev->wiphy.perm_addr))
2628 goto nla_put_failure;
2629
2630 if (!is_zero_ether_addr(rdev->wiphy.addr_mask) &&
2631 nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
2632 rdev->wiphy.addr_mask))
2633 goto nla_put_failure;
2634
2635 if (rdev->wiphy.n_addresses > 1) {
2636 void *attr;
2637
2638 attr = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
2639 if (!attr)
2640 goto nla_put_failure;
2641
2642 for (i = 0; i < rdev->wiphy.n_addresses; i++)
2643 if (nla_put(msg, i + 1, ETH_ALEN,
2644 rdev->wiphy.addresses[i].addr))
2645 goto nla_put_failure;
2646
2647 nla_nest_end(msg, attr);
2648 }
2649
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07002650 state->split_start++;
2651 break;
2652 case 10:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002653 if (nl80211_send_coalesce(msg, rdev))
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07002654 goto nla_put_failure;
2655
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002656 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
Felix Fietkau01e0daa2013-11-09 14:57:54 +01002657 (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
2658 nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
2659 goto nla_put_failure;
Jouni Malinenb43504c2014-01-15 00:01:08 +02002660
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002661 if (rdev->wiphy.max_ap_assoc_sta &&
Jouni Malinenb43504c2014-01-15 00:01:08 +02002662 nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002663 rdev->wiphy.max_ap_assoc_sta))
Jouni Malinenb43504c2014-01-15 00:01:08 +02002664 goto nla_put_failure;
2665
Johannes Bergad7e7182013-11-13 13:37:47 +01002666 state->split_start++;
2667 break;
2668 case 11:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002669 if (rdev->wiphy.n_vendor_commands) {
Johannes Berg567ffc32013-12-18 14:43:31 +01002670 const struct nl80211_vendor_cmd_info *info;
2671 struct nlattr *nested;
Johannes Bergad7e7182013-11-13 13:37:47 +01002672
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002673 nested = nla_nest_start_noflag(msg,
2674 NL80211_ATTR_VENDOR_DATA);
Johannes Berg567ffc32013-12-18 14:43:31 +01002675 if (!nested)
Johannes Bergad7e7182013-11-13 13:37:47 +01002676 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01002677
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002678 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
2679 info = &rdev->wiphy.vendor_commands[i].info;
Johannes Berg567ffc32013-12-18 14:43:31 +01002680 if (nla_put(msg, i + 1, sizeof(*info), info))
2681 goto nla_put_failure;
2682 }
2683 nla_nest_end(msg, nested);
2684 }
2685
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002686 if (rdev->wiphy.n_vendor_events) {
Johannes Berg567ffc32013-12-18 14:43:31 +01002687 const struct nl80211_vendor_cmd_info *info;
2688 struct nlattr *nested;
2689
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002690 nested = nla_nest_start_noflag(msg,
2691 NL80211_ATTR_VENDOR_EVENTS);
Johannes Berg567ffc32013-12-18 14:43:31 +01002692 if (!nested)
2693 goto nla_put_failure;
2694
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002695 for (i = 0; i < rdev->wiphy.n_vendor_events; i++) {
2696 info = &rdev->wiphy.vendor_events[i];
Johannes Berg567ffc32013-12-18 14:43:31 +01002697 if (nla_put(msg, i + 1, sizeof(*info), info))
2698 goto nla_put_failure;
2699 }
2700 nla_nest_end(msg, nested);
2701 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03002702 state->split_start++;
2703 break;
2704 case 12:
2705 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
2706 nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
2707 rdev->wiphy.max_num_csa_counters))
2708 goto nla_put_failure;
Felix Fietkau01e0daa2013-11-09 14:57:54 +01002709
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02002710 if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
2711 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
2712 goto nla_put_failure;
2713
Arend Van Sprielca986ad2017-04-21 13:05:00 +01002714 if (rdev->wiphy.max_sched_scan_reqs &&
2715 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_MAX_REQS,
2716 rdev->wiphy.max_sched_scan_reqs))
2717 goto nla_put_failure;
2718
Gautam Kumar Shuklad75bb062014-12-23 16:55:19 +01002719 if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
2720 sizeof(rdev->wiphy.ext_features),
2721 rdev->wiphy.ext_features))
2722 goto nla_put_failure;
2723
Arend van Spriel38de03d2016-03-02 20:37:18 +01002724 if (rdev->wiphy.bss_select_support) {
2725 struct nlattr *nested;
2726 u32 bss_select_support = rdev->wiphy.bss_select_support;
2727
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002728 nested = nla_nest_start_noflag(msg,
2729 NL80211_ATTR_BSS_SELECT);
Arend van Spriel38de03d2016-03-02 20:37:18 +01002730 if (!nested)
2731 goto nla_put_failure;
2732
2733 i = 0;
2734 while (bss_select_support) {
2735 if ((bss_select_support & 1) &&
2736 nla_put_flag(msg, i))
2737 goto nla_put_failure;
2738 i++;
2739 bss_select_support >>= 1;
2740 }
2741 nla_nest_end(msg, nested);
2742 }
2743
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05302744 state->split_start++;
2745 break;
2746 case 13:
2747 if (rdev->wiphy.num_iftype_ext_capab &&
2748 rdev->wiphy.iftype_ext_capab) {
2749 struct nlattr *nested_ext_capab, *nested;
2750
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002751 nested = nla_nest_start_noflag(msg,
2752 NL80211_ATTR_IFTYPE_EXT_CAPA);
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05302753 if (!nested)
2754 goto nla_put_failure;
2755
2756 for (i = state->capa_start;
2757 i < rdev->wiphy.num_iftype_ext_capab; i++) {
2758 const struct wiphy_iftype_ext_capab *capab;
2759
2760 capab = &rdev->wiphy.iftype_ext_capab[i];
2761
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002762 nested_ext_capab = nla_nest_start_noflag(msg,
2763 i);
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05302764 if (!nested_ext_capab ||
2765 nla_put_u32(msg, NL80211_ATTR_IFTYPE,
2766 capab->iftype) ||
2767 nla_put(msg, NL80211_ATTR_EXT_CAPA,
2768 capab->extended_capabilities_len,
2769 capab->extended_capabilities) ||
2770 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
2771 capab->extended_capabilities_len,
2772 capab->extended_capabilities_mask))
2773 goto nla_put_failure;
2774
2775 nla_nest_end(msg, nested_ext_capab);
2776 if (state->split)
2777 break;
2778 }
2779 nla_nest_end(msg, nested);
2780 if (i < rdev->wiphy.num_iftype_ext_capab) {
2781 state->capa_start = i + 1;
2782 break;
2783 }
2784 }
2785
Luca Coelho85859892017-02-08 15:00:34 +02002786 if (nla_put_u32(msg, NL80211_ATTR_BANDS,
2787 rdev->wiphy.nan_supported_bands))
2788 goto nla_put_failure;
2789
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02002790 if (wiphy_ext_feature_isset(&rdev->wiphy,
2791 NL80211_EXT_FEATURE_TXQS)) {
2792 struct cfg80211_txq_stats txqstats = {};
2793 int res;
2794
2795 res = rdev_get_txq_stats(rdev, NULL, &txqstats);
2796 if (!res &&
2797 !nl80211_put_txq_stats(msg, &txqstats,
2798 NL80211_ATTR_TXQ_STATS))
2799 goto nla_put_failure;
2800
2801 if (nla_put_u32(msg, NL80211_ATTR_TXQ_LIMIT,
2802 rdev->wiphy.txq_limit))
2803 goto nla_put_failure;
2804 if (nla_put_u32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT,
2805 rdev->wiphy.txq_memory_limit))
2806 goto nla_put_failure;
2807 if (nla_put_u32(msg, NL80211_ATTR_TXQ_QUANTUM,
2808 rdev->wiphy.txq_quantum))
2809 goto nla_put_failure;
2810 }
2811
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02002812 state->split_start++;
2813 break;
2814 case 14:
2815 if (nl80211_send_pmsr_capa(rdev, msg))
2816 goto nla_put_failure;
2817
Veerendranath Jakkamab4dfa22018-12-19 22:52:25 +05302818 state->split_start++;
2819 break;
2820 case 15:
2821 if (rdev->wiphy.akm_suites &&
2822 nla_put(msg, NL80211_ATTR_AKM_SUITES,
2823 sizeof(u32) * rdev->wiphy.n_akm_suites,
2824 rdev->wiphy.akm_suites))
2825 goto nla_put_failure;
2826
Veerendranath Jakkamd6039a32020-01-27 02:00:32 +05302827 if (nl80211_put_iftype_akm_suites(rdev, msg))
2828 goto nla_put_failure;
2829
Johannes Berg3710a8a2020-02-24 11:34:25 +01002830 if (nl80211_put_tid_config_support(rdev, msg))
2831 goto nla_put_failure;
Carl Huang6bdb68c2020-12-03 05:37:26 -05002832 state->split_start++;
2833 break;
2834 case 16:
2835 if (nl80211_put_sar_specs(rdev, msg))
2836 goto nla_put_failure;
Johannes Berg3710a8a2020-02-24 11:34:25 +01002837
John Crispindc1e3cb2021-09-15 19:54:34 -07002838 if (nl80211_put_mbssid_support(&rdev->wiphy, msg))
2839 goto nla_put_failure;
2840
Johannes Berg3713b4e2013-02-14 16:19:38 +01002841 /* done */
Johannes Berg86e8cf92013-06-19 10:57:22 +02002842 state->split_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002843 break;
Johannes Bergff1b6e62011-05-04 15:37:28 +02002844 }
Johannes Berg3bb20552014-05-26 13:52:25 +02002845 finish:
Johannes Berg053c0952015-01-16 22:09:00 +01002846 genlmsg_end(msg, hdr);
2847 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002848
2849 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002850 genlmsg_cancel(msg, hdr);
2851 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04002852}
2853
Johannes Berg86e8cf92013-06-19 10:57:22 +02002854static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
2855 struct netlink_callback *cb,
2856 struct nl80211_dump_wiphy_state *state)
2857{
Johannes Berg50508d92019-07-29 16:31:09 +02002858 struct nlattr **tb = kcalloc(NUM_NL80211_ATTR, sizeof(*tb), GFP_KERNEL);
2859 int ret;
2860
2861 if (!tb)
2862 return -ENOMEM;
2863
2864 ret = nlmsg_parse_deprecated(cb->nlh,
2865 GENL_HDRLEN + nl80211_fam.hdrsize,
2866 tb, nl80211_fam.maxattr,
2867 nl80211_policy, NULL);
Johannes Berg86e8cf92013-06-19 10:57:22 +02002868 /* ignore parse errors for backward compatibility */
Johannes Berg50508d92019-07-29 16:31:09 +02002869 if (ret) {
2870 ret = 0;
2871 goto out;
2872 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002873
2874 state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
2875 if (tb[NL80211_ATTR_WIPHY])
2876 state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
2877 if (tb[NL80211_ATTR_WDEV])
2878 state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
2879 if (tb[NL80211_ATTR_IFINDEX]) {
2880 struct net_device *netdev;
2881 struct cfg80211_registered_device *rdev;
2882 int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2883
Ying Xue7f2b8562014-01-15 10:23:45 +08002884 netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
Johannes Berg50508d92019-07-29 16:31:09 +02002885 if (!netdev) {
2886 ret = -ENODEV;
2887 goto out;
2888 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002889 if (netdev->ieee80211_ptr) {
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002890 rdev = wiphy_to_rdev(
Johannes Berg86e8cf92013-06-19 10:57:22 +02002891 netdev->ieee80211_ptr->wiphy);
2892 state->filter_wiphy = rdev->wiphy_idx;
2893 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002894 }
2895
Johannes Berg50508d92019-07-29 16:31:09 +02002896 ret = 0;
2897out:
2898 kfree(tb);
2899 return ret;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002900}
2901
Johannes Berg55682962007-09-20 13:09:35 -04002902static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
2903{
Johannes Berg645e77d2013-03-01 14:03:49 +01002904 int idx = 0, ret;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002905 struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002906 struct cfg80211_registered_device *rdev;
Johannes Berg3a5a4232013-06-19 10:09:57 +02002907
Johannes Berg5fe231e2013-05-08 21:45:15 +02002908 rtnl_lock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02002909 if (!state) {
2910 state = kzalloc(sizeof(*state), GFP_KERNEL);
John W. Linville57ed5cd2013-06-28 13:18:21 -04002911 if (!state) {
2912 rtnl_unlock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02002913 return -ENOMEM;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002914 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002915 state->filter_wiphy = -1;
2916 ret = nl80211_dump_wiphy_parse(skb, cb, state);
2917 if (ret) {
2918 kfree(state);
2919 rtnl_unlock();
2920 return ret;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002921 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002922 cb->args[0] = (long)state;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002923 }
2924
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002925 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2926 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02002927 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002928 if (++idx <= state->start)
Johannes Berg55682962007-09-20 13:09:35 -04002929 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002930 if (state->filter_wiphy != -1 &&
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002931 state->filter_wiphy != rdev->wiphy_idx)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002932 continue;
2933 /* attempt to fit multiple wiphy data chunks into the skb */
2934 do {
Johannes Berg3bb20552014-05-26 13:52:25 +02002935 ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY,
2936 skb,
Johannes Berg3713b4e2013-02-14 16:19:38 +01002937 NETLINK_CB(cb->skb).portid,
2938 cb->nlh->nlmsg_seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002939 NLM_F_MULTI, state);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002940 if (ret < 0) {
2941 /*
2942 * If sending the wiphy data didn't fit (ENOBUFS
2943 * or EMSGSIZE returned), this SKB is still
2944 * empty (so it's not too big because another
2945 * wiphy dataset is already in the skb) and
2946 * we've not tried to adjust the dump allocation
2947 * yet ... then adjust the alloc size to be
2948 * bigger, and return 1 but with the empty skb.
2949 * This results in an empty message being RX'ed
2950 * in userspace, but that is ignored.
2951 *
2952 * We can then retry with the larger buffer.
2953 */
2954 if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
Pontus Fuchsf12cb282014-01-16 15:00:40 +01002955 !skb->len && !state->split &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002956 cb->min_dump_alloc < 4096) {
2957 cb->min_dump_alloc = 4096;
Pontus Fuchsf12cb282014-01-16 15:00:40 +01002958 state->split_start = 0;
David S. Millerd98cae64e2013-06-19 16:49:39 -07002959 rtnl_unlock();
Johannes Berg3713b4e2013-02-14 16:19:38 +01002960 return 1;
2961 }
2962 idx--;
2963 break;
Johannes Berg645e77d2013-03-01 14:03:49 +01002964 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002965 } while (state->split_start > 0);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002966 break;
Johannes Berg55682962007-09-20 13:09:35 -04002967 }
Johannes Berg5fe231e2013-05-08 21:45:15 +02002968 rtnl_unlock();
Johannes Berg55682962007-09-20 13:09:35 -04002969
Johannes Berg86e8cf92013-06-19 10:57:22 +02002970 state->start = idx;
Johannes Berg55682962007-09-20 13:09:35 -04002971
2972 return skb->len;
2973}
2974
Johannes Berg86e8cf92013-06-19 10:57:22 +02002975static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
2976{
2977 kfree((void *)cb->args[0]);
2978 return 0;
2979}
2980
Johannes Berg55682962007-09-20 13:09:35 -04002981static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
2982{
2983 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002984 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg86e8cf92013-06-19 10:57:22 +02002985 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -04002986
Johannes Berg645e77d2013-03-01 14:03:49 +01002987 msg = nlmsg_new(4096, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002988 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002989 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002990
Johannes Berg3bb20552014-05-26 13:52:25 +02002991 if (nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY, msg,
2992 info->snd_portid, info->snd_seq, 0,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002993 &state) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002994 nlmsg_free(msg);
2995 return -ENOBUFS;
2996 }
Johannes Berg55682962007-09-20 13:09:35 -04002997
Johannes Berg134e6372009-07-10 09:51:34 +00002998 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002999}
3000
Jouni Malinen31888482008-10-30 16:59:24 +02003001static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
3002 [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 },
3003 [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 },
3004 [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 },
3005 [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 },
3006 [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 },
3007};
3008
3009static int parse_txq_params(struct nlattr *tb[],
3010 struct ieee80211_txq_params *txq_params)
3011{
Dan Williams259d8c12018-01-29 17:03:15 -08003012 u8 ac;
3013
Johannes Berga3304b02012-03-28 11:04:24 +02003014 if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
Jouni Malinen31888482008-10-30 16:59:24 +02003015 !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
3016 !tb[NL80211_TXQ_ATTR_AIFS])
3017 return -EINVAL;
3018
Dan Williams259d8c12018-01-29 17:03:15 -08003019 ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
Jouni Malinen31888482008-10-30 16:59:24 +02003020 txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
3021 txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
3022 txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
3023 txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
3024
Dan Williams259d8c12018-01-29 17:03:15 -08003025 if (ac >= NL80211_NUM_ACS)
Johannes Berga3304b02012-03-28 11:04:24 +02003026 return -EINVAL;
Dan Williams259d8c12018-01-29 17:03:15 -08003027 txq_params->ac = array_index_nospec(ac, NL80211_NUM_ACS);
Jouni Malinen31888482008-10-30 16:59:24 +02003028 return 0;
3029}
3030
Johannes Bergf444de02010-05-05 15:25:02 +02003031static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
3032{
3033 /*
Johannes Berge7e05172020-11-09 10:57:47 +01003034 * You can only set the channel explicitly for some interfaces,
3035 * most have their channel managed via their respective
Johannes Bergcc1d2802012-05-16 23:50:20 +02003036 * "establish a connection" command (connect, join, ...)
3037 *
3038 * For AP/GO and mesh mode, the channel can be set with the
3039 * channel userspace API, but is only stored and passed to the
3040 * low-level driver when the AP starts or the mesh is joined.
3041 * This is for backward compatibility, userspace can also give
3042 * the channel in the start-ap or join-mesh commands instead.
Johannes Bergf444de02010-05-05 15:25:02 +02003043 *
3044 * Monitors are special as they are normally slaved to
Johannes Berge8c9bd52012-06-06 08:18:22 +02003045 * whatever else is going on, so they have their own special
3046 * operation to set the monitor channel if possible.
Johannes Bergf444de02010-05-05 15:25:02 +02003047 */
3048 return !wdev ||
3049 wdev->iftype == NL80211_IFTYPE_AP ||
Johannes Bergf444de02010-05-05 15:25:02 +02003050 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
Johannes Berg074ac8d2010-09-16 14:58:22 +02003051 wdev->iftype == NL80211_IFTYPE_MONITOR ||
3052 wdev->iftype == NL80211_IFTYPE_P2P_GO;
Johannes Bergf444de02010-05-05 15:25:02 +02003053}
3054
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02003055int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
3056 struct genl_info *info,
3057 struct cfg80211_chan_def *chandef)
Johannes Berg683b6d32012-11-08 21:25:48 +01003058{
Johannes Berg49f9cf02018-10-01 11:55:09 +02003059 struct netlink_ext_ack *extack = info->extack;
3060 struct nlattr **attrs = info->attrs;
Mahesh Paliveladbeca2e2012-11-29 14:11:07 +05303061 u32 control_freq;
Johannes Berg683b6d32012-11-08 21:25:48 +01003062
Johannes Berg49f9cf02018-10-01 11:55:09 +02003063 if (!attrs[NL80211_ATTR_WIPHY_FREQ])
Johannes Berg683b6d32012-11-08 21:25:48 +01003064 return -EINVAL;
3065
Thomas Pedersen942ba882020-04-30 10:25:51 -07003066 control_freq = MHZ_TO_KHZ(
3067 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
3068 if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
3069 control_freq +=
3070 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
Johannes Berg683b6d32012-11-08 21:25:48 +01003071
Johannes Bergf43e5212019-09-23 13:51:16 +02003072 memset(chandef, 0, sizeof(*chandef));
Thomas Pedersen942ba882020-04-30 10:25:51 -07003073 chandef->chan = ieee80211_get_channel_khz(&rdev->wiphy, control_freq);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003074 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
Thomas Pedersen942ba882020-04-30 10:25:51 -07003075 chandef->center_freq1 = KHZ_TO_MHZ(control_freq);
3076 chandef->freq1_offset = control_freq % 1000;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003077 chandef->center_freq2 = 0;
Johannes Berg683b6d32012-11-08 21:25:48 +01003078
3079 /* Primary channel not allowed */
Johannes Berg49f9cf02018-10-01 11:55:09 +02003080 if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) {
3081 NL_SET_ERR_MSG_ATTR(extack, attrs[NL80211_ATTR_WIPHY_FREQ],
3082 "Channel is disabled");
Johannes Berg683b6d32012-11-08 21:25:48 +01003083 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02003084 }
Johannes Berg683b6d32012-11-08 21:25:48 +01003085
Johannes Berg49f9cf02018-10-01 11:55:09 +02003086 if (attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003087 enum nl80211_channel_type chantype;
Johannes Berg683b6d32012-11-08 21:25:48 +01003088
Johannes Berg49f9cf02018-10-01 11:55:09 +02003089 chantype = nla_get_u32(attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003090
3091 switch (chantype) {
3092 case NL80211_CHAN_NO_HT:
3093 case NL80211_CHAN_HT20:
3094 case NL80211_CHAN_HT40PLUS:
3095 case NL80211_CHAN_HT40MINUS:
3096 cfg80211_chandef_create(chandef, chandef->chan,
3097 chantype);
Tova Mussaiffa46292017-08-05 11:44:38 +03003098 /* user input for center_freq is incorrect */
Johannes Berg49f9cf02018-10-01 11:55:09 +02003099 if (attrs[NL80211_ATTR_CENTER_FREQ1] &&
3100 chandef->center_freq1 != nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1])) {
3101 NL_SET_ERR_MSG_ATTR(extack,
3102 attrs[NL80211_ATTR_CENTER_FREQ1],
3103 "bad center frequency 1");
Tova Mussaiffa46292017-08-05 11:44:38 +03003104 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02003105 }
Tova Mussaiffa46292017-08-05 11:44:38 +03003106 /* center_freq2 must be zero */
Johannes Berg49f9cf02018-10-01 11:55:09 +02003107 if (attrs[NL80211_ATTR_CENTER_FREQ2] &&
3108 nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2])) {
3109 NL_SET_ERR_MSG_ATTR(extack,
3110 attrs[NL80211_ATTR_CENTER_FREQ2],
3111 "center frequency 2 can't be used");
Tova Mussaiffa46292017-08-05 11:44:38 +03003112 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02003113 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003114 break;
3115 default:
Johannes Berg49f9cf02018-10-01 11:55:09 +02003116 NL_SET_ERR_MSG_ATTR(extack,
3117 attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
3118 "invalid channel type");
Johannes Berg683b6d32012-11-08 21:25:48 +01003119 return -EINVAL;
Johannes Berg683b6d32012-11-08 21:25:48 +01003120 }
Johannes Berg49f9cf02018-10-01 11:55:09 +02003121 } else if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003122 chandef->width =
Johannes Berg49f9cf02018-10-01 11:55:09 +02003123 nla_get_u32(attrs[NL80211_ATTR_CHANNEL_WIDTH]);
Thomas Pedersen942ba882020-04-30 10:25:51 -07003124 if (attrs[NL80211_ATTR_CENTER_FREQ1]) {
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003125 chandef->center_freq1 =
Johannes Berg49f9cf02018-10-01 11:55:09 +02003126 nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1]);
Thomas Pedersen942ba882020-04-30 10:25:51 -07003127 if (attrs[NL80211_ATTR_CENTER_FREQ1_OFFSET])
3128 chandef->freq1_offset = nla_get_u32(
3129 attrs[NL80211_ATTR_CENTER_FREQ1_OFFSET]);
3130 else
3131 chandef->freq1_offset = 0;
3132 }
Johannes Berg49f9cf02018-10-01 11:55:09 +02003133 if (attrs[NL80211_ATTR_CENTER_FREQ2])
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003134 chandef->center_freq2 =
Johannes Berg49f9cf02018-10-01 11:55:09 +02003135 nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2]);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003136 }
3137
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +03003138 if (info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]) {
3139 chandef->edmg.channels =
3140 nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]);
3141
3142 if (info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG])
3143 chandef->edmg.bw_config =
3144 nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG]);
3145 } else {
3146 chandef->edmg.bw_config = 0;
3147 chandef->edmg.channels = 0;
3148 }
3149
Johannes Berg49f9cf02018-10-01 11:55:09 +02003150 if (!cfg80211_chandef_valid(chandef)) {
3151 NL_SET_ERR_MSG(extack, "invalid channel definition");
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003152 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02003153 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003154
Johannes Berg9f5e8f62012-11-22 16:59:45 +01003155 if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
Johannes Berg49f9cf02018-10-01 11:55:09 +02003156 IEEE80211_CHAN_DISABLED)) {
3157 NL_SET_ERR_MSG(extack, "(extension) channel is disabled");
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003158 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02003159 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003160
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02003161 if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
3162 chandef->width == NL80211_CHAN_WIDTH_10) &&
Johannes Berg49f9cf02018-10-01 11:55:09 +02003163 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ)) {
3164 NL_SET_ERR_MSG(extack, "5/10 MHz not supported");
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02003165 return -EINVAL;
Johannes Berg49f9cf02018-10-01 11:55:09 +02003166 }
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02003167
Johannes Berg683b6d32012-11-08 21:25:48 +01003168 return 0;
3169}
3170
Johannes Bergf444de02010-05-05 15:25:02 +02003171static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
Jouni Malinene16821b2014-04-28 11:22:08 +03003172 struct net_device *dev,
Johannes Bergf444de02010-05-05 15:25:02 +02003173 struct genl_info *info)
3174{
Johannes Berg683b6d32012-11-08 21:25:48 +01003175 struct cfg80211_chan_def chandef;
Johannes Bergf444de02010-05-05 15:25:02 +02003176 int result;
Johannes Berge8c9bd52012-06-06 08:18:22 +02003177 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
Jouni Malinene16821b2014-04-28 11:22:08 +03003178 struct wireless_dev *wdev = NULL;
Johannes Berge8c9bd52012-06-06 08:18:22 +02003179
Jouni Malinene16821b2014-04-28 11:22:08 +03003180 if (dev)
3181 wdev = dev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02003182 if (!nl80211_can_set_dev_channel(wdev))
3183 return -EOPNOTSUPP;
Jouni Malinene16821b2014-04-28 11:22:08 +03003184 if (wdev)
3185 iftype = wdev->iftype;
Johannes Bergf444de02010-05-05 15:25:02 +02003186
Johannes Berg683b6d32012-11-08 21:25:48 +01003187 result = nl80211_parse_chandef(rdev, info, &chandef);
3188 if (result)
3189 return result;
Johannes Bergf444de02010-05-05 15:25:02 +02003190
Johannes Berge8c9bd52012-06-06 08:18:22 +02003191 switch (iftype) {
Johannes Bergaa430da2012-05-16 23:50:18 +02003192 case NL80211_IFTYPE_AP:
3193 case NL80211_IFTYPE_P2P_GO:
Arik Nemtsov923b3522015-07-08 15:41:44 +03003194 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
3195 iftype)) {
Johannes Bergaa430da2012-05-16 23:50:18 +02003196 result = -EINVAL;
3197 break;
3198 }
Jouni Malinene16821b2014-04-28 11:22:08 +03003199 if (wdev->beacon_interval) {
3200 if (!dev || !rdev->ops->set_ap_chanwidth ||
3201 !(rdev->wiphy.features &
3202 NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
3203 result = -EBUSY;
3204 break;
3205 }
3206
3207 /* Only allow dynamic channel width changes */
3208 if (chandef.chan != wdev->preset_chandef.chan) {
3209 result = -EBUSY;
3210 break;
3211 }
3212 result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
3213 if (result)
3214 break;
3215 }
Johannes Berg683b6d32012-11-08 21:25:48 +01003216 wdev->preset_chandef = chandef;
Johannes Bergaa430da2012-05-16 23:50:18 +02003217 result = 0;
3218 break;
Johannes Bergcc1d2802012-05-16 23:50:20 +02003219 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg683b6d32012-11-08 21:25:48 +01003220 result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
Johannes Bergcc1d2802012-05-16 23:50:20 +02003221 break;
Johannes Berge8c9bd52012-06-06 08:18:22 +02003222 case NL80211_IFTYPE_MONITOR:
Johannes Berg683b6d32012-11-08 21:25:48 +01003223 result = cfg80211_set_monitor_channel(rdev, &chandef);
Johannes Berge8c9bd52012-06-06 08:18:22 +02003224 break;
Johannes Bergaa430da2012-05-16 23:50:18 +02003225 default:
Johannes Berge8c9bd52012-06-06 08:18:22 +02003226 result = -EINVAL;
Johannes Bergf444de02010-05-05 15:25:02 +02003227 }
Johannes Bergf444de02010-05-05 15:25:02 +02003228
3229 return result;
3230}
3231
3232static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
3233{
Johannes Berg4c476992010-10-04 21:36:35 +02003234 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3235 struct net_device *netdev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02003236
Jouni Malinene16821b2014-04-28 11:22:08 +03003237 return __nl80211_set_channel(rdev, netdev, info);
Johannes Bergf444de02010-05-05 15:25:02 +02003238}
3239
Johannes Berg55682962007-09-20 13:09:35 -04003240static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
3241{
Johannes Berga05829a2021-01-22 16:19:43 +01003242 struct cfg80211_registered_device *rdev = NULL;
Johannes Bergf444de02010-05-05 15:25:02 +02003243 struct net_device *netdev = NULL;
3244 struct wireless_dev *wdev;
Bill Jordana1e567c2010-09-10 11:22:32 -04003245 int result = 0, rem_txq_params = 0;
Jouni Malinen31888482008-10-30 16:59:24 +02003246 struct nlattr *nl_txq_params;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003247 u32 changed;
3248 u8 retry_short = 0, retry_long = 0;
3249 u32 frag_threshold = 0, rts_threshold = 0;
Lukáš Turek81077e82009-12-21 22:50:47 +01003250 u8 coverage_class = 0;
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003251 u32 txq_limit = 0, txq_memory_limit = 0, txq_quantum = 0;
Johannes Berg55682962007-09-20 13:09:35 -04003252
Johannes Berga05829a2021-01-22 16:19:43 +01003253 rtnl_lock();
Johannes Bergf444de02010-05-05 15:25:02 +02003254 /*
3255 * Try to find the wiphy and netdev. Normally this
3256 * function shouldn't need the netdev, but this is
3257 * done for backward compatibility -- previously
3258 * setting the channel was done per wiphy, but now
3259 * it is per netdev. Previous userland like hostapd
3260 * also passed a netdev to set_wiphy, so that it is
3261 * possible to let that go to the right netdev!
3262 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01003263
Johannes Bergf444de02010-05-05 15:25:02 +02003264 if (info->attrs[NL80211_ATTR_IFINDEX]) {
3265 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
3266
Ying Xue7f2b8562014-01-15 10:23:45 +08003267 netdev = __dev_get_by_index(genl_info_net(info), ifindex);
Johannes Berg5fe231e2013-05-08 21:45:15 +02003268 if (netdev && netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +08003269 rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
Johannes Berg5fe231e2013-05-08 21:45:15 +02003270 else
Johannes Bergf444de02010-05-05 15:25:02 +02003271 netdev = NULL;
Johannes Berg4bbf4d52009-03-24 09:35:46 +01003272 }
3273
Johannes Bergf444de02010-05-05 15:25:02 +02003274 if (!netdev) {
Johannes Berg878d9ec2012-06-15 14:18:32 +02003275 rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
3276 info->attrs);
Johannes Berga05829a2021-01-22 16:19:43 +01003277 if (IS_ERR(rdev)) {
3278 rtnl_unlock();
Johannes Berg4c476992010-10-04 21:36:35 +02003279 return PTR_ERR(rdev);
Johannes Berga05829a2021-01-22 16:19:43 +01003280 }
Johannes Bergf444de02010-05-05 15:25:02 +02003281 wdev = NULL;
3282 netdev = NULL;
3283 result = 0;
Johannes Berg71fe96b2012-10-24 10:04:58 +02003284 } else
Johannes Bergf444de02010-05-05 15:25:02 +02003285 wdev = netdev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02003286
Johannes Berga05829a2021-01-22 16:19:43 +01003287 wiphy_lock(&rdev->wiphy);
Johannes Berga05829a2021-01-22 16:19:43 +01003288
Johannes Bergf444de02010-05-05 15:25:02 +02003289 /*
3290 * end workaround code, by now the rdev is available
3291 * and locked, and wdev may or may not be NULL.
3292 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01003293
3294 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
Jouni Malinen31888482008-10-30 16:59:24 +02003295 result = cfg80211_dev_rename(
3296 rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
Johannes Berg0391a452021-01-28 18:35:25 +01003297 rtnl_unlock();
Johannes Berg4bbf4d52009-03-24 09:35:46 +01003298
Johannes Berg4bbf4d52009-03-24 09:35:46 +01003299 if (result)
Johannes Berga05829a2021-01-22 16:19:43 +01003300 goto out;
Johannes Berg55682962007-09-20 13:09:35 -04003301
Jouni Malinen31888482008-10-30 16:59:24 +02003302 if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
3303 struct ieee80211_txq_params txq_params;
3304 struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
3305
Johannes Berga05829a2021-01-22 16:19:43 +01003306 if (!rdev->ops->set_txq_params) {
3307 result = -EOPNOTSUPP;
3308 goto out;
3309 }
Jouni Malinen31888482008-10-30 16:59:24 +02003310
Johannes Berga05829a2021-01-22 16:19:43 +01003311 if (!netdev) {
3312 result = -EINVAL;
3313 goto out;
3314 }
Eliad Pellerf70f01c2011-09-25 20:06:53 +03003315
Johannes Berg133a3ff2011-11-03 14:50:13 +01003316 if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Johannes Berga05829a2021-01-22 16:19:43 +01003317 netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
3318 result = -EINVAL;
3319 goto out;
3320 }
Johannes Berg133a3ff2011-11-03 14:50:13 +01003321
Johannes Berga05829a2021-01-22 16:19:43 +01003322 if (!netif_running(netdev)) {
3323 result = -ENETDOWN;
3324 goto out;
3325 }
Johannes Berg2b5f8b02012-04-02 10:51:55 +02003326
Jouni Malinen31888482008-10-30 16:59:24 +02003327 nla_for_each_nested(nl_txq_params,
3328 info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
3329 rem_txq_params) {
Johannes Berg8cb08172019-04-26 14:07:28 +02003330 result = nla_parse_nested_deprecated(tb,
3331 NL80211_TXQ_ATTR_MAX,
3332 nl_txq_params,
3333 txq_params_policy,
3334 info->extack);
Johannes Bergae811e22014-01-24 10:17:47 +01003335 if (result)
Johannes Berga05829a2021-01-22 16:19:43 +01003336 goto out;
Jouni Malinen31888482008-10-30 16:59:24 +02003337 result = parse_txq_params(tb, &txq_params);
3338 if (result)
Johannes Berga05829a2021-01-22 16:19:43 +01003339 goto out;
Jouni Malinen31888482008-10-30 16:59:24 +02003340
Hila Gonene35e4d22012-06-27 17:19:42 +03003341 result = rdev_set_txq_params(rdev, netdev,
3342 &txq_params);
Jouni Malinen31888482008-10-30 16:59:24 +02003343 if (result)
Johannes Berga05829a2021-01-22 16:19:43 +01003344 goto out;
Jouni Malinen31888482008-10-30 16:59:24 +02003345 }
3346 }
3347
Jouni Malinen72bdcf32008-11-26 16:15:24 +02003348 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinene16821b2014-04-28 11:22:08 +03003349 result = __nl80211_set_channel(
3350 rdev,
3351 nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
3352 info);
Jouni Malinen72bdcf32008-11-26 16:15:24 +02003353 if (result)
Johannes Berga05829a2021-01-22 16:19:43 +01003354 goto out;
Jouni Malinen72bdcf32008-11-26 16:15:24 +02003355 }
3356
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003357 if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
Johannes Bergc8442112012-10-24 10:17:18 +02003358 struct wireless_dev *txp_wdev = wdev;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003359 enum nl80211_tx_power_setting type;
3360 int idx, mbm = 0;
3361
Johannes Bergc8442112012-10-24 10:17:18 +02003362 if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
3363 txp_wdev = NULL;
3364
Johannes Berga05829a2021-01-22 16:19:43 +01003365 if (!rdev->ops->set_tx_power) {
3366 result = -EOPNOTSUPP;
3367 goto out;
3368 }
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003369
3370 idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
3371 type = nla_get_u32(info->attrs[idx]);
3372
3373 if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
Johannes Berga05829a2021-01-22 16:19:43 +01003374 (type != NL80211_TX_POWER_AUTOMATIC)) {
3375 result = -EINVAL;
3376 goto out;
3377 }
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003378
3379 if (type != NL80211_TX_POWER_AUTOMATIC) {
3380 idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
3381 mbm = nla_get_u32(info->attrs[idx]);
3382 }
3383
Johannes Bergc8442112012-10-24 10:17:18 +02003384 result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003385 if (result)
Johannes Berga05829a2021-01-22 16:19:43 +01003386 goto out;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03003387 }
3388
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09003389 if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
3390 info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
3391 u32 tx_ant, rx_ant;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07003392
Bruno Randolf7f531e02010-12-16 11:30:22 +09003393 if ((!rdev->wiphy.available_antennas_tx &&
3394 !rdev->wiphy.available_antennas_rx) ||
Johannes Berga05829a2021-01-22 16:19:43 +01003395 !rdev->ops->set_antenna) {
3396 result = -EOPNOTSUPP;
3397 goto out;
3398 }
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09003399
3400 tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
3401 rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
3402
Bruno Randolfa7ffac92010-12-08 13:59:24 +09003403 /* reject antenna configurations which don't match the
Bruno Randolf7f531e02010-12-16 11:30:22 +09003404 * available antenna masks, except for the "all" mask */
3405 if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
Johannes Berga05829a2021-01-22 16:19:43 +01003406 (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx))) {
3407 result = -EINVAL;
3408 goto out;
3409 }
Bruno Randolfa7ffac92010-12-08 13:59:24 +09003410
Bruno Randolf7f531e02010-12-16 11:30:22 +09003411 tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
3412 rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09003413
Hila Gonene35e4d22012-06-27 17:19:42 +03003414 result = rdev_set_antenna(rdev, tx_ant, rx_ant);
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09003415 if (result)
Johannes Berga05829a2021-01-22 16:19:43 +01003416 goto out;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09003417 }
3418
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003419 changed = 0;
3420
3421 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
3422 retry_short = nla_get_u8(
3423 info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
Ying Xue7f2b8562014-01-15 10:23:45 +08003424
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003425 changed |= WIPHY_PARAM_RETRY_SHORT;
3426 }
3427
3428 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
3429 retry_long = nla_get_u8(
3430 info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
Ying Xue7f2b8562014-01-15 10:23:45 +08003431
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003432 changed |= WIPHY_PARAM_RETRY_LONG;
3433 }
3434
3435 if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
3436 frag_threshold = nla_get_u32(
3437 info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
Johannes Berga05829a2021-01-22 16:19:43 +01003438 if (frag_threshold < 256) {
3439 result = -EINVAL;
3440 goto out;
3441 }
Ying Xue7f2b8562014-01-15 10:23:45 +08003442
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003443 if (frag_threshold != (u32) -1) {
3444 /*
3445 * Fragments (apart from the last one) are required to
3446 * have even length. Make the fragmentation code
3447 * simpler by stripping LSB should someone try to use
3448 * odd threshold value.
3449 */
3450 frag_threshold &= ~0x1;
3451 }
3452 changed |= WIPHY_PARAM_FRAG_THRESHOLD;
3453 }
3454
3455 if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
3456 rts_threshold = nla_get_u32(
3457 info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
3458 changed |= WIPHY_PARAM_RTS_THRESHOLD;
3459 }
3460
Lukáš Turek81077e82009-12-21 22:50:47 +01003461 if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
Johannes Berga05829a2021-01-22 16:19:43 +01003462 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
3463 result = -EINVAL;
3464 goto out;
3465 }
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02003466
Lukáš Turek81077e82009-12-21 22:50:47 +01003467 coverage_class = nla_get_u8(
3468 info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
3469 changed |= WIPHY_PARAM_COVERAGE_CLASS;
3470 }
3471
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02003472 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
Johannes Berga05829a2021-01-22 16:19:43 +01003473 if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION)) {
3474 result = -EOPNOTSUPP;
3475 goto out;
3476 }
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02003477
3478 changed |= WIPHY_PARAM_DYN_ACK;
3479 }
3480
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003481 if (info->attrs[NL80211_ATTR_TXQ_LIMIT]) {
3482 if (!wiphy_ext_feature_isset(&rdev->wiphy,
Johannes Berga05829a2021-01-22 16:19:43 +01003483 NL80211_EXT_FEATURE_TXQS)) {
3484 result = -EOPNOTSUPP;
3485 goto out;
3486 }
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003487 txq_limit = nla_get_u32(
3488 info->attrs[NL80211_ATTR_TXQ_LIMIT]);
3489 changed |= WIPHY_PARAM_TXQ_LIMIT;
3490 }
3491
3492 if (info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]) {
3493 if (!wiphy_ext_feature_isset(&rdev->wiphy,
Johannes Berga05829a2021-01-22 16:19:43 +01003494 NL80211_EXT_FEATURE_TXQS)) {
3495 result = -EOPNOTSUPP;
3496 goto out;
3497 }
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003498 txq_memory_limit = nla_get_u32(
3499 info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]);
3500 changed |= WIPHY_PARAM_TXQ_MEMORY_LIMIT;
3501 }
3502
3503 if (info->attrs[NL80211_ATTR_TXQ_QUANTUM]) {
3504 if (!wiphy_ext_feature_isset(&rdev->wiphy,
Johannes Berga05829a2021-01-22 16:19:43 +01003505 NL80211_EXT_FEATURE_TXQS)) {
3506 result = -EOPNOTSUPP;
3507 goto out;
3508 }
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003509 txq_quantum = nla_get_u32(
3510 info->attrs[NL80211_ATTR_TXQ_QUANTUM]);
3511 changed |= WIPHY_PARAM_TXQ_QUANTUM;
3512 }
3513
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003514 if (changed) {
3515 u8 old_retry_short, old_retry_long;
3516 u32 old_frag_threshold, old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01003517 u8 old_coverage_class;
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003518 u32 old_txq_limit, old_txq_memory_limit, old_txq_quantum;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003519
Johannes Berga05829a2021-01-22 16:19:43 +01003520 if (!rdev->ops->set_wiphy_params) {
3521 result = -EOPNOTSUPP;
3522 goto out;
3523 }
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003524
3525 old_retry_short = rdev->wiphy.retry_short;
3526 old_retry_long = rdev->wiphy.retry_long;
3527 old_frag_threshold = rdev->wiphy.frag_threshold;
3528 old_rts_threshold = rdev->wiphy.rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01003529 old_coverage_class = rdev->wiphy.coverage_class;
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003530 old_txq_limit = rdev->wiphy.txq_limit;
3531 old_txq_memory_limit = rdev->wiphy.txq_memory_limit;
3532 old_txq_quantum = rdev->wiphy.txq_quantum;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003533
3534 if (changed & WIPHY_PARAM_RETRY_SHORT)
3535 rdev->wiphy.retry_short = retry_short;
3536 if (changed & WIPHY_PARAM_RETRY_LONG)
3537 rdev->wiphy.retry_long = retry_long;
3538 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
3539 rdev->wiphy.frag_threshold = frag_threshold;
3540 if (changed & WIPHY_PARAM_RTS_THRESHOLD)
3541 rdev->wiphy.rts_threshold = rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01003542 if (changed & WIPHY_PARAM_COVERAGE_CLASS)
3543 rdev->wiphy.coverage_class = coverage_class;
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003544 if (changed & WIPHY_PARAM_TXQ_LIMIT)
3545 rdev->wiphy.txq_limit = txq_limit;
3546 if (changed & WIPHY_PARAM_TXQ_MEMORY_LIMIT)
3547 rdev->wiphy.txq_memory_limit = txq_memory_limit;
3548 if (changed & WIPHY_PARAM_TXQ_QUANTUM)
3549 rdev->wiphy.txq_quantum = txq_quantum;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003550
Hila Gonene35e4d22012-06-27 17:19:42 +03003551 result = rdev_set_wiphy_params(rdev, changed);
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003552 if (result) {
3553 rdev->wiphy.retry_short = old_retry_short;
3554 rdev->wiphy.retry_long = old_retry_long;
3555 rdev->wiphy.frag_threshold = old_frag_threshold;
3556 rdev->wiphy.rts_threshold = old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01003557 rdev->wiphy.coverage_class = old_coverage_class;
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003558 rdev->wiphy.txq_limit = old_txq_limit;
3559 rdev->wiphy.txq_memory_limit = old_txq_memory_limit;
3560 rdev->wiphy.txq_quantum = old_txq_quantum;
Johannes Berga05829a2021-01-22 16:19:43 +01003561 goto out;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02003562 }
3563 }
Johannes Berga05829a2021-01-22 16:19:43 +01003564
3565 result = 0;
3566
3567out:
3568 wiphy_unlock(&rdev->wiphy);
3569 return result;
Johannes Berg55682962007-09-20 13:09:35 -04003570}
3571
Johannes Berg683b6d32012-11-08 21:25:48 +01003572static int nl80211_send_chandef(struct sk_buff *msg,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01003573 const struct cfg80211_chan_def *chandef)
Johannes Berg683b6d32012-11-08 21:25:48 +01003574{
Johannes Berg601555c2014-11-27 17:26:56 +01003575 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
3576 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003577
Johannes Berg683b6d32012-11-08 21:25:48 +01003578 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
3579 chandef->chan->center_freq))
3580 return -ENOBUFS;
Thomas Pedersen942ba882020-04-30 10:25:51 -07003581 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET,
3582 chandef->chan->freq_offset))
3583 return -ENOBUFS;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01003584 switch (chandef->width) {
3585 case NL80211_CHAN_WIDTH_20_NOHT:
3586 case NL80211_CHAN_WIDTH_20:
3587 case NL80211_CHAN_WIDTH_40:
3588 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
3589 cfg80211_get_chandef_type(chandef)))
3590 return -ENOBUFS;
3591 break;
3592 default:
3593 break;
3594 }
3595 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
3596 return -ENOBUFS;
3597 if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
3598 return -ENOBUFS;
3599 if (chandef->center_freq2 &&
3600 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
Johannes Berg683b6d32012-11-08 21:25:48 +01003601 return -ENOBUFS;
3602 return 0;
3603}
3604
Eric W. Biederman15e47302012-09-07 20:12:54 +00003605static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
Johannes Bergd7264052009-04-19 16:23:20 +02003606 struct cfg80211_registered_device *rdev,
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003607 struct wireless_dev *wdev,
3608 enum nl80211_commands cmd)
Johannes Berg55682962007-09-20 13:09:35 -04003609{
Johannes Berg72fb2ab2012-06-15 17:52:47 +02003610 struct net_device *dev = wdev->netdev;
Johannes Berg55682962007-09-20 13:09:35 -04003611 void *hdr;
3612
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003613 WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
3614 cmd != NL80211_CMD_DEL_INTERFACE &&
3615 cmd != NL80211_CMD_SET_INTERFACE);
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02003616
3617 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04003618 if (!hdr)
3619 return -1;
3620
Johannes Berg72fb2ab2012-06-15 17:52:47 +02003621 if (dev &&
3622 (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02003623 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
Johannes Berg72fb2ab2012-06-15 17:52:47 +02003624 goto nla_put_failure;
3625
3626 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
3627 nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02003628 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
3629 NL80211_ATTR_PAD) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02003630 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04003631 nla_put_u32(msg, NL80211_ATTR_GENERATION,
3632 rdev->devlist_generation ^
Antonio Quartulli446faa12018-06-14 09:43:06 +08003633 (cfg80211_rdev_list_generation << 2)) ||
3634 nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr))
David S. Miller9360ffd2012-03-29 04:41:26 -04003635 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02003636
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02003637 if (rdev->ops->get_channel) {
Johannes Berg683b6d32012-11-08 21:25:48 +01003638 int ret;
Johannes Bergf43e5212019-09-23 13:51:16 +02003639 struct cfg80211_chan_def chandef = {};
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02003640
Johannes Berg683b6d32012-11-08 21:25:48 +01003641 ret = rdev_get_channel(rdev, wdev, &chandef);
3642 if (ret == 0) {
3643 if (nl80211_send_chandef(msg, &chandef))
3644 goto nla_put_failure;
3645 }
Pontus Fuchsd91df0e2012-04-03 16:39:58 +02003646 }
3647
Rafał Miłeckid55d0d52015-08-31 22:59:38 +02003648 if (rdev->ops->get_tx_power) {
3649 int dbm, ret;
3650
3651 ret = rdev_get_tx_power(rdev, wdev, &dbm);
3652 if (ret == 0 &&
3653 nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
3654 DBM_TO_MBM(dbm)))
3655 goto nla_put_failure;
3656 }
3657
Johannes Berg44905262017-10-17 21:56:01 +02003658 wdev_lock(wdev);
3659 switch (wdev->iftype) {
3660 case NL80211_IFTYPE_AP:
3661 if (wdev->ssid_len &&
3662 nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
Johannes Berg4564b182017-12-11 12:33:47 +01003663 goto nla_put_failure_locked;
Johannes Berg44905262017-10-17 21:56:01 +02003664 break;
3665 case NL80211_IFTYPE_STATION:
3666 case NL80211_IFTYPE_P2P_CLIENT:
3667 case NL80211_IFTYPE_ADHOC: {
3668 const u8 *ssid_ie;
3669 if (!wdev->current_bss)
3670 break;
Dominik Brodowski7a94b8c2018-01-15 08:12:15 +01003671 rcu_read_lock();
Johannes Berg44905262017-10-17 21:56:01 +02003672 ssid_ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
3673 WLAN_EID_SSID);
Dominik Brodowski7a94b8c2018-01-15 08:12:15 +01003674 if (ssid_ie &&
3675 nla_put(msg, NL80211_ATTR_SSID, ssid_ie[1], ssid_ie + 2))
3676 goto nla_put_failure_rcu_locked;
3677 rcu_read_unlock();
Johannes Berg44905262017-10-17 21:56:01 +02003678 break;
3679 }
3680 default:
3681 /* nothing */
3682 break;
Antonio Quartullib84e7a02012-11-07 12:52:20 +01003683 }
Johannes Berg44905262017-10-17 21:56:01 +02003684 wdev_unlock(wdev);
Antonio Quartullib84e7a02012-11-07 12:52:20 +01003685
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02003686 if (rdev->ops->get_txq_stats) {
3687 struct cfg80211_txq_stats txqstats = {};
3688 int ret = rdev_get_txq_stats(rdev, wdev, &txqstats);
3689
3690 if (ret == 0 &&
3691 !nl80211_put_txq_stats(msg, &txqstats,
3692 NL80211_ATTR_TXQ_STATS))
3693 goto nla_put_failure;
3694 }
3695
Johannes Berg053c0952015-01-16 22:09:00 +01003696 genlmsg_end(msg, hdr);
3697 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04003698
Dominik Brodowski7a94b8c2018-01-15 08:12:15 +01003699 nla_put_failure_rcu_locked:
3700 rcu_read_unlock();
Johannes Berg4564b182017-12-11 12:33:47 +01003701 nla_put_failure_locked:
3702 wdev_unlock(wdev);
Johannes Berg55682962007-09-20 13:09:35 -04003703 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07003704 genlmsg_cancel(msg, hdr);
3705 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04003706}
3707
3708static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
3709{
3710 int wp_idx = 0;
3711 int if_idx = 0;
3712 int wp_start = cb->args[0];
3713 int if_start = cb->args[1];
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05003714 int filter_wiphy = -1;
Johannes Bergf5ea9122009-08-07 16:17:38 +02003715 struct cfg80211_registered_device *rdev;
Johannes Berg55682962007-09-20 13:09:35 -04003716 struct wireless_dev *wdev;
Johannes Bergea90e0d2017-03-15 14:26:04 +01003717 int ret;
Johannes Berg55682962007-09-20 13:09:35 -04003718
Johannes Berg5fe231e2013-05-08 21:45:15 +02003719 rtnl_lock();
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05003720 if (!cb->args[2]) {
3721 struct nl80211_dump_wiphy_state state = {
3722 .filter_wiphy = -1,
3723 };
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05003724
3725 ret = nl80211_dump_wiphy_parse(skb, cb, &state);
3726 if (ret)
Johannes Bergea90e0d2017-03-15 14:26:04 +01003727 goto out_unlock;
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05003728
3729 filter_wiphy = state.filter_wiphy;
3730
3731 /*
3732 * if filtering, set cb->args[2] to +1 since 0 is the default
3733 * value needed to determine that parsing is necessary.
3734 */
3735 if (filter_wiphy >= 0)
3736 cb->args[2] = filter_wiphy + 1;
3737 else
3738 cb->args[2] = -1;
3739 } else if (cb->args[2] > 0) {
3740 filter_wiphy = cb->args[2] - 1;
3741 }
3742
Johannes Bergf5ea9122009-08-07 16:17:38 +02003743 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
3744 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02003745 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02003746 if (wp_idx < wp_start) {
3747 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04003748 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02003749 }
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05003750
3751 if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx)
3752 continue;
3753
Johannes Berg55682962007-09-20 13:09:35 -04003754 if_idx = 0;
3755
Johannes Berg53873f12016-05-03 16:52:04 +03003756 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02003757 if (if_idx < if_start) {
3758 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04003759 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02003760 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00003761 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
Johannes Berg55682962007-09-20 13:09:35 -04003762 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003763 rdev, wdev,
3764 NL80211_CMD_NEW_INTERFACE) < 0) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02003765 goto out;
3766 }
3767 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04003768 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02003769
3770 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04003771 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02003772 out:
Johannes Berg55682962007-09-20 13:09:35 -04003773 cb->args[0] = wp_idx;
3774 cb->args[1] = if_idx;
3775
Johannes Bergea90e0d2017-03-15 14:26:04 +01003776 ret = skb->len;
3777 out_unlock:
3778 rtnl_unlock();
3779
3780 return ret;
Johannes Berg55682962007-09-20 13:09:35 -04003781}
3782
3783static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
3784{
3785 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08003786 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg72fb2ab2012-06-15 17:52:47 +02003787 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04003788
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07003789 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04003790 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02003791 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04003792
Eric W. Biederman15e47302012-09-07 20:12:54 +00003793 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003794 rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02003795 nlmsg_free(msg);
3796 return -ENOBUFS;
3797 }
Johannes Berg55682962007-09-20 13:09:35 -04003798
Johannes Berg134e6372009-07-10 09:51:34 +00003799 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04003800}
3801
Michael Wu66f7ac52008-01-31 19:48:22 +01003802static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
3803 [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
3804 [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
3805 [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
3806 [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
3807 [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
Felix Fietkaue057d3c2013-05-28 13:01:52 +02003808 [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
Michael Wu66f7ac52008-01-31 19:48:22 +01003809};
3810
3811static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
3812{
3813 struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
3814 int flag;
3815
3816 *mntrflags = 0;
3817
3818 if (!nla)
3819 return -EINVAL;
3820
Johannes Berg8cb08172019-04-26 14:07:28 +02003821 if (nla_parse_nested_deprecated(flags, NL80211_MNTR_FLAG_MAX, nla, mntr_flags_policy, NULL))
Michael Wu66f7ac52008-01-31 19:48:22 +01003822 return -EINVAL;
3823
3824 for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
3825 if (flags[flag])
3826 *mntrflags |= (1<<flag);
3827
Johannes Berg818a9862017-04-12 11:23:28 +02003828 *mntrflags |= MONITOR_FLAG_CHANGED;
3829
Michael Wu66f7ac52008-01-31 19:48:22 +01003830 return 0;
3831}
3832
Johannes Berg1db77592017-04-12 11:36:31 +02003833static int nl80211_parse_mon_options(struct cfg80211_registered_device *rdev,
3834 enum nl80211_iftype type,
3835 struct genl_info *info,
3836 struct vif_params *params)
3837{
3838 bool change = false;
3839 int err;
3840
3841 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
3842 if (type != NL80211_IFTYPE_MONITOR)
3843 return -EINVAL;
3844
3845 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
3846 &params->flags);
3847 if (err)
3848 return err;
3849
3850 change = true;
3851 }
3852
3853 if (params->flags & MONITOR_FLAG_ACTIVE &&
3854 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
3855 return -EOPNOTSUPP;
3856
3857 if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
3858 const u8 *mumimo_groups;
3859 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
3860
3861 if (type != NL80211_IFTYPE_MONITOR)
3862 return -EINVAL;
3863
3864 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
3865 return -EOPNOTSUPP;
3866
3867 mumimo_groups =
3868 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
3869
3870 /* bits 0 and 63 are reserved and must be zero */
Johannes Berg49546012017-04-27 09:13:38 +02003871 if ((mumimo_groups[0] & BIT(0)) ||
3872 (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(7)))
Johannes Berg1db77592017-04-12 11:36:31 +02003873 return -EINVAL;
3874
3875 params->vht_mumimo_groups = mumimo_groups;
3876 change = true;
3877 }
3878
3879 if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
3880 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
3881
3882 if (type != NL80211_IFTYPE_MONITOR)
3883 return -EINVAL;
3884
3885 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
3886 return -EOPNOTSUPP;
3887
3888 params->vht_mumimo_follow_addr =
3889 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]);
3890 change = true;
3891 }
3892
3893 return change ? 1 : 0;
3894}
3895
Johannes Berg9bc383d2009-11-19 11:55:19 +01003896static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003897 struct net_device *netdev, u8 use_4addr,
3898 enum nl80211_iftype iftype)
Johannes Berg9bc383d2009-11-19 11:55:19 +01003899{
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003900 if (!use_4addr) {
Julian Wiedmann2e92a2d2020-02-20 09:00:07 +01003901 if (netdev && netif_is_bridge_port(netdev))
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003902 return -EBUSY;
Johannes Berg9bc383d2009-11-19 11:55:19 +01003903 return 0;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003904 }
Johannes Berg9bc383d2009-11-19 11:55:19 +01003905
3906 switch (iftype) {
3907 case NL80211_IFTYPE_AP_VLAN:
3908 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
3909 return 0;
3910 break;
3911 case NL80211_IFTYPE_STATION:
3912 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
3913 return 0;
3914 break;
3915 default:
3916 break;
3917 }
3918
3919 return -EOPNOTSUPP;
3920}
3921
Johannes Berg55682962007-09-20 13:09:35 -04003922static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
3923{
Johannes Berg4c476992010-10-04 21:36:35 +02003924 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003925 struct vif_params params;
Johannes Berge36d56b2009-06-09 21:04:43 +02003926 int err;
Johannes Berg04a773a2009-04-19 21:24:32 +02003927 enum nl80211_iftype otype, ntype;
Johannes Berg4c476992010-10-04 21:36:35 +02003928 struct net_device *dev = info->user_ptr[1];
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003929 bool change = false;
Johannes Berg55682962007-09-20 13:09:35 -04003930
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003931 memset(&params, 0, sizeof(params));
3932
Johannes Berg04a773a2009-04-19 21:24:32 +02003933 otype = ntype = dev->ieee80211_ptr->iftype;
Johannes Berg55682962007-09-20 13:09:35 -04003934
Johannes Berg723b0382008-09-16 20:22:09 +02003935 if (info->attrs[NL80211_ATTR_IFTYPE]) {
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003936 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
Johannes Berg04a773a2009-04-19 21:24:32 +02003937 if (otype != ntype)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003938 change = true;
Johannes Berg723b0382008-09-16 20:22:09 +02003939 }
3940
Johannes Berg92ffe052008-09-16 20:39:36 +02003941 if (info->attrs[NL80211_ATTR_MESH_ID]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01003942 struct wireless_dev *wdev = dev->ieee80211_ptr;
3943
Johannes Berg4c476992010-10-04 21:36:35 +02003944 if (ntype != NL80211_IFTYPE_MESH_POINT)
3945 return -EINVAL;
Johannes Berg29cbe682010-12-03 09:20:44 +01003946 if (netif_running(dev))
3947 return -EBUSY;
3948
3949 wdev_lock(wdev);
3950 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
3951 IEEE80211_MAX_MESH_ID_LEN);
3952 wdev->mesh_id_up_len =
3953 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
3954 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
3955 wdev->mesh_id_up_len);
3956 wdev_unlock(wdev);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003957 }
3958
Felix Fietkau8b787642009-11-10 18:53:10 +01003959 if (info->attrs[NL80211_ATTR_4ADDR]) {
3960 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
3961 change = true;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003962 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
Johannes Berg9bc383d2009-11-19 11:55:19 +01003963 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02003964 return err;
Felix Fietkau8b787642009-11-10 18:53:10 +01003965 } else {
3966 params.use_4addr = -1;
3967 }
3968
Johannes Berg1db77592017-04-12 11:36:31 +02003969 err = nl80211_parse_mon_options(rdev, ntype, info, &params);
3970 if (err < 0)
3971 return err;
3972 if (err > 0)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003973 change = true;
Felix Fietkaue057d3c2013-05-28 13:01:52 +02003974
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003975 if (change)
Johannes Berg818a9862017-04-12 11:23:28 +02003976 err = cfg80211_change_iface(rdev, dev, ntype, &params);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01003977 else
3978 err = 0;
Johannes Berg60719ff2008-09-16 14:55:09 +02003979
Johannes Berg9bc383d2009-11-19 11:55:19 +01003980 if (!err && params.use_4addr != -1)
3981 dev->ieee80211_ptr->use_4addr = params.use_4addr;
3982
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02003983 if (change && !err) {
3984 struct wireless_dev *wdev = dev->ieee80211_ptr;
3985
3986 nl80211_notify_iface(rdev, wdev, NL80211_CMD_SET_INTERFACE);
3987 }
3988
Johannes Berg55682962007-09-20 13:09:35 -04003989 return err;
3990}
3991
Johannes Bergea6b2092021-04-27 11:49:52 +02003992static int _nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
Johannes Berg55682962007-09-20 13:09:35 -04003993{
Johannes Berg4c476992010-10-04 21:36:35 +02003994 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003995 struct vif_params params;
Johannes Berg84efbb82012-06-16 00:00:26 +02003996 struct wireless_dev *wdev;
Denis Kenzior896ff062016-08-03 16:58:33 -05003997 struct sk_buff *msg;
Johannes Berg55682962007-09-20 13:09:35 -04003998 int err;
3999 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
4000
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004001 memset(&params, 0, sizeof(params));
4002
Johannes Berg55682962007-09-20 13:09:35 -04004003 if (!info->attrs[NL80211_ATTR_IFNAME])
4004 return -EINVAL;
4005
Johannes Bergab0d76f2018-10-02 10:00:07 +02004006 if (info->attrs[NL80211_ATTR_IFTYPE])
Johannes Berg55682962007-09-20 13:09:35 -04004007 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
Johannes Berg55682962007-09-20 13:09:35 -04004008
Manikanta Pubbisetty33d915d2019-05-08 14:55:33 +05304009 if (!rdev->ops->add_virtual_intf)
Johannes Berg4c476992010-10-04 21:36:35 +02004010 return -EOPNOTSUPP;
Johannes Berg55682962007-09-20 13:09:35 -04004011
Ayala Bekercb3b7d82016-09-20 17:31:13 +03004012 if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
Ben Greeare8f479b2014-10-22 12:23:05 -07004013 rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
4014 info->attrs[NL80211_ATTR_MAC]) {
Arend van Spriel1c18f142013-01-08 10:17:27 +01004015 nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
4016 ETH_ALEN);
4017 if (!is_valid_ether_addr(params.macaddr))
4018 return -EADDRNOTAVAIL;
4019 }
4020
Johannes Berg9bc383d2009-11-19 11:55:19 +01004021 if (info->attrs[NL80211_ATTR_4ADDR]) {
Felix Fietkau8b787642009-11-10 18:53:10 +01004022 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
Johannes Bergad4bb6f2009-11-19 00:56:30 +01004023 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
Johannes Berg9bc383d2009-11-19 11:55:19 +01004024 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02004025 return err;
Johannes Berg9bc383d2009-11-19 11:55:19 +01004026 }
Felix Fietkau8b787642009-11-10 18:53:10 +01004027
Manikanta Pubbisettye6f40512019-07-22 12:44:50 +05304028 if (!cfg80211_iftype_allowed(&rdev->wiphy, type, params.use_4addr, 0))
Manikanta Pubbisetty33d915d2019-05-08 14:55:33 +05304029 return -EOPNOTSUPP;
4030
Johannes Berg1db77592017-04-12 11:36:31 +02004031 err = nl80211_parse_mon_options(rdev, type, info, &params);
4032 if (err < 0)
4033 return err;
Felix Fietkaue057d3c2013-05-28 13:01:52 +02004034
Johannes Berga18c7192015-02-24 10:56:42 +01004035 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4036 if (!msg)
4037 return -ENOMEM;
4038
Hila Gonene35e4d22012-06-27 17:19:42 +03004039 wdev = rdev_add_virtual_intf(rdev,
4040 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
Johannes Berg818a9862017-04-12 11:23:28 +02004041 NET_NAME_USER, type, &params);
Rafał Miłeckid687cbb2014-11-14 18:43:28 +01004042 if (WARN_ON(!wdev)) {
4043 nlmsg_free(msg);
4044 return -EPROTO;
4045 } else if (IS_ERR(wdev)) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02004046 nlmsg_free(msg);
Johannes Berg84efbb82012-06-16 00:00:26 +02004047 return PTR_ERR(wdev);
Johannes Berg1c90f9d2012-06-16 00:05:37 +02004048 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004049
Jukka Rissanen18e5ca62014-11-13 17:25:14 +02004050 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
Johannes Berg78f22b62014-03-24 17:57:27 +01004051 wdev->owner_nlportid = info->snd_portid;
4052
Johannes Berg98104fde2012-06-16 00:19:54 +02004053 switch (type) {
4054 case NL80211_IFTYPE_MESH_POINT:
4055 if (!info->attrs[NL80211_ATTR_MESH_ID])
4056 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01004057 wdev_lock(wdev);
4058 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
4059 IEEE80211_MAX_MESH_ID_LEN);
4060 wdev->mesh_id_up_len =
4061 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
4062 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
4063 wdev->mesh_id_up_len);
4064 wdev_unlock(wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +02004065 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03004066 case NL80211_IFTYPE_NAN:
Johannes Berg98104fde2012-06-16 00:19:54 +02004067 case NL80211_IFTYPE_P2P_DEVICE:
4068 /*
Ayala Bekercb3b7d82016-09-20 17:31:13 +03004069 * P2P Device and NAN do not have a netdev, so don't go
Johannes Berg98104fde2012-06-16 00:19:54 +02004070 * through the netdev notifier and must be added here
4071 */
Johannes Berg9bdaf3b2020-10-09 13:58:22 +02004072 cfg80211_init_wdev(wdev);
4073 cfg80211_register_wdev(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +02004074 break;
4075 default:
4076 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01004077 }
4078
Eric W. Biederman15e47302012-09-07 20:12:54 +00004079 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +02004080 rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02004081 nlmsg_free(msg);
4082 return -ENOBUFS;
4083 }
4084
4085 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04004086}
4087
Johannes Bergea6b2092021-04-27 11:49:52 +02004088static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
4089{
4090 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4091 int ret;
4092
4093 /* to avoid failing a new interface creation due to pending removal */
4094 cfg80211_destroy_ifaces(rdev);
4095
4096 wiphy_lock(&rdev->wiphy);
4097 ret = _nl80211_new_interface(skb, info);
4098 wiphy_unlock(&rdev->wiphy);
4099
4100 return ret;
4101}
4102
Johannes Berg55682962007-09-20 13:09:35 -04004103static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
4104{
Johannes Berg4c476992010-10-04 21:36:35 +02004105 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg84efbb82012-06-16 00:00:26 +02004106 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04004107
Johannes Berg4c476992010-10-04 21:36:35 +02004108 if (!rdev->ops->del_virtual_intf)
4109 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01004110
Johannes Berg84efbb82012-06-16 00:00:26 +02004111 /*
Johannes Berga05829a2021-01-22 16:19:43 +01004112 * We hold RTNL, so this is safe, without RTNL opencount cannot
4113 * reach 0, and thus the rdev cannot be deleted.
4114 *
4115 * We need to do it for the dev_close(), since that will call
4116 * the netdev notifiers, and we need to acquire the mutex there
4117 * but don't know if we get there from here or from some other
4118 * place (e.g. "ip link set ... down").
4119 */
4120 mutex_unlock(&rdev->wiphy.mtx);
4121
4122 /*
Johannes Berg84efbb82012-06-16 00:00:26 +02004123 * If we remove a wireless device without a netdev then clear
4124 * user_ptr[1] so that nl80211_post_doit won't dereference it
4125 * to check if it needs to do dev_put(). Otherwise it crashes
4126 * since the wdev has been freed, unlike with a netdev where
4127 * we need the dev_put() for the netdev to really be freed.
4128 */
4129 if (!wdev->netdev)
4130 info->user_ptr[1] = NULL;
Johannes Berga05829a2021-01-22 16:19:43 +01004131 else
4132 dev_close(wdev->netdev);
4133
4134 mutex_lock(&rdev->wiphy.mtx);
Johannes Berg84efbb82012-06-16 00:00:26 +02004135
Denis Kenzior7f8ed012016-08-03 16:58:35 -05004136 return rdev_del_virtual_intf(rdev, wdev);
Johannes Berg55682962007-09-20 13:09:35 -04004137}
4138
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01004139static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
4140{
4141 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4142 struct net_device *dev = info->user_ptr[1];
4143 u16 noack_map;
4144
4145 if (!info->attrs[NL80211_ATTR_NOACK_MAP])
4146 return -EINVAL;
4147
4148 if (!rdev->ops->set_noack_map)
4149 return -EOPNOTSUPP;
4150
4151 noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
4152
Hila Gonene35e4d22012-06-27 17:19:42 +03004153 return rdev_set_noack_map(rdev, dev, noack_map);
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01004154}
4155
Johannes Berg41ade002007-12-19 02:03:29 +01004156struct get_key_cookie {
4157 struct sk_buff *msg;
4158 int error;
Johannes Bergb9454e82009-07-08 13:29:08 +02004159 int idx;
Johannes Berg41ade002007-12-19 02:03:29 +01004160};
4161
4162static void get_key_callback(void *c, struct key_params *params)
4163{
Johannes Bergb9454e82009-07-08 13:29:08 +02004164 struct nlattr *key;
Johannes Berg41ade002007-12-19 02:03:29 +01004165 struct get_key_cookie *cookie = c;
4166
David S. Miller9360ffd2012-03-29 04:41:26 -04004167 if ((params->key &&
4168 nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
4169 params->key_len, params->key)) ||
4170 (params->seq &&
4171 nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
4172 params->seq_len, params->seq)) ||
4173 (params->cipher &&
4174 nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
4175 params->cipher)))
4176 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01004177
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004178 key = nla_nest_start_noflag(cookie->msg, NL80211_ATTR_KEY);
Johannes Bergb9454e82009-07-08 13:29:08 +02004179 if (!key)
4180 goto nla_put_failure;
4181
David S. Miller9360ffd2012-03-29 04:41:26 -04004182 if ((params->key &&
4183 nla_put(cookie->msg, NL80211_KEY_DATA,
4184 params->key_len, params->key)) ||
4185 (params->seq &&
4186 nla_put(cookie->msg, NL80211_KEY_SEQ,
4187 params->seq_len, params->seq)) ||
4188 (params->cipher &&
4189 nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
4190 params->cipher)))
4191 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02004192
Andrew Zaborowskiefdfce72018-09-24 18:10:22 +02004193 if (nla_put_u8(cookie->msg, NL80211_KEY_IDX, cookie->idx))
David S. Miller9360ffd2012-03-29 04:41:26 -04004194 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02004195
4196 nla_nest_end(cookie->msg, key);
4197
Johannes Berg41ade002007-12-19 02:03:29 +01004198 return;
4199 nla_put_failure:
4200 cookie->error = 1;
4201}
4202
4203static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
4204{
Johannes Berg4c476992010-10-04 21:36:35 +02004205 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01004206 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004207 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01004208 u8 key_idx = 0;
Johannes Berge31b8212010-10-05 19:39:30 +02004209 const u8 *mac_addr = NULL;
4210 bool pairwise;
Johannes Berg41ade002007-12-19 02:03:29 +01004211 struct get_key_cookie cookie = {
4212 .error = 0,
4213 };
4214 void *hdr;
4215 struct sk_buff *msg;
Johannes Berg155d7c72020-04-20 14:06:00 +02004216 bool bigtk_support = false;
4217
4218 if (wiphy_ext_feature_isset(&rdev->wiphy,
4219 NL80211_EXT_FEATURE_BEACON_PROTECTION))
4220 bigtk_support = true;
4221
4222 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
4223 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
4224 wiphy_ext_feature_isset(&rdev->wiphy,
4225 NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
4226 bigtk_support = true;
Johannes Berg41ade002007-12-19 02:03:29 +01004227
Jouni Malinen56be3932020-02-22 15:25:43 +02004228 if (info->attrs[NL80211_ATTR_KEY_IDX]) {
Johannes Berg41ade002007-12-19 02:03:29 +01004229 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
Johannes Berg155d7c72020-04-20 14:06:00 +02004230
4231 if (key_idx >= 6 && key_idx <= 7 && !bigtk_support) {
4232 GENL_SET_ERR_MSG(info, "BIGTK not supported");
Jouni Malinen56be3932020-02-22 15:25:43 +02004233 return -EINVAL;
Johannes Berg155d7c72020-04-20 14:06:00 +02004234 }
Jouni Malinen56be3932020-02-22 15:25:43 +02004235 }
Johannes Berg41ade002007-12-19 02:03:29 +01004236
Johannes Berg41ade002007-12-19 02:03:29 +01004237 if (info->attrs[NL80211_ATTR_MAC])
4238 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4239
Johannes Berge31b8212010-10-05 19:39:30 +02004240 pairwise = !!mac_addr;
4241 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
4242 u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07004243
Johannes Berge31b8212010-10-05 19:39:30 +02004244 if (kt != NL80211_KEYTYPE_GROUP &&
4245 kt != NL80211_KEYTYPE_PAIRWISE)
4246 return -EINVAL;
4247 pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
4248 }
4249
Johannes Berg4c476992010-10-04 21:36:35 +02004250 if (!rdev->ops->get_key)
4251 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01004252
Johannes Berg0fa7b392015-01-23 11:10:12 +01004253 if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
4254 return -ENOENT;
4255
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07004256 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02004257 if (!msg)
4258 return -ENOMEM;
Johannes Berg41ade002007-12-19 02:03:29 +01004259
Eric W. Biederman15e47302012-09-07 20:12:54 +00004260 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg41ade002007-12-19 02:03:29 +01004261 NL80211_CMD_NEW_KEY);
Dan Carpentercb35fba2013-08-14 14:50:01 +03004262 if (!hdr)
Johannes Berg9fe271a2013-10-25 11:15:12 +02004263 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01004264
4265 cookie.msg = msg;
Johannes Bergb9454e82009-07-08 13:29:08 +02004266 cookie.idx = key_idx;
Johannes Berg41ade002007-12-19 02:03:29 +01004267
David S. Miller9360ffd2012-03-29 04:41:26 -04004268 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
4269 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
4270 goto nla_put_failure;
4271 if (mac_addr &&
4272 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
4273 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01004274
Hila Gonene35e4d22012-06-27 17:19:42 +03004275 err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
4276 get_key_callback);
Johannes Berg41ade002007-12-19 02:03:29 +01004277
4278 if (err)
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03004279 goto free_msg;
Johannes Berg41ade002007-12-19 02:03:29 +01004280
4281 if (cookie.error)
4282 goto nla_put_failure;
4283
4284 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02004285 return genlmsg_reply(msg, info);
Johannes Berg41ade002007-12-19 02:03:29 +01004286
4287 nla_put_failure:
4288 err = -ENOBUFS;
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03004289 free_msg:
Johannes Berg41ade002007-12-19 02:03:29 +01004290 nlmsg_free(msg);
Johannes Berg41ade002007-12-19 02:03:29 +01004291 return err;
4292}
4293
4294static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
4295{
Johannes Berg4c476992010-10-04 21:36:35 +02004296 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergb9454e82009-07-08 13:29:08 +02004297 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01004298 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004299 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01004300
Johannes Bergb9454e82009-07-08 13:29:08 +02004301 err = nl80211_parse_key(info, &key);
4302 if (err)
4303 return err;
4304
4305 if (key.idx < 0)
Johannes Berg41ade002007-12-19 02:03:29 +01004306 return -EINVAL;
4307
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01004308 /* Only support setting default key and
4309 * Extended Key ID action NL80211_KEY_SET_TX.
4310 */
Jouni Malinen56be3932020-02-22 15:25:43 +02004311 if (!key.def && !key.defmgmt && !key.defbeacon &&
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01004312 !(key.p.mode == NL80211_KEY_SET_TX))
Johannes Berg41ade002007-12-19 02:03:29 +01004313 return -EINVAL;
4314
Johannes Bergfffd0932009-07-08 14:22:54 +02004315 wdev_lock(dev->ieee80211_ptr);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004316
4317 if (key.def) {
4318 if (!rdev->ops->set_default_key) {
4319 err = -EOPNOTSUPP;
4320 goto out;
4321 }
4322
4323 err = nl80211_key_allowed(dev->ieee80211_ptr);
4324 if (err)
4325 goto out;
4326
Hila Gonene35e4d22012-06-27 17:19:42 +03004327 err = rdev_set_default_key(rdev, dev, key.idx,
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004328 key.def_uni, key.def_multi);
4329
4330 if (err)
4331 goto out;
Johannes Bergfffd0932009-07-08 14:22:54 +02004332
Johannes Berg3d23e342009-09-29 23:27:28 +02004333#ifdef CONFIG_CFG80211_WEXT
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004334 dev->ieee80211_ptr->wext.default_key = key.idx;
Johannes Berg08645122009-05-11 13:54:58 +02004335#endif
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01004336 } else if (key.defmgmt) {
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004337 if (key.def_uni || !key.def_multi) {
4338 err = -EINVAL;
4339 goto out;
4340 }
4341
4342 if (!rdev->ops->set_default_mgmt_key) {
4343 err = -EOPNOTSUPP;
4344 goto out;
4345 }
4346
4347 err = nl80211_key_allowed(dev->ieee80211_ptr);
4348 if (err)
4349 goto out;
4350
Hila Gonene35e4d22012-06-27 17:19:42 +03004351 err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004352 if (err)
4353 goto out;
4354
4355#ifdef CONFIG_CFG80211_WEXT
4356 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
4357#endif
Jouni Malinen56be3932020-02-22 15:25:43 +02004358 } else if (key.defbeacon) {
4359 if (key.def_uni || !key.def_multi) {
4360 err = -EINVAL;
4361 goto out;
4362 }
4363
4364 if (!rdev->ops->set_default_beacon_key) {
4365 err = -EOPNOTSUPP;
4366 goto out;
4367 }
4368
4369 err = nl80211_key_allowed(dev->ieee80211_ptr);
4370 if (err)
4371 goto out;
4372
4373 err = rdev_set_default_beacon_key(rdev, dev, key.idx);
4374 if (err)
4375 goto out;
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01004376 } else if (key.p.mode == NL80211_KEY_SET_TX &&
4377 wiphy_ext_feature_isset(&rdev->wiphy,
4378 NL80211_EXT_FEATURE_EXT_KEY_ID)) {
4379 u8 *mac_addr = NULL;
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004380
Alexander Wetzel6cdd3972019-03-19 21:34:07 +01004381 if (info->attrs[NL80211_ATTR_MAC])
4382 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4383
4384 if (!mac_addr || key.idx < 0 || key.idx > 1) {
4385 err = -EINVAL;
4386 goto out;
4387 }
4388
4389 err = rdev_add_key(rdev, dev, key.idx,
4390 NL80211_KEYTYPE_PAIRWISE,
4391 mac_addr, &key.p);
4392 } else {
4393 err = -EINVAL;
4394 }
Johannes Bergdbd2fd62010-12-09 19:58:59 +01004395 out:
Johannes Bergfffd0932009-07-08 14:22:54 +02004396 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01004397
Johannes Berg41ade002007-12-19 02:03:29 +01004398 return err;
4399}
4400
4401static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
4402{
Johannes Berg4c476992010-10-04 21:36:35 +02004403 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfffd0932009-07-08 14:22:54 +02004404 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004405 struct net_device *dev = info->user_ptr[1];
Johannes Bergb9454e82009-07-08 13:29:08 +02004406 struct key_parse key;
Johannes Berge31b8212010-10-05 19:39:30 +02004407 const u8 *mac_addr = NULL;
Johannes Berg41ade002007-12-19 02:03:29 +01004408
Johannes Bergb9454e82009-07-08 13:29:08 +02004409 err = nl80211_parse_key(info, &key);
4410 if (err)
4411 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01004412
Jouni Malinenf8af7642020-02-22 15:25:42 +02004413 if (!key.p.key) {
4414 GENL_SET_ERR_MSG(info, "no key");
Johannes Berg41ade002007-12-19 02:03:29 +01004415 return -EINVAL;
Jouni Malinenf8af7642020-02-22 15:25:42 +02004416 }
Johannes Berg41ade002007-12-19 02:03:29 +01004417
Johannes Berg41ade002007-12-19 02:03:29 +01004418 if (info->attrs[NL80211_ATTR_MAC])
4419 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4420
Johannes Berge31b8212010-10-05 19:39:30 +02004421 if (key.type == -1) {
4422 if (mac_addr)
4423 key.type = NL80211_KEYTYPE_PAIRWISE;
4424 else
4425 key.type = NL80211_KEYTYPE_GROUP;
4426 }
4427
4428 /* for now */
4429 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
Jouni Malinenf8af7642020-02-22 15:25:42 +02004430 key.type != NL80211_KEYTYPE_GROUP) {
4431 GENL_SET_ERR_MSG(info, "key type not pairwise or group");
Johannes Berge31b8212010-10-05 19:39:30 +02004432 return -EINVAL;
Jouni Malinenf8af7642020-02-22 15:25:42 +02004433 }
Johannes Berge31b8212010-10-05 19:39:30 +02004434
Gurumoorthi Gnanasambandhan14f34e362019-10-31 23:46:40 +02004435 if (key.type == NL80211_KEYTYPE_GROUP &&
4436 info->attrs[NL80211_ATTR_VLAN_ID])
4437 key.p.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);
4438
Johannes Berg4c476992010-10-04 21:36:35 +02004439 if (!rdev->ops->add_key)
4440 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01004441
Johannes Berge31b8212010-10-05 19:39:30 +02004442 if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
4443 key.type == NL80211_KEYTYPE_PAIRWISE,
Jouni Malinenf8af7642020-02-22 15:25:42 +02004444 mac_addr)) {
4445 GENL_SET_ERR_MSG(info, "key setting validation failed");
Johannes Berg4c476992010-10-04 21:36:35 +02004446 return -EINVAL;
Jouni Malinenf8af7642020-02-22 15:25:42 +02004447 }
Johannes Bergfffd0932009-07-08 14:22:54 +02004448
4449 wdev_lock(dev->ieee80211_ptr);
4450 err = nl80211_key_allowed(dev->ieee80211_ptr);
Jouni Malinenf8af7642020-02-22 15:25:42 +02004451 if (err)
4452 GENL_SET_ERR_MSG(info, "key not allowed");
4453 if (!err) {
Hila Gonene35e4d22012-06-27 17:19:42 +03004454 err = rdev_add_key(rdev, dev, key.idx,
4455 key.type == NL80211_KEYTYPE_PAIRWISE,
4456 mac_addr, &key.p);
Jouni Malinenf8af7642020-02-22 15:25:42 +02004457 if (err)
4458 GENL_SET_ERR_MSG(info, "key addition failed");
4459 }
Johannes Bergfffd0932009-07-08 14:22:54 +02004460 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01004461
Johannes Berg41ade002007-12-19 02:03:29 +01004462 return err;
4463}
4464
4465static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
4466{
Johannes Berg4c476992010-10-04 21:36:35 +02004467 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01004468 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004469 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01004470 u8 *mac_addr = NULL;
Johannes Bergb9454e82009-07-08 13:29:08 +02004471 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01004472
Johannes Bergb9454e82009-07-08 13:29:08 +02004473 err = nl80211_parse_key(info, &key);
4474 if (err)
4475 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01004476
4477 if (info->attrs[NL80211_ATTR_MAC])
4478 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4479
Johannes Berge31b8212010-10-05 19:39:30 +02004480 if (key.type == -1) {
4481 if (mac_addr)
4482 key.type = NL80211_KEYTYPE_PAIRWISE;
4483 else
4484 key.type = NL80211_KEYTYPE_GROUP;
4485 }
4486
4487 /* for now */
4488 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
4489 key.type != NL80211_KEYTYPE_GROUP)
4490 return -EINVAL;
4491
Anant Thazhemadam2d946302020-12-05 03:28:25 +05304492 if (!cfg80211_valid_key_idx(rdev, key.idx,
4493 key.type == NL80211_KEYTYPE_PAIRWISE))
4494 return -EINVAL;
4495
Johannes Berg4c476992010-10-04 21:36:35 +02004496 if (!rdev->ops->del_key)
4497 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01004498
Johannes Bergfffd0932009-07-08 14:22:54 +02004499 wdev_lock(dev->ieee80211_ptr);
4500 err = nl80211_key_allowed(dev->ieee80211_ptr);
Johannes Berge31b8212010-10-05 19:39:30 +02004501
Johannes Berg0fa7b392015-01-23 11:10:12 +01004502 if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
Johannes Berge31b8212010-10-05 19:39:30 +02004503 !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
4504 err = -ENOENT;
4505
Johannes Bergfffd0932009-07-08 14:22:54 +02004506 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03004507 err = rdev_del_key(rdev, dev, key.idx,
4508 key.type == NL80211_KEYTYPE_PAIRWISE,
4509 mac_addr);
Johannes Berg41ade002007-12-19 02:03:29 +01004510
Johannes Berg3d23e342009-09-29 23:27:28 +02004511#ifdef CONFIG_CFG80211_WEXT
Johannes Berg08645122009-05-11 13:54:58 +02004512 if (!err) {
Johannes Bergb9454e82009-07-08 13:29:08 +02004513 if (key.idx == dev->ieee80211_ptr->wext.default_key)
Johannes Berg08645122009-05-11 13:54:58 +02004514 dev->ieee80211_ptr->wext.default_key = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +02004515 else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
Johannes Berg08645122009-05-11 13:54:58 +02004516 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
4517 }
4518#endif
Johannes Bergfffd0932009-07-08 14:22:54 +02004519 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg08645122009-05-11 13:54:58 +02004520
Johannes Berg41ade002007-12-19 02:03:29 +01004521 return err;
4522}
4523
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05304524/* This function returns an error or the number of nested attributes */
4525static int validate_acl_mac_addrs(struct nlattr *nl_attr)
4526{
4527 struct nlattr *attr;
4528 int n_entries = 0, tmp;
4529
4530 nla_for_each_nested(attr, nl_attr, tmp) {
4531 if (nla_len(attr) != ETH_ALEN)
4532 return -EINVAL;
4533
4534 n_entries++;
4535 }
4536
4537 return n_entries;
4538}
4539
4540/*
4541 * This function parses ACL information and allocates memory for ACL data.
4542 * On successful return, the calling function is responsible to free the
4543 * ACL buffer returned by this function.
4544 */
4545static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
4546 struct genl_info *info)
4547{
4548 enum nl80211_acl_policy acl_policy;
4549 struct nlattr *attr;
4550 struct cfg80211_acl_data *acl;
4551 int i = 0, n_entries, tmp;
4552
4553 if (!wiphy->max_acl_mac_addrs)
4554 return ERR_PTR(-EOPNOTSUPP);
4555
4556 if (!info->attrs[NL80211_ATTR_ACL_POLICY])
4557 return ERR_PTR(-EINVAL);
4558
4559 acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
4560 if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
4561 acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
4562 return ERR_PTR(-EINVAL);
4563
4564 if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
4565 return ERR_PTR(-EINVAL);
4566
4567 n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
4568 if (n_entries < 0)
4569 return ERR_PTR(n_entries);
4570
4571 if (n_entries > wiphy->max_acl_mac_addrs)
4572 return ERR_PTR(-ENOTSUPP);
4573
Gustavo A. R. Silva391d1322019-04-03 10:37:44 -05004574 acl = kzalloc(struct_size(acl, mac_addrs, n_entries), GFP_KERNEL);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05304575 if (!acl)
4576 return ERR_PTR(-ENOMEM);
4577
4578 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
4579 memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
4580 i++;
4581 }
4582
4583 acl->n_acl_entries = n_entries;
4584 acl->acl_policy = acl_policy;
4585
4586 return acl;
4587}
4588
4589static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
4590{
4591 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4592 struct net_device *dev = info->user_ptr[1];
4593 struct cfg80211_acl_data *acl;
4594 int err;
4595
4596 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4597 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4598 return -EOPNOTSUPP;
4599
4600 if (!dev->ieee80211_ptr->beacon_interval)
4601 return -EINVAL;
4602
4603 acl = parse_acl_data(&rdev->wiphy, info);
4604 if (IS_ERR(acl))
4605 return PTR_ERR(acl);
4606
4607 err = rdev_set_mac_acl(rdev, dev, acl);
4608
4609 kfree(acl);
4610
4611 return err;
4612}
4613
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304614static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
4615 u8 *rates, u8 rates_len)
4616{
4617 u8 i;
4618 u32 mask = 0;
4619
4620 for (i = 0; i < rates_len; i++) {
4621 int rate = (rates[i] & 0x7f) * 5;
4622 int ridx;
4623
4624 for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
4625 struct ieee80211_rate *srate =
4626 &sband->bitrates[ridx];
4627 if (rate == srate->bitrate) {
4628 mask |= 1 << ridx;
4629 break;
4630 }
4631 }
4632 if (ridx == sband->n_bitrates)
4633 return 0; /* rate not found */
4634 }
4635
4636 return mask;
4637}
4638
4639static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
4640 u8 *rates, u8 rates_len,
4641 u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
4642{
4643 u8 i;
4644
4645 memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
4646
4647 for (i = 0; i < rates_len; i++) {
4648 int ridx, rbit;
4649
4650 ridx = rates[i] / 8;
4651 rbit = BIT(rates[i] % 8);
4652
4653 /* check validity */
4654 if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
4655 return false;
4656
4657 /* check availability */
Masashi Honma30fe6d52018-09-25 11:15:00 +09004658 ridx = array_index_nospec(ridx, IEEE80211_HT_MCS_MASK_LEN);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304659 if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
4660 mcs[ridx] |= rbit;
4661 else
4662 return false;
4663 }
4664
4665 return true;
4666}
4667
4668static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
4669{
4670 u16 mcs_mask = 0;
4671
4672 switch (vht_mcs_map) {
4673 case IEEE80211_VHT_MCS_NOT_SUPPORTED:
4674 break;
4675 case IEEE80211_VHT_MCS_SUPPORT_0_7:
4676 mcs_mask = 0x00FF;
4677 break;
4678 case IEEE80211_VHT_MCS_SUPPORT_0_8:
4679 mcs_mask = 0x01FF;
4680 break;
4681 case IEEE80211_VHT_MCS_SUPPORT_0_9:
4682 mcs_mask = 0x03FF;
4683 break;
4684 default:
4685 break;
4686 }
4687
4688 return mcs_mask;
4689}
4690
4691static void vht_build_mcs_mask(u16 vht_mcs_map,
4692 u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
4693{
4694 u8 nss;
4695
4696 for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
4697 vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
4698 vht_mcs_map >>= 2;
4699 }
4700}
4701
4702static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
4703 struct nl80211_txrate_vht *txrate,
4704 u16 mcs[NL80211_VHT_NSS_MAX])
4705{
4706 u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
4707 u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
4708 u8 i;
4709
4710 if (!sband->vht_cap.vht_supported)
4711 return false;
4712
4713 memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
4714
4715 /* Build vht_mcs_mask from VHT capabilities */
4716 vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
4717
4718 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
4719 if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
4720 mcs[i] = txrate->mcs[i];
4721 else
4722 return false;
4723 }
4724
4725 return true;
4726}
4727
Miles Hueb89a6a2020-08-04 10:16:29 +02004728static u16 he_mcs_map_to_mcs_mask(u8 he_mcs_map)
4729{
4730 switch (he_mcs_map) {
4731 case IEEE80211_HE_MCS_NOT_SUPPORTED:
4732 return 0;
4733 case IEEE80211_HE_MCS_SUPPORT_0_7:
4734 return 0x00FF;
4735 case IEEE80211_HE_MCS_SUPPORT_0_9:
4736 return 0x03FF;
4737 case IEEE80211_HE_MCS_SUPPORT_0_11:
4738 return 0xFFF;
4739 default:
4740 break;
4741 }
4742 return 0;
4743}
4744
4745static void he_build_mcs_mask(u16 he_mcs_map,
4746 u16 he_mcs_mask[NL80211_HE_NSS_MAX])
4747{
4748 u8 nss;
4749
4750 for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) {
4751 he_mcs_mask[nss] = he_mcs_map_to_mcs_mask(he_mcs_map & 0x03);
4752 he_mcs_map >>= 2;
4753 }
4754}
4755
4756static u16 he_get_txmcsmap(struct genl_info *info,
4757 const struct ieee80211_sta_he_cap *he_cap)
4758{
4759 struct net_device *dev = info->user_ptr[1];
4760 struct wireless_dev *wdev = dev->ieee80211_ptr;
4761 __le16 tx_mcs;
4762
4763 switch (wdev->chandef.width) {
4764 case NL80211_CHAN_WIDTH_80P80:
4765 tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_80p80;
4766 break;
4767 case NL80211_CHAN_WIDTH_160:
4768 tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_160;
4769 break;
4770 default:
4771 tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_80;
4772 break;
4773 }
4774 return le16_to_cpu(tx_mcs);
4775}
4776
4777static bool he_set_mcs_mask(struct genl_info *info,
4778 struct wireless_dev *wdev,
4779 struct ieee80211_supported_band *sband,
4780 struct nl80211_txrate_he *txrate,
4781 u16 mcs[NL80211_HE_NSS_MAX])
4782{
4783 const struct ieee80211_sta_he_cap *he_cap;
4784 u16 tx_mcs_mask[NL80211_HE_NSS_MAX] = {};
4785 u16 tx_mcs_map = 0;
4786 u8 i;
4787
4788 he_cap = ieee80211_get_he_iftype_cap(sband, wdev->iftype);
4789 if (!he_cap)
4790 return false;
4791
4792 memset(mcs, 0, sizeof(u16) * NL80211_HE_NSS_MAX);
4793
4794 tx_mcs_map = he_get_txmcsmap(info, he_cap);
4795
4796 /* Build he_mcs_mask from HE capabilities */
4797 he_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
4798
4799 for (i = 0; i < NL80211_HE_NSS_MAX; i++) {
4800 if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
4801 mcs[i] = txrate->mcs[i];
4802 else
4803 return false;
4804 }
4805
4806 return true;
4807}
4808
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304809static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +05304810 struct nlattr *attrs[],
4811 enum nl80211_attrs attr,
Miles Hueb89a6a2020-08-04 10:16:29 +02004812 struct cfg80211_bitrate_mask *mask,
Rajkumar Manoharan857b34c2020-10-16 13:15:26 -07004813 struct net_device *dev,
4814 bool default_all_enabled)
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304815{
4816 struct nlattr *tb[NL80211_TXRATE_MAX + 1];
4817 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Miles Hueb89a6a2020-08-04 10:16:29 +02004818 struct wireless_dev *wdev = dev->ieee80211_ptr;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304819 int rem, i;
4820 struct nlattr *tx_rates;
4821 struct ieee80211_supported_band *sband;
Miles Hueb89a6a2020-08-04 10:16:29 +02004822 u16 vht_tx_mcs_map, he_tx_mcs_map;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304823
4824 memset(mask, 0, sizeof(*mask));
4825 /* Default to all rates enabled */
4826 for (i = 0; i < NUM_NL80211_BANDS; i++) {
Miles Hueb89a6a2020-08-04 10:16:29 +02004827 const struct ieee80211_sta_he_cap *he_cap;
4828
Rajkumar Manoharan857b34c2020-10-16 13:15:26 -07004829 if (!default_all_enabled)
4830 break;
4831
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304832 sband = rdev->wiphy.bands[i];
4833
4834 if (!sband)
4835 continue;
4836
4837 mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
4838 memcpy(mask->control[i].ht_mcs,
4839 sband->ht_cap.mcs.rx_mask,
4840 sizeof(mask->control[i].ht_mcs));
4841
Ping-Ke Shih9df66d52021-06-09 15:59:44 +08004842 if (sband->vht_cap.vht_supported) {
4843 vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
4844 vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
4845 }
Miles Hueb89a6a2020-08-04 10:16:29 +02004846
4847 he_cap = ieee80211_get_he_iftype_cap(sband, wdev->iftype);
4848 if (!he_cap)
4849 continue;
4850
4851 he_tx_mcs_map = he_get_txmcsmap(info, he_cap);
4852 he_build_mcs_mask(he_tx_mcs_map, mask->control[i].he_mcs);
4853
4854 mask->control[i].he_gi = 0xFF;
4855 mask->control[i].he_ltf = 0xFF;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304856 }
4857
4858 /* if no rates are given set it back to the defaults */
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +05304859 if (!attrs[attr])
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304860 goto out;
4861
4862 /* The nested attribute uses enum nl80211_band as the index. This maps
4863 * directly to the enum nl80211_band values used in cfg80211.
4864 */
4865 BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +05304866 nla_for_each_nested(tx_rates, attrs[attr], rem) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304867 enum nl80211_band band = nla_type(tx_rates);
4868 int err;
4869
4870 if (band < 0 || band >= NUM_NL80211_BANDS)
4871 return -EINVAL;
4872 sband = rdev->wiphy.bands[band];
4873 if (sband == NULL)
4874 return -EINVAL;
Johannes Berg8cb08172019-04-26 14:07:28 +02004875 err = nla_parse_nested_deprecated(tb, NL80211_TXRATE_MAX,
4876 tx_rates,
4877 nl80211_txattr_policy,
4878 info->extack);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304879 if (err)
4880 return err;
4881 if (tb[NL80211_TXRATE_LEGACY]) {
4882 mask->control[band].legacy = rateset_to_mask(
4883 sband,
4884 nla_data(tb[NL80211_TXRATE_LEGACY]),
4885 nla_len(tb[NL80211_TXRATE_LEGACY]));
4886 if ((mask->control[band].legacy == 0) &&
4887 nla_len(tb[NL80211_TXRATE_LEGACY]))
4888 return -EINVAL;
4889 }
4890 if (tb[NL80211_TXRATE_HT]) {
4891 if (!ht_rateset_to_mask(
4892 sband,
4893 nla_data(tb[NL80211_TXRATE_HT]),
4894 nla_len(tb[NL80211_TXRATE_HT]),
4895 mask->control[band].ht_mcs))
4896 return -EINVAL;
4897 }
Rajkumar Manoharanc4a30442020-10-16 13:15:27 -07004898
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304899 if (tb[NL80211_TXRATE_VHT]) {
4900 if (!vht_set_mcs_mask(
4901 sband,
4902 nla_data(tb[NL80211_TXRATE_VHT]),
4903 mask->control[band].vht_mcs))
4904 return -EINVAL;
4905 }
Rajkumar Manoharanc4a30442020-10-16 13:15:27 -07004906
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304907 if (tb[NL80211_TXRATE_GI]) {
4908 mask->control[band].gi =
4909 nla_get_u8(tb[NL80211_TXRATE_GI]);
4910 if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
4911 return -EINVAL;
4912 }
Miles Hueb89a6a2020-08-04 10:16:29 +02004913 if (tb[NL80211_TXRATE_HE] &&
4914 !he_set_mcs_mask(info, wdev, sband,
4915 nla_data(tb[NL80211_TXRATE_HE]),
4916 mask->control[band].he_mcs))
4917 return -EINVAL;
Rajkumar Manoharanc4a30442020-10-16 13:15:27 -07004918
Miles Hueb89a6a2020-08-04 10:16:29 +02004919 if (tb[NL80211_TXRATE_HE_GI])
4920 mask->control[band].he_gi =
4921 nla_get_u8(tb[NL80211_TXRATE_HE_GI]);
4922 if (tb[NL80211_TXRATE_HE_LTF])
4923 mask->control[band].he_ltf =
4924 nla_get_u8(tb[NL80211_TXRATE_HE_LTF]);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304925
4926 if (mask->control[band].legacy == 0) {
Miles Hueb89a6a2020-08-04 10:16:29 +02004927 /* don't allow empty legacy rates if HT, VHT or HE
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304928 * are not even supported.
4929 */
4930 if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
Miles Hueb89a6a2020-08-04 10:16:29 +02004931 rdev->wiphy.bands[band]->vht_cap.vht_supported ||
4932 ieee80211_get_he_iftype_cap(sband, wdev->iftype)))
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304933 return -EINVAL;
4934
4935 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
4936 if (mask->control[band].ht_mcs[i])
4937 goto out;
4938
4939 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
4940 if (mask->control[band].vht_mcs[i])
4941 goto out;
4942
Miles Hueb89a6a2020-08-04 10:16:29 +02004943 for (i = 0; i < NL80211_HE_NSS_MAX; i++)
4944 if (mask->control[band].he_mcs[i])
4945 goto out;
4946
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304947 /* legacy and mcs rates may not be both empty */
4948 return -EINVAL;
4949 }
4950 }
4951
4952out:
4953 return 0;
4954}
4955
Johannes Berg8564e382016-09-19 09:44:44 +02004956static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
4957 enum nl80211_band band,
4958 struct cfg80211_bitrate_mask *beacon_rate)
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304959{
Rajkumar Manoharanc4a30442020-10-16 13:15:27 -07004960 u32 count_ht, count_vht, count_he, i;
Johannes Berg8564e382016-09-19 09:44:44 +02004961 u32 rate = beacon_rate->control[band].legacy;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304962
4963 /* Allow only one rate */
4964 if (hweight32(rate) > 1)
4965 return -EINVAL;
4966
4967 count_ht = 0;
4968 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02004969 if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304970 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02004971 } else if (beacon_rate->control[band].ht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304972 count_ht++;
4973 if (count_ht > 1)
4974 return -EINVAL;
4975 }
4976 if (count_ht && rate)
4977 return -EINVAL;
4978 }
4979
4980 count_vht = 0;
4981 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02004982 if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304983 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02004984 } else if (beacon_rate->control[band].vht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304985 count_vht++;
4986 if (count_vht > 1)
4987 return -EINVAL;
4988 }
4989 if (count_vht && rate)
4990 return -EINVAL;
4991 }
4992
Rajkumar Manoharanc4a30442020-10-16 13:15:27 -07004993 count_he = 0;
4994 for (i = 0; i < NL80211_HE_NSS_MAX; i++) {
4995 if (hweight16(beacon_rate->control[band].he_mcs[i]) > 1) {
4996 return -EINVAL;
4997 } else if (beacon_rate->control[band].he_mcs[i]) {
4998 count_he++;
4999 if (count_he > 1)
5000 return -EINVAL;
5001 }
5002 if (count_he && rate)
5003 return -EINVAL;
5004 }
5005
5006 if ((count_ht && count_vht && count_he) ||
5007 (!rate && !count_ht && !count_vht && !count_he))
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05305008 return -EINVAL;
5009
Johannes Berg8564e382016-09-19 09:44:44 +02005010 if (rate &&
5011 !wiphy_ext_feature_isset(&rdev->wiphy,
5012 NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
5013 return -EINVAL;
5014 if (count_ht &&
5015 !wiphy_ext_feature_isset(&rdev->wiphy,
5016 NL80211_EXT_FEATURE_BEACON_RATE_HT))
5017 return -EINVAL;
5018 if (count_vht &&
5019 !wiphy_ext_feature_isset(&rdev->wiphy,
5020 NL80211_EXT_FEATURE_BEACON_RATE_VHT))
5021 return -EINVAL;
Rajkumar Manoharanc4a30442020-10-16 13:15:27 -07005022 if (count_he &&
5023 !wiphy_ext_feature_isset(&rdev->wiphy,
5024 NL80211_EXT_FEATURE_BEACON_RATE_HE))
5025 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02005026
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05305027 return 0;
5028}
5029
John Crispindc1e3cb2021-09-15 19:54:34 -07005030static int nl80211_parse_mbssid_config(struct wiphy *wiphy,
5031 struct net_device *dev,
5032 struct nlattr *attrs,
5033 struct cfg80211_mbssid_config *config,
5034 u8 num_elems)
5035{
5036 struct nlattr *tb[NL80211_MBSSID_CONFIG_ATTR_MAX + 1];
5037
5038 if (!wiphy->mbssid_max_interfaces)
5039 return -EOPNOTSUPP;
5040
5041 if (nla_parse_nested(tb, NL80211_MBSSID_CONFIG_ATTR_MAX, attrs, NULL,
5042 NULL) ||
5043 !tb[NL80211_MBSSID_CONFIG_ATTR_INDEX])
5044 return -EINVAL;
5045
5046 config->ema = nla_get_flag(tb[NL80211_MBSSID_CONFIG_ATTR_EMA]);
5047 if (config->ema) {
5048 if (!wiphy->ema_max_profile_periodicity)
5049 return -EOPNOTSUPP;
5050
5051 if (num_elems > wiphy->ema_max_profile_periodicity)
5052 return -EINVAL;
5053 }
5054
5055 config->index = nla_get_u8(tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]);
5056 if (config->index >= wiphy->mbssid_max_interfaces ||
5057 (!config->index && !num_elems))
5058 return -EINVAL;
5059
5060 if (tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]) {
5061 u32 tx_ifindex =
5062 nla_get_u32(tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]);
5063
5064 if ((!config->index && tx_ifindex != dev->ifindex) ||
5065 (config->index && tx_ifindex == dev->ifindex))
5066 return -EINVAL;
5067
5068 if (tx_ifindex != dev->ifindex) {
5069 struct net_device *tx_netdev =
5070 dev_get_by_index(wiphy_net(wiphy), tx_ifindex);
5071
5072 if (!tx_netdev || !tx_netdev->ieee80211_ptr ||
5073 tx_netdev->ieee80211_ptr->wiphy != wiphy ||
5074 tx_netdev->ieee80211_ptr->iftype !=
5075 NL80211_IFTYPE_AP) {
5076 dev_put(tx_netdev);
5077 return -EINVAL;
5078 }
5079
5080 config->tx_wdev = tx_netdev->ieee80211_ptr;
5081 } else {
5082 config->tx_wdev = dev->ieee80211_ptr;
5083 }
5084 } else if (!config->index) {
5085 config->tx_wdev = dev->ieee80211_ptr;
5086 } else {
5087 return -EINVAL;
5088 }
5089
5090 return 0;
5091}
5092
5093static struct cfg80211_mbssid_elems *
5094nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs)
5095{
5096 struct nlattr *nl_elems;
5097 struct cfg80211_mbssid_elems *elems;
5098 int rem_elems;
5099 u8 i = 0, num_elems = 0;
5100
5101 if (!wiphy->mbssid_max_interfaces)
5102 return ERR_PTR(-EINVAL);
5103
5104 nla_for_each_nested(nl_elems, attrs, rem_elems)
5105 num_elems++;
5106
5107 elems = kzalloc(struct_size(elems, elem, num_elems), GFP_KERNEL);
5108 if (!elems)
5109 return ERR_PTR(-ENOMEM);
5110
5111 nla_for_each_nested(nl_elems, attrs, rem_elems) {
5112 elems->elem[i].data = nla_data(nl_elems);
5113 elems->elem[i].len = nla_len(nl_elems);
5114 i++;
5115 }
5116 elems->cnt = num_elems;
5117 return elems;
5118}
5119
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07005120static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
5121 struct nlattr *attrs[],
Johannes Berg88600202012-02-13 15:17:18 +01005122 struct cfg80211_beacon_data *bcn)
Johannes Berged1b6cc2007-12-19 02:03:32 +01005123{
Johannes Berg88600202012-02-13 15:17:18 +01005124 bool haveinfo = false;
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07005125 int err;
Johannes Berged1b6cc2007-12-19 02:03:32 +01005126
Johannes Berg88600202012-02-13 15:17:18 +01005127 memset(bcn, 0, sizeof(*bcn));
Johannes Berged1b6cc2007-12-19 02:03:32 +01005128
Simon Wunderlicha1193be2013-06-14 14:15:19 +02005129 if (attrs[NL80211_ATTR_BEACON_HEAD]) {
5130 bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
5131 bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
Johannes Berg88600202012-02-13 15:17:18 +01005132 if (!bcn->head_len)
5133 return -EINVAL;
5134 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01005135 }
5136
Simon Wunderlicha1193be2013-06-14 14:15:19 +02005137 if (attrs[NL80211_ATTR_BEACON_TAIL]) {
5138 bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
5139 bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
Johannes Berg88600202012-02-13 15:17:18 +01005140 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01005141 }
5142
Johannes Berg4c476992010-10-04 21:36:35 +02005143 if (!haveinfo)
5144 return -EINVAL;
Johannes Berged1b6cc2007-12-19 02:03:32 +01005145
Simon Wunderlicha1193be2013-06-14 14:15:19 +02005146 if (attrs[NL80211_ATTR_IE]) {
5147 bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
5148 bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03005149 }
5150
Simon Wunderlicha1193be2013-06-14 14:15:19 +02005151 if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01005152 bcn->proberesp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02005153 nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01005154 bcn->proberesp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02005155 nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03005156 }
5157
Simon Wunderlicha1193be2013-06-14 14:15:19 +02005158 if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01005159 bcn->assocresp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02005160 nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01005161 bcn->assocresp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02005162 nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03005163 }
5164
Simon Wunderlicha1193be2013-06-14 14:15:19 +02005165 if (attrs[NL80211_ATTR_PROBE_RESP]) {
5166 bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
5167 bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
Arik Nemtsov00f740e2011-11-10 11:28:56 +02005168 }
5169
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07005170 if (attrs[NL80211_ATTR_FTM_RESPONDER]) {
5171 struct nlattr *tb[NL80211_FTM_RESP_ATTR_MAX + 1];
5172
Johannes Berg8cb08172019-04-26 14:07:28 +02005173 err = nla_parse_nested_deprecated(tb,
5174 NL80211_FTM_RESP_ATTR_MAX,
5175 attrs[NL80211_ATTR_FTM_RESPONDER],
5176 NULL, NULL);
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07005177 if (err)
5178 return err;
5179
5180 if (tb[NL80211_FTM_RESP_ATTR_ENABLED] &&
5181 wiphy_ext_feature_isset(&rdev->wiphy,
5182 NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
5183 bcn->ftm_responder = 1;
5184 else
5185 return -EOPNOTSUPP;
5186
5187 if (tb[NL80211_FTM_RESP_ATTR_LCI]) {
5188 bcn->lci = nla_data(tb[NL80211_FTM_RESP_ATTR_LCI]);
5189 bcn->lci_len = nla_len(tb[NL80211_FTM_RESP_ATTR_LCI]);
5190 }
5191
5192 if (tb[NL80211_FTM_RESP_ATTR_CIVICLOC]) {
5193 bcn->civicloc = nla_data(tb[NL80211_FTM_RESP_ATTR_CIVICLOC]);
5194 bcn->civicloc_len = nla_len(tb[NL80211_FTM_RESP_ATTR_CIVICLOC]);
5195 }
5196 } else {
5197 bcn->ftm_responder = -1;
5198 }
5199
John Crispindc1e3cb2021-09-15 19:54:34 -07005200 if (attrs[NL80211_ATTR_MBSSID_ELEMS]) {
5201 struct cfg80211_mbssid_elems *mbssid =
5202 nl80211_parse_mbssid_elems(&rdev->wiphy,
5203 attrs[NL80211_ATTR_MBSSID_ELEMS]);
5204
5205 if (IS_ERR(mbssid))
5206 return PTR_ERR(mbssid);
5207
5208 bcn->mbssid_ies = mbssid;
5209 }
5210
Johannes Berg88600202012-02-13 15:17:18 +01005211 return 0;
5212}
5213
John Crispin796e90f2019-07-30 18:37:00 +02005214static int nl80211_parse_he_obss_pd(struct nlattr *attrs,
5215 struct ieee80211_he_obss_pd *he_obss_pd)
5216{
5217 struct nlattr *tb[NL80211_HE_OBSS_PD_ATTR_MAX + 1];
5218 int err;
5219
5220 err = nla_parse_nested(tb, NL80211_HE_OBSS_PD_ATTR_MAX, attrs,
5221 he_obss_pd_policy, NULL);
5222 if (err)
5223 return err;
5224
Rajkumar Manoharanf5bec332020-09-28 00:28:11 -07005225 if (!tb[NL80211_HE_OBSS_PD_ATTR_SR_CTRL])
5226 return -EINVAL;
5227
5228 he_obss_pd->sr_ctrl = nla_get_u8(tb[NL80211_HE_OBSS_PD_ATTR_SR_CTRL]);
5229
Rajkumar Manoharan6c8b6e42020-09-28 00:28:10 -07005230 if (tb[NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET])
5231 he_obss_pd->min_offset =
5232 nla_get_u8(tb[NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET]);
5233 if (tb[NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET])
5234 he_obss_pd->max_offset =
5235 nla_get_u8(tb[NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET]);
Rajkumar Manoharanf5bec332020-09-28 00:28:11 -07005236 if (tb[NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET])
5237 he_obss_pd->non_srg_max_offset =
5238 nla_get_u8(tb[NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET]);
John Crispin796e90f2019-07-30 18:37:00 +02005239
Rajkumar Manoharan6c8b6e42020-09-28 00:28:10 -07005240 if (he_obss_pd->min_offset > he_obss_pd->max_offset)
John Crispin796e90f2019-07-30 18:37:00 +02005241 return -EINVAL;
5242
Rajkumar Manoharanf5bec332020-09-28 00:28:11 -07005243 if (tb[NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP])
5244 memcpy(he_obss_pd->bss_color_bitmap,
5245 nla_data(tb[NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP]),
5246 sizeof(he_obss_pd->bss_color_bitmap));
5247
5248 if (tb[NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP])
5249 memcpy(he_obss_pd->partial_bssid_bitmap,
5250 nla_data(tb[NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP]),
5251 sizeof(he_obss_pd->partial_bssid_bitmap));
5252
John Crispin796e90f2019-07-30 18:37:00 +02005253 he_obss_pd->enable = true;
5254
5255 return 0;
5256}
5257
John Crispin5c5e52d2019-12-17 15:19:18 +01005258static int nl80211_parse_he_bss_color(struct nlattr *attrs,
5259 struct cfg80211_he_bss_color *he_bss_color)
5260{
5261 struct nlattr *tb[NL80211_HE_BSS_COLOR_ATTR_MAX + 1];
5262 int err;
5263
5264 err = nla_parse_nested(tb, NL80211_HE_BSS_COLOR_ATTR_MAX, attrs,
5265 he_bss_color_policy, NULL);
5266 if (err)
5267 return err;
5268
5269 if (!tb[NL80211_HE_BSS_COLOR_ATTR_COLOR])
5270 return -EINVAL;
5271
5272 he_bss_color->color =
5273 nla_get_u8(tb[NL80211_HE_BSS_COLOR_ATTR_COLOR]);
Johannes Berg75e6b592020-07-30 13:00:52 +02005274 he_bss_color->enabled =
5275 !nla_get_flag(tb[NL80211_HE_BSS_COLOR_ATTR_DISABLED]);
John Crispin5c5e52d2019-12-17 15:19:18 +01005276 he_bss_color->partial =
5277 nla_get_flag(tb[NL80211_HE_BSS_COLOR_ATTR_PARTIAL]);
5278
5279 return 0;
5280}
5281
Aloka Dixit291c49d2020-09-11 00:05:29 +00005282static int nl80211_parse_fils_discovery(struct cfg80211_registered_device *rdev,
5283 struct nlattr *attrs,
5284 struct cfg80211_ap_settings *params)
5285{
5286 struct nlattr *tb[NL80211_FILS_DISCOVERY_ATTR_MAX + 1];
5287 int ret;
5288 struct cfg80211_fils_discovery *fd = &params->fils_discovery;
5289
5290 if (!wiphy_ext_feature_isset(&rdev->wiphy,
5291 NL80211_EXT_FEATURE_FILS_DISCOVERY))
5292 return -EINVAL;
5293
5294 ret = nla_parse_nested(tb, NL80211_FILS_DISCOVERY_ATTR_MAX, attrs,
5295 NULL, NULL);
5296 if (ret)
5297 return ret;
5298
5299 if (!tb[NL80211_FILS_DISCOVERY_ATTR_INT_MIN] ||
5300 !tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX] ||
5301 !tb[NL80211_FILS_DISCOVERY_ATTR_TMPL])
5302 return -EINVAL;
5303
5304 fd->tmpl_len = nla_len(tb[NL80211_FILS_DISCOVERY_ATTR_TMPL]);
5305 fd->tmpl = nla_data(tb[NL80211_FILS_DISCOVERY_ATTR_TMPL]);
5306 fd->min_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MIN]);
5307 fd->max_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX]);
5308
5309 return 0;
5310}
5311
Aloka Dixit7443dcd2020-09-11 00:33:00 +00005312static int
5313nl80211_parse_unsol_bcast_probe_resp(struct cfg80211_registered_device *rdev,
5314 struct nlattr *attrs,
5315 struct cfg80211_ap_settings *params)
5316{
5317 struct nlattr *tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX + 1];
5318 int ret;
5319 struct cfg80211_unsol_bcast_probe_resp *presp =
5320 &params->unsol_bcast_probe_resp;
5321
5322 if (!wiphy_ext_feature_isset(&rdev->wiphy,
5323 NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP))
5324 return -EINVAL;
5325
5326 ret = nla_parse_nested(tb, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX,
5327 attrs, NULL, NULL);
5328 if (ret)
5329 return ret;
5330
5331 if (!tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT] ||
5332 !tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL])
5333 return -EINVAL;
5334
5335 presp->tmpl = nla_data(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL]);
5336 presp->tmpl_len = nla_len(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL]);
5337 presp->interval = nla_get_u32(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT]);
5338 return 0;
5339}
5340
Johannes Berg66cd7942017-02-07 22:40:44 +02005341static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
Johannes Berg153e2a12021-09-30 13:11:29 +02005342 const struct element *rates)
Johannes Berg66cd7942017-02-07 22:40:44 +02005343{
5344 int i;
5345
5346 if (!rates)
5347 return;
5348
Johannes Berg153e2a12021-09-30 13:11:29 +02005349 for (i = 0; i < rates->datalen; i++) {
5350 if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
Johannes Berg66cd7942017-02-07 22:40:44 +02005351 params->ht_required = true;
Johannes Berg153e2a12021-09-30 13:11:29 +02005352 if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
Johannes Berg66cd7942017-02-07 22:40:44 +02005353 params->vht_required = true;
Johannes Berg153e2a12021-09-30 13:11:29 +02005354 if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
Ilan Peer2a392592020-03-26 15:09:35 +02005355 params->he_required = true;
Johannes Berg153e2a12021-09-30 13:11:29 +02005356 if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_SAE_H2E)
Ilan Peerd6587602020-11-29 17:30:46 +02005357 params->sae_h2e_required = true;
Johannes Berg66cd7942017-02-07 22:40:44 +02005358 }
5359}
5360
5361/*
5362 * Since the nl80211 API didn't include, from the beginning, attributes about
5363 * HT/VHT requirements/capabilities, we parse them out of the IEs for the
5364 * benefit of drivers that rebuild IEs in the firmware.
5365 */
5366static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
5367{
5368 const struct cfg80211_beacon_data *bcn = &params->beacon;
Igor Mitsyankoba83bfb2017-08-30 13:52:25 -07005369 size_t ies_len = bcn->tail_len;
5370 const u8 *ies = bcn->tail;
Johannes Berg153e2a12021-09-30 13:11:29 +02005371 const struct element *rates;
5372 const struct element *cap;
Johannes Berg66cd7942017-02-07 22:40:44 +02005373
Johannes Berg153e2a12021-09-30 13:11:29 +02005374 rates = cfg80211_find_elem(WLAN_EID_SUPP_RATES, ies, ies_len);
Johannes Berg66cd7942017-02-07 22:40:44 +02005375 nl80211_check_ap_rate_selectors(params, rates);
5376
Johannes Berg153e2a12021-09-30 13:11:29 +02005377 rates = cfg80211_find_elem(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
Johannes Berg66cd7942017-02-07 22:40:44 +02005378 nl80211_check_ap_rate_selectors(params, rates);
5379
Johannes Berg153e2a12021-09-30 13:11:29 +02005380 cap = cfg80211_find_elem(WLAN_EID_HT_CAPABILITY, ies, ies_len);
5381 if (cap && cap->datalen >= sizeof(*params->ht_cap))
5382 params->ht_cap = (void *)cap->data;
5383 cap = cfg80211_find_elem(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
5384 if (cap && cap->datalen >= sizeof(*params->vht_cap))
5385 params->vht_cap = (void *)cap->data;
5386 cap = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
5387 if (cap && cap->datalen >= sizeof(*params->he_cap) + 1)
5388 params->he_cap = (void *)(cap->data + 1);
5389 cap = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
5390 if (cap && cap->datalen >= sizeof(*params->he_oper) + 1)
5391 params->he_oper = (void *)(cap->data + 1);
Johannes Berg66cd7942017-02-07 22:40:44 +02005392}
5393
Felix Fietkau46c1dd02012-06-19 02:50:57 +02005394static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
5395 struct cfg80211_ap_settings *params)
5396{
5397 struct wireless_dev *wdev;
5398 bool ret = false;
5399
Johannes Berg53873f12016-05-03 16:52:04 +03005400 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Felix Fietkau46c1dd02012-06-19 02:50:57 +02005401 if (wdev->iftype != NL80211_IFTYPE_AP &&
5402 wdev->iftype != NL80211_IFTYPE_P2P_GO)
5403 continue;
5404
Johannes Berg683b6d32012-11-08 21:25:48 +01005405 if (!wdev->preset_chandef.chan)
Felix Fietkau46c1dd02012-06-19 02:50:57 +02005406 continue;
5407
Johannes Berg683b6d32012-11-08 21:25:48 +01005408 params->chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02005409 ret = true;
5410 break;
5411 }
5412
Felix Fietkau46c1dd02012-06-19 02:50:57 +02005413 return ret;
5414}
5415
Jouni Malinene39e5b52012-09-30 19:29:39 +03005416static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
5417 enum nl80211_auth_type auth_type,
5418 enum nl80211_commands cmd)
5419{
5420 if (auth_type > NL80211_AUTHTYPE_MAX)
5421 return false;
5422
5423 switch (cmd) {
5424 case NL80211_CMD_AUTHENTICATE:
5425 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
5426 auth_type == NL80211_AUTHTYPE_SAE)
5427 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03005428 if (!wiphy_ext_feature_isset(&rdev->wiphy,
5429 NL80211_EXT_FEATURE_FILS_STA) &&
5430 (auth_type == NL80211_AUTHTYPE_FILS_SK ||
5431 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
5432 auth_type == NL80211_AUTHTYPE_FILS_PK))
5433 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03005434 return true;
5435 case NL80211_CMD_CONNECT:
Srinivas Dasari10773a72018-01-25 17:13:39 +02005436 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
Chung-Hsien Hsu26f70442019-05-09 09:49:06 +00005437 !wiphy_ext_feature_isset(&rdev->wiphy,
5438 NL80211_EXT_FEATURE_SAE_OFFLOAD) &&
Srinivas Dasari10773a72018-01-25 17:13:39 +02005439 auth_type == NL80211_AUTHTYPE_SAE)
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03005440 return false;
Srinivas Dasari10773a72018-01-25 17:13:39 +02005441
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03005442 /* FILS with SK PFS or PK not supported yet */
5443 if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
5444 auth_type == NL80211_AUTHTYPE_FILS_PK)
5445 return false;
5446 if (!wiphy_ext_feature_isset(
5447 &rdev->wiphy,
5448 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
5449 auth_type == NL80211_AUTHTYPE_FILS_SK)
5450 return false;
5451 return true;
Jouni Malinene39e5b52012-09-30 19:29:39 +03005452 case NL80211_CMD_START_AP:
Chung-Hsien Hsu2831a632020-08-17 02:33:15 -05005453 if (!wiphy_ext_feature_isset(&rdev->wiphy,
5454 NL80211_EXT_FEATURE_SAE_OFFLOAD_AP) &&
5455 auth_type == NL80211_AUTHTYPE_SAE)
Jouni Malinene39e5b52012-09-30 19:29:39 +03005456 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03005457 /* FILS not supported yet */
5458 if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
5459 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
5460 auth_type == NL80211_AUTHTYPE_FILS_PK)
5461 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03005462 return true;
5463 default:
5464 return false;
5465 }
5466}
5467
Johannes Berg88600202012-02-13 15:17:18 +01005468static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
5469{
5470 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5471 struct net_device *dev = info->user_ptr[1];
5472 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg9e263e12021-09-23 16:18:37 +02005473 struct cfg80211_ap_settings *params;
Johannes Berg88600202012-02-13 15:17:18 +01005474 int err;
5475
5476 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
5477 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5478 return -EOPNOTSUPP;
5479
5480 if (!rdev->ops->start_ap)
5481 return -EOPNOTSUPP;
5482
5483 if (wdev->beacon_interval)
5484 return -EALREADY;
5485
Johannes Berg88600202012-02-13 15:17:18 +01005486 /* these are required for START_AP */
5487 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
5488 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
5489 !info->attrs[NL80211_ATTR_BEACON_HEAD])
5490 return -EINVAL;
5491
Johannes Berg9e263e12021-09-23 16:18:37 +02005492 params = kzalloc(sizeof(*params), GFP_KERNEL);
5493 if (!params)
5494 return -ENOMEM;
Johannes Berg88600202012-02-13 15:17:18 +01005495
Johannes Berg9e263e12021-09-23 16:18:37 +02005496 err = nl80211_parse_beacon(rdev, info->attrs, &params->beacon);
5497 if (err)
5498 goto out;
5499
5500 params->beacon_interval =
Johannes Berg88600202012-02-13 15:17:18 +01005501 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Johannes Berg9e263e12021-09-23 16:18:37 +02005502 params->dtim_period =
Johannes Berg88600202012-02-13 15:17:18 +01005503 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
5504
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05305505 err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
Johannes Berg9e263e12021-09-23 16:18:37 +02005506 params->beacon_interval);
Johannes Berg88600202012-02-13 15:17:18 +01005507 if (err)
Johannes Berg9e263e12021-09-23 16:18:37 +02005508 goto out;
Johannes Berg88600202012-02-13 15:17:18 +01005509
5510 /*
5511 * In theory, some of these attributes should be required here
5512 * but since they were not used when the command was originally
5513 * added, keep them optional for old user space programs to let
5514 * them continue to work with drivers that do not need the
5515 * additional information -- drivers must check!
5516 */
5517 if (info->attrs[NL80211_ATTR_SSID]) {
Johannes Berg9e263e12021-09-23 16:18:37 +02005518 params->ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
5519 params->ssid_len =
Johannes Berg88600202012-02-13 15:17:18 +01005520 nla_len(info->attrs[NL80211_ATTR_SSID]);
Johannes Berg9e263e12021-09-23 16:18:37 +02005521 if (params->ssid_len == 0) {
5522 err = -EINVAL;
5523 goto out;
5524 }
Johannes Berg88600202012-02-13 15:17:18 +01005525 }
5526
Johannes Bergab0d76f2018-10-02 10:00:07 +02005527 if (info->attrs[NL80211_ATTR_HIDDEN_SSID])
Johannes Berg9e263e12021-09-23 16:18:37 +02005528 params->hidden_ssid = nla_get_u32(
Johannes Berg88600202012-02-13 15:17:18 +01005529 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
Johannes Berg88600202012-02-13 15:17:18 +01005530
Johannes Berg9e263e12021-09-23 16:18:37 +02005531 params->privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
Johannes Berg88600202012-02-13 15:17:18 +01005532
5533 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
Johannes Berg9e263e12021-09-23 16:18:37 +02005534 params->auth_type = nla_get_u32(
Johannes Berg88600202012-02-13 15:17:18 +01005535 info->attrs[NL80211_ATTR_AUTH_TYPE]);
Johannes Berg9e263e12021-09-23 16:18:37 +02005536 if (!nl80211_valid_auth_type(rdev, params->auth_type,
5537 NL80211_CMD_START_AP)) {
5538 err = -EINVAL;
5539 goto out;
5540 }
Johannes Berg88600202012-02-13 15:17:18 +01005541 } else
Johannes Berg9e263e12021-09-23 16:18:37 +02005542 params->auth_type = NL80211_AUTHTYPE_AUTOMATIC;
Johannes Berg88600202012-02-13 15:17:18 +01005543
Johannes Berg9e263e12021-09-23 16:18:37 +02005544 err = nl80211_crypto_settings(rdev, info, &params->crypto,
Johannes Berg88600202012-02-13 15:17:18 +01005545 NL80211_MAX_NR_CIPHER_SUITES);
5546 if (err)
Johannes Berg9e263e12021-09-23 16:18:37 +02005547 goto out;
Johannes Berg88600202012-02-13 15:17:18 +01005548
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +05305549 if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
Johannes Berg9e263e12021-09-23 16:18:37 +02005550 if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER)) {
5551 err = -EOPNOTSUPP;
5552 goto out;
5553 }
5554 params->inactivity_timeout = nla_get_u16(
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +05305555 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
5556 }
5557
Johannes Berg53cabad2012-11-14 15:17:28 +01005558 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
Johannes Berg9e263e12021-09-23 16:18:37 +02005559 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
5560 err = -EINVAL;
5561 goto out;
5562 }
5563 params->p2p_ctwindow =
Johannes Berg53cabad2012-11-14 15:17:28 +01005564 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
Johannes Berg9e263e12021-09-23 16:18:37 +02005565 if (params->p2p_ctwindow != 0 &&
5566 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) {
5567 err = -EINVAL;
5568 goto out;
5569 }
Johannes Berg53cabad2012-11-14 15:17:28 +01005570 }
5571
5572 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
5573 u8 tmp;
5574
Johannes Berg9e263e12021-09-23 16:18:37 +02005575 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
5576 err = -EINVAL;
5577 goto out;
5578 }
Johannes Berg53cabad2012-11-14 15:17:28 +01005579 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
Johannes Berg9e263e12021-09-23 16:18:37 +02005580 params->p2p_opp_ps = tmp;
5581 if (params->p2p_opp_ps != 0 &&
5582 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) {
5583 err = -EINVAL;
5584 goto out;
5585 }
Johannes Berg53cabad2012-11-14 15:17:28 +01005586 }
5587
Johannes Bergaa430da2012-05-16 23:50:18 +02005588 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg9e263e12021-09-23 16:18:37 +02005589 err = nl80211_parse_chandef(rdev, info, &params->chandef);
Johannes Berg683b6d32012-11-08 21:25:48 +01005590 if (err)
Johannes Berg9e263e12021-09-23 16:18:37 +02005591 goto out;
Johannes Berg683b6d32012-11-08 21:25:48 +01005592 } else if (wdev->preset_chandef.chan) {
Johannes Berg9e263e12021-09-23 16:18:37 +02005593 params->chandef = wdev->preset_chandef;
5594 } else if (!nl80211_get_ap_channel(rdev, params)) {
5595 err = -EINVAL;
5596 goto out;
5597 }
Johannes Bergaa430da2012-05-16 23:50:18 +02005598
Johannes Berg9e263e12021-09-23 16:18:37 +02005599 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params->chandef,
5600 wdev->iftype)) {
5601 err = -EINVAL;
5602 goto out;
5603 }
Johannes Bergaa430da2012-05-16 23:50:18 +02005604
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05305605 if (info->attrs[NL80211_ATTR_TX_RATES]) {
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +05305606 err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
5607 NL80211_ATTR_TX_RATES,
Johannes Berg9e263e12021-09-23 16:18:37 +02005608 &params->beacon_rate,
Rajkumar Manoharan857b34c2020-10-16 13:15:26 -07005609 dev, false);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05305610 if (err)
Johannes Berg9e263e12021-09-23 16:18:37 +02005611 goto out;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05305612
Johannes Berg9e263e12021-09-23 16:18:37 +02005613 err = validate_beacon_tx_rate(rdev, params->chandef.chan->band,
5614 &params->beacon_rate);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05305615 if (err)
Johannes Berg9e263e12021-09-23 16:18:37 +02005616 goto out;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05305617 }
5618
Eliad Peller18998c32014-09-10 14:07:34 +03005619 if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
Johannes Berg9e263e12021-09-23 16:18:37 +02005620 params->smps_mode =
Eliad Peller18998c32014-09-10 14:07:34 +03005621 nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
Johannes Berg9e263e12021-09-23 16:18:37 +02005622 switch (params->smps_mode) {
Eliad Peller18998c32014-09-10 14:07:34 +03005623 case NL80211_SMPS_OFF:
5624 break;
5625 case NL80211_SMPS_STATIC:
5626 if (!(rdev->wiphy.features &
Johannes Berg9e263e12021-09-23 16:18:37 +02005627 NL80211_FEATURE_STATIC_SMPS)) {
5628 err = -EINVAL;
5629 goto out;
5630 }
Eliad Peller18998c32014-09-10 14:07:34 +03005631 break;
5632 case NL80211_SMPS_DYNAMIC:
5633 if (!(rdev->wiphy.features &
Johannes Berg9e263e12021-09-23 16:18:37 +02005634 NL80211_FEATURE_DYNAMIC_SMPS)) {
5635 err = -EINVAL;
5636 goto out;
5637 }
Eliad Peller18998c32014-09-10 14:07:34 +03005638 break;
5639 default:
Johannes Berg9e263e12021-09-23 16:18:37 +02005640 err = -EINVAL;
5641 goto out;
Eliad Peller18998c32014-09-10 14:07:34 +03005642 }
5643 } else {
Johannes Berg9e263e12021-09-23 16:18:37 +02005644 params->smps_mode = NL80211_SMPS_OFF;
Eliad Peller18998c32014-09-10 14:07:34 +03005645 }
5646
Johannes Berg9e263e12021-09-23 16:18:37 +02005647 params->pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
5648 if (params->pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
5649 err = -EOPNOTSUPP;
5650 goto out;
5651 }
Purushottam Kushwaha6e8ef842016-07-05 13:44:51 +05305652
Ola Olsson4baf6be2015-10-29 07:04:58 +01005653 if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
Johannes Berg9e263e12021-09-23 16:18:37 +02005654 params->acl = parse_acl_data(&rdev->wiphy, info);
5655 if (IS_ERR(params->acl)) {
5656 err = PTR_ERR(params->acl);
Johannes Berg05075fe72021-09-27 13:44:03 +02005657 params->acl = NULL;
Johannes Berg9e263e12021-09-23 16:18:37 +02005658 goto out;
5659 }
Ola Olsson4baf6be2015-10-29 07:04:58 +01005660 }
5661
Johannes Berg9e263e12021-09-23 16:18:37 +02005662 params->twt_responder =
John Crispina0de1ca32019-05-28 13:49:48 +02005663 nla_get_flag(info->attrs[NL80211_ATTR_TWT_RESPONDER]);
5664
John Crispin796e90f2019-07-30 18:37:00 +02005665 if (info->attrs[NL80211_ATTR_HE_OBSS_PD]) {
5666 err = nl80211_parse_he_obss_pd(
5667 info->attrs[NL80211_ATTR_HE_OBSS_PD],
Johannes Berg9e263e12021-09-23 16:18:37 +02005668 &params->he_obss_pd);
Luca Coelhobc7a39b2020-06-26 12:49:39 +03005669 if (err)
5670 goto out;
John Crispin796e90f2019-07-30 18:37:00 +02005671 }
5672
John Crispin5c5e52d2019-12-17 15:19:18 +01005673 if (info->attrs[NL80211_ATTR_HE_BSS_COLOR]) {
5674 err = nl80211_parse_he_bss_color(
5675 info->attrs[NL80211_ATTR_HE_BSS_COLOR],
Johannes Berg9e263e12021-09-23 16:18:37 +02005676 &params->he_bss_color);
John Crispin5c5e52d2019-12-17 15:19:18 +01005677 if (err)
Luca Coelho60a01212020-06-26 12:49:40 +03005678 goto out;
John Crispin5c5e52d2019-12-17 15:19:18 +01005679 }
5680
Aloka Dixit291c49d2020-09-11 00:05:29 +00005681 if (info->attrs[NL80211_ATTR_FILS_DISCOVERY]) {
5682 err = nl80211_parse_fils_discovery(rdev,
5683 info->attrs[NL80211_ATTR_FILS_DISCOVERY],
Johannes Berg9e263e12021-09-23 16:18:37 +02005684 params);
Aloka Dixit291c49d2020-09-11 00:05:29 +00005685 if (err)
5686 goto out;
5687 }
5688
Aloka Dixit7443dcd2020-09-11 00:33:00 +00005689 if (info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP]) {
5690 err = nl80211_parse_unsol_bcast_probe_resp(
5691 rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP],
Johannes Berg9e263e12021-09-23 16:18:37 +02005692 params);
Aloka Dixit7443dcd2020-09-11 00:33:00 +00005693 if (err)
Johannes Bergabaf94e2021-04-08 14:28:34 +02005694 goto out;
Aloka Dixit7443dcd2020-09-11 00:33:00 +00005695 }
5696
John Crispindc1e3cb2021-09-15 19:54:34 -07005697 if (info->attrs[NL80211_ATTR_MBSSID_CONFIG]) {
5698 err = nl80211_parse_mbssid_config(&rdev->wiphy, dev,
5699 info->attrs[NL80211_ATTR_MBSSID_CONFIG],
5700 &params->mbssid_config,
5701 params->beacon.mbssid_ies ?
5702 params->beacon.mbssid_ies->cnt :
5703 0);
5704 if (err)
5705 goto out;
5706 }
5707
Johannes Berg9e263e12021-09-23 16:18:37 +02005708 nl80211_calculate_ap_params(params);
Johannes Berg66cd7942017-02-07 22:40:44 +02005709
Srinivas Dasarife494372019-01-23 18:06:56 +05305710 if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
Johannes Berg9e263e12021-09-23 16:18:37 +02005711 params->flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
Srinivas Dasarife494372019-01-23 18:06:56 +05305712
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005713 wdev_lock(wdev);
Johannes Berg9e263e12021-09-23 16:18:37 +02005714 err = rdev_start_ap(rdev, dev, params);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02005715 if (!err) {
Johannes Berg9e263e12021-09-23 16:18:37 +02005716 wdev->preset_chandef = params->chandef;
5717 wdev->beacon_interval = params->beacon_interval;
5718 wdev->chandef = params->chandef;
5719 wdev->ssid_len = params->ssid_len;
5720 memcpy(wdev->ssid, params->ssid, wdev->ssid_len);
Denis Kenzior466a3062018-03-26 12:52:47 -05005721
5722 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
5723 wdev->conn_owner_nlportid = info->snd_portid;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02005724 }
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005725 wdev_unlock(wdev);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05305726
Johannes Berg9951ebf2020-02-21 10:41:43 +01005727out:
Johannes Berg9e263e12021-09-23 16:18:37 +02005728 kfree(params->acl);
John Crispindc1e3cb2021-09-15 19:54:34 -07005729 kfree(params->beacon.mbssid_ies);
5730 if (params->mbssid_config.tx_wdev &&
5731 params->mbssid_config.tx_wdev->netdev &&
5732 params->mbssid_config.tx_wdev->netdev != dev)
5733 dev_put(params->mbssid_config.tx_wdev->netdev);
Johannes Berg9e263e12021-09-23 16:18:37 +02005734 kfree(params);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05305735
Johannes Berg56d18932011-05-09 18:41:15 +02005736 return err;
Johannes Berged1b6cc2007-12-19 02:03:32 +01005737}
5738
Johannes Berg88600202012-02-13 15:17:18 +01005739static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
5740{
5741 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5742 struct net_device *dev = info->user_ptr[1];
5743 struct wireless_dev *wdev = dev->ieee80211_ptr;
5744 struct cfg80211_beacon_data params;
5745 int err;
5746
5747 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
5748 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5749 return -EOPNOTSUPP;
5750
5751 if (!rdev->ops->change_beacon)
5752 return -EOPNOTSUPP;
5753
5754 if (!wdev->beacon_interval)
5755 return -EINVAL;
5756
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07005757 err = nl80211_parse_beacon(rdev, info->attrs, &params);
Johannes Berg88600202012-02-13 15:17:18 +01005758 if (err)
John Crispindc1e3cb2021-09-15 19:54:34 -07005759 goto out;
Johannes Berg88600202012-02-13 15:17:18 +01005760
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005761 wdev_lock(wdev);
5762 err = rdev_change_beacon(rdev, dev, &params);
5763 wdev_unlock(wdev);
5764
John Crispindc1e3cb2021-09-15 19:54:34 -07005765out:
5766 kfree(params.mbssid_ies);
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005767 return err;
Johannes Berg88600202012-02-13 15:17:18 +01005768}
5769
5770static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
Johannes Berged1b6cc2007-12-19 02:03:32 +01005771{
Johannes Berg4c476992010-10-04 21:36:35 +02005772 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5773 struct net_device *dev = info->user_ptr[1];
Johannes Berged1b6cc2007-12-19 02:03:32 +01005774
Ilan Peer7c8d5e02014-02-25 15:33:38 +02005775 return cfg80211_stop_ap(rdev, dev, false);
Johannes Berged1b6cc2007-12-19 02:03:32 +01005776}
5777
Johannes Berg5727ef12007-12-19 02:03:34 +01005778static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
5779 [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
5780 [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
5781 [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
Jouni Malinen0e467242009-05-11 21:57:55 +03005782 [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
Javier Cardonab39c48f2011-04-07 15:08:30 -07005783 [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
Johannes Bergd83023d2011-12-14 09:29:15 +01005784 [NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },
Johannes Berg5727ef12007-12-19 02:03:34 +01005785};
5786
Johannes Bergeccb8e82009-05-11 21:57:56 +03005787static int parse_station_flags(struct genl_info *info,
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005788 enum nl80211_iftype iftype,
Johannes Bergeccb8e82009-05-11 21:57:56 +03005789 struct station_parameters *params)
Johannes Berg5727ef12007-12-19 02:03:34 +01005790{
5791 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
Johannes Bergeccb8e82009-05-11 21:57:56 +03005792 struct nlattr *nla;
Johannes Berg5727ef12007-12-19 02:03:34 +01005793 int flag;
5794
Johannes Bergeccb8e82009-05-11 21:57:56 +03005795 /*
5796 * Try parsing the new attribute first so userspace
5797 * can specify both for older kernels.
5798 */
5799 nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
5800 if (nla) {
5801 struct nl80211_sta_flag_update *sta_flags;
Johannes Berg5727ef12007-12-19 02:03:34 +01005802
Johannes Bergeccb8e82009-05-11 21:57:56 +03005803 sta_flags = nla_data(nla);
5804 params->sta_flags_mask = sta_flags->mask;
5805 params->sta_flags_set = sta_flags->set;
Johannes Berg77ee7c82013-02-15 00:48:33 +01005806 params->sta_flags_set &= params->sta_flags_mask;
Johannes Bergeccb8e82009-05-11 21:57:56 +03005807 if ((params->sta_flags_mask |
5808 params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
5809 return -EINVAL;
5810 return 0;
5811 }
5812
5813 /* if present, parse the old attribute */
5814
5815 nla = info->attrs[NL80211_ATTR_STA_FLAGS];
Johannes Berg5727ef12007-12-19 02:03:34 +01005816 if (!nla)
5817 return 0;
5818
Johannes Berg8cb08172019-04-26 14:07:28 +02005819 if (nla_parse_nested_deprecated(flags, NL80211_STA_FLAG_MAX, nla, sta_flags_policy, info->extack))
Johannes Berg5727ef12007-12-19 02:03:34 +01005820 return -EINVAL;
5821
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005822 /*
5823 * Only allow certain flags for interface types so that
5824 * other attributes are silently ignored. Remember that
5825 * this is backward compatibility code with old userspace
5826 * and shouldn't be hit in other cases anyway.
5827 */
5828 switch (iftype) {
5829 case NL80211_IFTYPE_AP:
5830 case NL80211_IFTYPE_AP_VLAN:
5831 case NL80211_IFTYPE_P2P_GO:
5832 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
5833 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
5834 BIT(NL80211_STA_FLAG_WME) |
5835 BIT(NL80211_STA_FLAG_MFP);
5836 break;
5837 case NL80211_IFTYPE_P2P_CLIENT:
5838 case NL80211_IFTYPE_STATION:
5839 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
5840 BIT(NL80211_STA_FLAG_TDLS_PEER);
5841 break;
5842 case NL80211_IFTYPE_MESH_POINT:
5843 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5844 BIT(NL80211_STA_FLAG_MFP) |
5845 BIT(NL80211_STA_FLAG_AUTHORIZED);
Bernd Edlinger5cf30062018-07-08 09:57:22 +00005846 break;
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005847 default:
5848 return -EINVAL;
5849 }
Johannes Berg5727ef12007-12-19 02:03:34 +01005850
Johannes Berg3383b5a2012-05-10 20:14:43 +02005851 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
5852 if (flags[flag]) {
Johannes Bergeccb8e82009-05-11 21:57:56 +03005853 params->sta_flags_set |= (1<<flag);
Johannes Berg5727ef12007-12-19 02:03:34 +01005854
Johannes Berg3383b5a2012-05-10 20:14:43 +02005855 /* no longer support new API additions in old API */
5856 if (flag > NL80211_STA_FLAG_MAX_OLD_API)
5857 return -EINVAL;
5858 }
5859 }
5860
Johannes Berg5727ef12007-12-19 02:03:34 +01005861 return 0;
5862}
5863
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02005864bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005865{
5866 struct nlattr *rate;
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03005867 u32 bitrate;
5868 u16 bitrate_compat;
Matthias Kaehlckebbf67e42017-04-17 15:59:52 -07005869 enum nl80211_rate_info rate_flg;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005870
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005871 rate = nla_nest_start_noflag(msg, attr);
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005872 if (!rate)
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005873 return false;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005874
5875 /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
5876 bitrate = cfg80211_calculate_bitrate(info);
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03005877 /* report 16-bit bitrate only if we can */
5878 bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005879 if (bitrate > 0 &&
5880 nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
5881 return false;
5882 if (bitrate_compat > 0 &&
5883 nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
5884 return false;
5885
Johannes Bergb51f3be2015-01-15 16:14:02 +01005886 switch (info->bw) {
5887 case RATE_INFO_BW_5:
5888 rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
5889 break;
5890 case RATE_INFO_BW_10:
5891 rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
5892 break;
5893 default:
5894 WARN_ON(1);
Miaohe Lin7b506ff2020-08-22 04:23:23 -04005895 fallthrough;
Johannes Bergb51f3be2015-01-15 16:14:02 +01005896 case RATE_INFO_BW_20:
5897 rate_flg = 0;
5898 break;
5899 case RATE_INFO_BW_40:
5900 rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
5901 break;
5902 case RATE_INFO_BW_80:
5903 rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
5904 break;
5905 case RATE_INFO_BW_160:
5906 rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
5907 break;
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03005908 case RATE_INFO_BW_HE_RU:
5909 rate_flg = 0;
5910 WARN_ON(!(info->flags & RATE_INFO_FLAGS_HE_MCS));
Johannes Bergb51f3be2015-01-15 16:14:02 +01005911 }
5912
5913 if (rate_flg && nla_put_flag(msg, rate_flg))
5914 return false;
5915
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005916 if (info->flags & RATE_INFO_FLAGS_MCS) {
5917 if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
5918 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005919 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
5920 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
5921 return false;
5922 } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
5923 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
5924 return false;
5925 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
5926 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005927 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
5928 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
5929 return false;
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03005930 } else if (info->flags & RATE_INFO_FLAGS_HE_MCS) {
5931 if (nla_put_u8(msg, NL80211_RATE_INFO_HE_MCS, info->mcs))
5932 return false;
5933 if (nla_put_u8(msg, NL80211_RATE_INFO_HE_NSS, info->nss))
5934 return false;
5935 if (nla_put_u8(msg, NL80211_RATE_INFO_HE_GI, info->he_gi))
5936 return false;
5937 if (nla_put_u8(msg, NL80211_RATE_INFO_HE_DCM, info->he_dcm))
5938 return false;
5939 if (info->bw == RATE_INFO_BW_HE_RU &&
5940 nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
5941 info->he_ru_alloc))
5942 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01005943 }
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005944
5945 nla_nest_end(msg, rate);
5946 return true;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01005947}
5948
Felix Fietkau119363c2013-04-22 16:29:30 +02005949static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
5950 int id)
5951{
5952 void *attr;
5953 int i = 0;
5954
5955 if (!mask)
5956 return true;
5957
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005958 attr = nla_nest_start_noflag(msg, id);
Felix Fietkau119363c2013-04-22 16:29:30 +02005959 if (!attr)
5960 return false;
5961
5962 for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
5963 if (!(mask & BIT(i)))
5964 continue;
5965
5966 if (nla_put_u8(msg, i, signal[i]))
5967 return false;
5968 }
5969
5970 nla_nest_end(msg, attr);
5971
5972 return true;
5973}
5974
Johannes Bergcf5ead82014-11-14 17:14:00 +01005975static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
5976 u32 seq, int flags,
John W. Linville66266b32012-03-15 13:25:41 -04005977 struct cfg80211_registered_device *rdev,
5978 struct net_device *dev,
Johannes Berg98b62182009-12-23 13:15:44 +01005979 const u8 *mac_addr, struct station_info *sinfo)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005980{
5981 void *hdr;
Paul Stewartf4263c92011-03-31 09:25:41 -07005982 struct nlattr *sinfoattr, *bss_param;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005983
Johannes Bergcf5ead82014-11-14 17:14:00 +01005984 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Andy Strohmanf77bf482019-05-24 23:27:29 -07005985 if (!hdr) {
5986 cfg80211_sinfo_release_content(sinfo);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005987 return -1;
Andy Strohmanf77bf482019-05-24 23:27:29 -07005988 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005989
David S. Miller9360ffd2012-03-29 04:41:26 -04005990 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5991 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
5992 nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
5993 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02005994
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005995 sinfoattr = nla_nest_start_noflag(msg, NL80211_ATTR_STA_INFO);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005996 if (!sinfoattr)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01005997 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01005998
5999#define PUT_SINFO(attr, memb, type) do { \
Johannes Bergd686b922016-04-26 09:54:11 +02006000 BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
Omer Efrat397c6572018-06-17 13:06:14 +03006001 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
Johannes Berg319090b2014-11-17 14:08:11 +01006002 nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
6003 sinfo->memb)) \
6004 goto nla_put_failure; \
6005 } while (0)
Johannes Bergd686b922016-04-26 09:54:11 +02006006#define PUT_SINFO_U64(attr, memb) do { \
Omer Efrat397c6572018-06-17 13:06:14 +03006007 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
Johannes Bergd686b922016-04-26 09:54:11 +02006008 nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
6009 sinfo->memb, NL80211_STA_INFO_PAD)) \
6010 goto nla_put_failure; \
6011 } while (0)
Johannes Berg319090b2014-11-17 14:08:11 +01006012
6013 PUT_SINFO(CONNECTED_TIME, connected_time, u32);
6014 PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
Ben Greear6c7a0032019-08-09 11:00:00 -07006015 PUT_SINFO_U64(ASSOC_AT_BOOTTIME, assoc_at);
Johannes Berg319090b2014-11-17 14:08:11 +01006016
Omer Efrat397c6572018-06-17 13:06:14 +03006017 if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES) |
6018 BIT_ULL(NL80211_STA_INFO_RX_BYTES64)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04006019 nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02006020 (u32)sinfo->rx_bytes))
6021 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01006022
Omer Efrat397c6572018-06-17 13:06:14 +03006023 if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES) |
6024 BIT_ULL(NL80211_STA_INFO_TX_BYTES64)) &&
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02006025 nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
6026 (u32)sinfo->tx_bytes))
6027 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01006028
Johannes Bergd686b922016-04-26 09:54:11 +02006029 PUT_SINFO_U64(RX_BYTES64, rx_bytes);
6030 PUT_SINFO_U64(TX_BYTES64, tx_bytes);
Johannes Berg319090b2014-11-17 14:08:11 +01006031 PUT_SINFO(LLID, llid, u16);
6032 PUT_SINFO(PLID, plid, u16);
6033 PUT_SINFO(PLINK_STATE, plink_state, u8);
Johannes Bergd686b922016-04-26 09:54:11 +02006034 PUT_SINFO_U64(RX_DURATION, rx_duration);
Toke Høiland-Jørgensen36647052018-12-18 17:02:07 -08006035 PUT_SINFO_U64(TX_DURATION, tx_duration);
6036
6037 if (wiphy_ext_feature_isset(&rdev->wiphy,
6038 NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
6039 PUT_SINFO(AIRTIME_WEIGHT, airtime_weight, u16);
Johannes Berg319090b2014-11-17 14:08:11 +01006040
John W. Linville66266b32012-03-15 13:25:41 -04006041 switch (rdev->wiphy.signal_type) {
6042 case CFG80211_SIGNAL_TYPE_MBM:
Johannes Berg319090b2014-11-17 14:08:11 +01006043 PUT_SINFO(SIGNAL, signal, u8);
6044 PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
John W. Linville66266b32012-03-15 13:25:41 -04006045 break;
6046 default:
6047 break;
6048 }
Omer Efrat397c6572018-06-17 13:06:14 +03006049 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02006050 if (!nl80211_put_signal(msg, sinfo->chains,
6051 sinfo->chain_signal,
6052 NL80211_STA_INFO_CHAIN_SIGNAL))
6053 goto nla_put_failure;
6054 }
Omer Efrat397c6572018-06-17 13:06:14 +03006055 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02006056 if (!nl80211_put_signal(msg, sinfo->chains,
6057 sinfo->chain_signal_avg,
6058 NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
6059 goto nla_put_failure;
6060 }
Omer Efrat397c6572018-06-17 13:06:14 +03006061 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01006062 if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
6063 NL80211_STA_INFO_TX_BITRATE))
Henning Rogge420e7fa2008-12-11 22:04:19 +01006064 goto nla_put_failure;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01006065 }
Omer Efrat397c6572018-06-17 13:06:14 +03006066 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01006067 if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
6068 NL80211_STA_INFO_RX_BITRATE))
6069 goto nla_put_failure;
Henning Rogge420e7fa2008-12-11 22:04:19 +01006070 }
Johannes Berg319090b2014-11-17 14:08:11 +01006071
6072 PUT_SINFO(RX_PACKETS, rx_packets, u32);
6073 PUT_SINFO(TX_PACKETS, tx_packets, u32);
6074 PUT_SINFO(TX_RETRIES, tx_retries, u32);
6075 PUT_SINFO(TX_FAILED, tx_failed, u32);
6076 PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
Narayanraddi Mastiab606332019-02-07 12:16:05 -08006077 PUT_SINFO(AIRTIME_LINK_METRIC, airtime_link_metric, u32);
Johannes Berg319090b2014-11-17 14:08:11 +01006078 PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
6079 PUT_SINFO(LOCAL_PM, local_pm, u32);
6080 PUT_SINFO(PEER_PM, peer_pm, u32);
6081 PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
Bob Copelanddbdaee72018-10-25 15:48:53 -04006082 PUT_SINFO(CONNECTED_TO_GATE, connected_to_gate, u8);
Markus Theil1303a512020-06-11 16:02:38 +02006083 PUT_SINFO(CONNECTED_TO_AS, connected_to_as, u8);
Johannes Berg319090b2014-11-17 14:08:11 +01006084
Omer Efrat397c6572018-06-17 13:06:14 +03006085 if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM)) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02006086 bss_param = nla_nest_start_noflag(msg,
6087 NL80211_STA_INFO_BSS_PARAM);
Paul Stewartf4263c92011-03-31 09:25:41 -07006088 if (!bss_param)
6089 goto nla_put_failure;
6090
David S. Miller9360ffd2012-03-29 04:41:26 -04006091 if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
6092 nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
6093 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
6094 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
6095 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
6096 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
6097 nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
6098 sinfo->bss_param.dtim_period) ||
6099 nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
6100 sinfo->bss_param.beacon_interval))
6101 goto nla_put_failure;
Paul Stewartf4263c92011-03-31 09:25:41 -07006102
6103 nla_nest_end(msg, bss_param);
6104 }
Omer Efrat397c6572018-06-17 13:06:14 +03006105 if ((sinfo->filled & BIT_ULL(NL80211_STA_INFO_STA_FLAGS)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04006106 nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
6107 sizeof(struct nl80211_sta_flag_update),
6108 &sinfo->sta_flags))
6109 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01006110
Johannes Bergd686b922016-04-26 09:54:11 +02006111 PUT_SINFO_U64(T_OFFSET, t_offset);
6112 PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
6113 PUT_SINFO_U64(BEACON_RX, rx_beacon);
Johannes Berga76b1942014-11-17 14:12:22 +01006114 PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
Ankita Bajaj0d4e14a2018-09-27 18:01:57 +03006115 PUT_SINFO(RX_MPDUS, rx_mpdu_count, u32);
6116 PUT_SINFO(FCS_ERROR_COUNT, fcs_err_count, u32);
Balaji Pothunoori81d54392018-04-16 20:18:40 +05306117 if (wiphy_ext_feature_isset(&rdev->wiphy,
Balaji Pothunoori9c066022018-07-19 18:56:27 +05306118 NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT)) {
6119 PUT_SINFO(ACK_SIGNAL, ack_signal, u8);
6120 PUT_SINFO(ACK_SIGNAL_AVG, avg_ack_signal, s8);
6121 }
Johannes Berg319090b2014-11-17 14:08:11 +01006122
6123#undef PUT_SINFO
Johannes Bergd686b922016-04-26 09:54:11 +02006124#undef PUT_SINFO_U64
Johannes Berg6de39802014-12-19 12:34:00 +01006125
Arend van Spriel8689c052018-05-10 13:50:12 +02006126 if (sinfo->pertid) {
Johannes Berg6de39802014-12-19 12:34:00 +01006127 struct nlattr *tidsattr;
6128 int tid;
6129
Michal Kubecekae0be8d2019-04-26 11:13:06 +02006130 tidsattr = nla_nest_start_noflag(msg,
6131 NL80211_STA_INFO_TID_STATS);
Johannes Berg6de39802014-12-19 12:34:00 +01006132 if (!tidsattr)
6133 goto nla_put_failure;
6134
6135 for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
6136 struct cfg80211_tid_stats *tidstats;
6137 struct nlattr *tidattr;
6138
6139 tidstats = &sinfo->pertid[tid];
6140
6141 if (!tidstats->filled)
6142 continue;
6143
Michal Kubecekae0be8d2019-04-26 11:13:06 +02006144 tidattr = nla_nest_start_noflag(msg, tid + 1);
Johannes Berg6de39802014-12-19 12:34:00 +01006145 if (!tidattr)
6146 goto nla_put_failure;
6147
Johannes Bergd686b922016-04-26 09:54:11 +02006148#define PUT_TIDVAL_U64(attr, memb) do { \
Johannes Berg6de39802014-12-19 12:34:00 +01006149 if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
Johannes Bergd686b922016-04-26 09:54:11 +02006150 nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
6151 tidstats->memb, NL80211_TID_STATS_PAD)) \
Johannes Berg6de39802014-12-19 12:34:00 +01006152 goto nla_put_failure; \
6153 } while (0)
6154
Johannes Bergd686b922016-04-26 09:54:11 +02006155 PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
6156 PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
6157 PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
6158 PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
Johannes Berg6de39802014-12-19 12:34:00 +01006159
Johannes Bergd686b922016-04-26 09:54:11 +02006160#undef PUT_TIDVAL_U64
Toke Høiland-Jørgensen52539ca2018-05-08 13:03:50 +02006161 if ((tidstats->filled &
6162 BIT(NL80211_TID_STATS_TXQ_STATS)) &&
6163 !nl80211_put_txq_stats(msg, &tidstats->txq_stats,
6164 NL80211_TID_STATS_TXQ_STATS))
6165 goto nla_put_failure;
6166
Johannes Berg6de39802014-12-19 12:34:00 +01006167 nla_nest_end(msg, tidattr);
6168 }
6169
6170 nla_nest_end(msg, tidsattr);
6171 }
6172
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006173 nla_nest_end(msg, sinfoattr);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006174
Johannes Berg319090b2014-11-17 14:08:11 +01006175 if (sinfo->assoc_req_ies_len &&
David S. Miller9360ffd2012-03-29 04:41:26 -04006176 nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
6177 sinfo->assoc_req_ies))
6178 goto nla_put_failure;
Jouni Malinen50d3dfb2011-08-08 12:11:52 +03006179
Johannes Berg7ea3e112018-05-18 11:40:44 +02006180 cfg80211_sinfo_release_content(sinfo);
Johannes Berg053c0952015-01-16 22:09:00 +01006181 genlmsg_end(msg, hdr);
6182 return 0;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006183
6184 nla_put_failure:
Johannes Berg7ea3e112018-05-18 11:40:44 +02006185 cfg80211_sinfo_release_content(sinfo);
Thomas Grafbc3ed282008-06-03 16:36:54 -07006186 genlmsg_cancel(msg, hdr);
6187 return -EMSGSIZE;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006188}
6189
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006190static int nl80211_dump_station(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02006191 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006192{
Johannes Berg73887fd2018-05-18 09:57:55 +02006193 struct station_info sinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08006194 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02006195 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006196 u8 mac_addr[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02006197 int sta_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006198 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006199
Johannes Berg5297c652018-09-27 14:36:44 +02006200 err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02006201 if (err)
Johannes Berga05829a2021-01-22 16:19:43 +01006202 return err;
6203 /* nl80211_prepare_wdev_dump acquired it in the successful case */
6204 __acquire(&rdev->wiphy.mtx);
Johannes Bergbba95fe2008-07-29 13:22:51 +02006205
Johannes Berg97990a02013-04-19 01:02:55 +02006206 if (!wdev->netdev) {
6207 err = -EINVAL;
6208 goto out_err;
6209 }
6210
Zhao, Gang1b8ec872014-04-21 12:53:02 +08006211 if (!rdev->ops->dump_station) {
Jouni Malineneec60b02009-03-20 21:21:19 +02006212 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02006213 goto out_err;
6214 }
6215
Johannes Bergbba95fe2008-07-29 13:22:51 +02006216 while (1) {
Johannes Berg73887fd2018-05-18 09:57:55 +02006217 memset(&sinfo, 0, sizeof(sinfo));
Zhao, Gang1b8ec872014-04-21 12:53:02 +08006218 err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
Johannes Berg73887fd2018-05-18 09:57:55 +02006219 mac_addr, &sinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02006220 if (err == -ENOENT)
6221 break;
6222 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01006223 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02006224
Johannes Bergcf5ead82014-11-14 17:14:00 +01006225 if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
Eric W. Biederman15e47302012-09-07 20:12:54 +00006226 NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02006227 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08006228 rdev, wdev->netdev, mac_addr,
Johannes Berg73887fd2018-05-18 09:57:55 +02006229 &sinfo) < 0)
Johannes Bergbba95fe2008-07-29 13:22:51 +02006230 goto out;
6231
6232 sta_idx++;
6233 }
6234
Johannes Bergbba95fe2008-07-29 13:22:51 +02006235 out:
Johannes Berg97990a02013-04-19 01:02:55 +02006236 cb->args[2] = sta_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02006237 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02006238 out_err:
Johannes Berga05829a2021-01-22 16:19:43 +01006239 wiphy_unlock(&rdev->wiphy);
Johannes Bergbba95fe2008-07-29 13:22:51 +02006240
6241 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006242}
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006243
Johannes Berg5727ef12007-12-19 02:03:34 +01006244static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
6245{
Johannes Berg4c476992010-10-04 21:36:35 +02006246 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6247 struct net_device *dev = info->user_ptr[1];
Johannes Berg73887fd2018-05-18 09:57:55 +02006248 struct station_info sinfo;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006249 struct sk_buff *msg;
6250 u8 *mac_addr = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02006251 int err;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006252
Johannes Berg73887fd2018-05-18 09:57:55 +02006253 memset(&sinfo, 0, sizeof(sinfo));
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006254
Johannes Berg73887fd2018-05-18 09:57:55 +02006255 if (!info->attrs[NL80211_ATTR_MAC])
6256 return -EINVAL;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006257
6258 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
6259
Johannes Berg73887fd2018-05-18 09:57:55 +02006260 if (!rdev->ops->get_station)
6261 return -EOPNOTSUPP;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006262
Johannes Berg73887fd2018-05-18 09:57:55 +02006263 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006264 if (err)
Johannes Berg73887fd2018-05-18 09:57:55 +02006265 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006266
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07006267 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg7ea3e112018-05-18 11:40:44 +02006268 if (!msg) {
Denis Kenziorba8f5662018-05-21 19:21:42 -05006269 cfg80211_sinfo_release_content(&sinfo);
Johannes Berg73887fd2018-05-18 09:57:55 +02006270 return -ENOMEM;
Johannes Berg7ea3e112018-05-18 11:40:44 +02006271 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006272
Johannes Bergcf5ead82014-11-14 17:14:00 +01006273 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
6274 info->snd_portid, info->snd_seq, 0,
Johannes Berg73887fd2018-05-18 09:57:55 +02006275 rdev, dev, mac_addr, &sinfo) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02006276 nlmsg_free(msg);
Johannes Berg73887fd2018-05-18 09:57:55 +02006277 return -ENOBUFS;
Johannes Berg4c476992010-10-04 21:36:35 +02006278 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01006279
Johannes Berg73887fd2018-05-18 09:57:55 +02006280 return genlmsg_reply(msg, info);
Johannes Berg5727ef12007-12-19 02:03:34 +01006281}
6282
Johannes Berg77ee7c82013-02-15 00:48:33 +01006283int cfg80211_check_station_change(struct wiphy *wiphy,
6284 struct station_parameters *params,
6285 enum cfg80211_station_type statype)
6286{
Ayala Bekere4208422015-10-23 11:20:06 +03006287 if (params->listen_interval != -1 &&
6288 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01006289 return -EINVAL;
Ayala Bekere4208422015-10-23 11:20:06 +03006290
Ayala Beker17b94242016-03-17 15:41:38 +02006291 if (params->support_p2p_ps != -1 &&
6292 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
6293 return -EINVAL;
6294
Arik Nemtsovc72e1142014-07-17 17:14:29 +03006295 if (params->aid &&
Ayala Bekere4208422015-10-23 11:20:06 +03006296 !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
6297 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01006298 return -EINVAL;
6299
6300 /* When you run into this, adjust the code below for the new flag */
6301 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
6302
6303 switch (statype) {
Thomas Pederseneef941e2013-03-04 13:06:11 -08006304 case CFG80211_STA_MESH_PEER_KERNEL:
6305 case CFG80211_STA_MESH_PEER_USER:
Johannes Berg77ee7c82013-02-15 00:48:33 +01006306 /*
6307 * No ignoring the TDLS flag here -- the userspace mesh
6308 * code doesn't have the bug of including TDLS in the
6309 * mask everywhere.
6310 */
6311 if (params->sta_flags_mask &
6312 ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
6313 BIT(NL80211_STA_FLAG_MFP) |
6314 BIT(NL80211_STA_FLAG_AUTHORIZED)))
6315 return -EINVAL;
6316 break;
6317 case CFG80211_STA_TDLS_PEER_SETUP:
6318 case CFG80211_STA_TDLS_PEER_ACTIVE:
6319 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
6320 return -EINVAL;
6321 /* ignore since it can't change */
6322 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
6323 break;
6324 default:
6325 /* disallow mesh-specific things */
6326 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
6327 return -EINVAL;
6328 if (params->local_pm)
6329 return -EINVAL;
6330 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
6331 return -EINVAL;
6332 }
6333
6334 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
6335 statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
6336 /* TDLS can't be set, ... */
6337 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
6338 return -EINVAL;
6339 /*
6340 * ... but don't bother the driver with it. This works around
6341 * a hostapd/wpa_supplicant issue -- it always includes the
6342 * TLDS_PEER flag in the mask even for AP mode.
6343 */
6344 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
6345 }
6346
Ayala Beker47edb112015-09-21 15:49:53 +03006347 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
6348 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01006349 /* reject other things that can't change */
6350 if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
6351 return -EINVAL;
6352 if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
6353 return -EINVAL;
6354 if (params->supported_rates)
6355 return -EINVAL;
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006356 if (params->ext_capab || params->ht_capa || params->vht_capa ||
6357 params->he_capa)
Johannes Berg77ee7c82013-02-15 00:48:33 +01006358 return -EINVAL;
6359 }
6360
Ayala Beker47edb112015-09-21 15:49:53 +03006361 if (statype != CFG80211_STA_AP_CLIENT &&
6362 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01006363 if (params->vlan)
6364 return -EINVAL;
6365 }
6366
6367 switch (statype) {
6368 case CFG80211_STA_AP_MLME_CLIENT:
6369 /* Use this only for authorizing/unauthorizing a station */
6370 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
6371 return -EOPNOTSUPP;
6372 break;
6373 case CFG80211_STA_AP_CLIENT:
Ayala Beker47edb112015-09-21 15:49:53 +03006374 case CFG80211_STA_AP_CLIENT_UNASSOC:
Johannes Berg77ee7c82013-02-15 00:48:33 +01006375 /* accept only the listed bits */
6376 if (params->sta_flags_mask &
6377 ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
6378 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
6379 BIT(NL80211_STA_FLAG_ASSOCIATED) |
6380 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
6381 BIT(NL80211_STA_FLAG_WME) |
6382 BIT(NL80211_STA_FLAG_MFP)))
6383 return -EINVAL;
6384
6385 /* but authenticated/associated only if driver handles it */
6386 if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
6387 params->sta_flags_mask &
6388 (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
6389 BIT(NL80211_STA_FLAG_ASSOCIATED)))
6390 return -EINVAL;
6391 break;
6392 case CFG80211_STA_IBSS:
6393 case CFG80211_STA_AP_STA:
6394 /* reject any changes other than AUTHORIZED */
6395 if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
6396 return -EINVAL;
6397 break;
6398 case CFG80211_STA_TDLS_PEER_SETUP:
6399 /* reject any changes other than AUTHORIZED or WME */
6400 if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
6401 BIT(NL80211_STA_FLAG_WME)))
6402 return -EINVAL;
6403 /* force (at least) rates when authorizing */
6404 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
6405 !params->supported_rates)
6406 return -EINVAL;
6407 break;
6408 case CFG80211_STA_TDLS_PEER_ACTIVE:
6409 /* reject any changes */
6410 return -EINVAL;
Thomas Pederseneef941e2013-03-04 13:06:11 -08006411 case CFG80211_STA_MESH_PEER_KERNEL:
Johannes Berg77ee7c82013-02-15 00:48:33 +01006412 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
6413 return -EINVAL;
6414 break;
Thomas Pederseneef941e2013-03-04 13:06:11 -08006415 case CFG80211_STA_MESH_PEER_USER:
Chun-Yeow Yeoh42925042015-04-18 01:30:02 +08006416 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
6417 params->plink_action != NL80211_PLINK_ACTION_BLOCK)
Johannes Berg77ee7c82013-02-15 00:48:33 +01006418 return -EINVAL;
6419 break;
6420 }
6421
Beni Lev06f7c882016-07-19 19:28:56 +03006422 /*
6423 * Older kernel versions ignored this attribute entirely, so don't
6424 * reject attempts to update it but mark it as unused instead so the
6425 * driver won't look at the data.
6426 */
6427 if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
6428 statype != CFG80211_STA_TDLS_PEER_SETUP)
6429 params->opmode_notif_used = false;
6430
Johannes Berg77ee7c82013-02-15 00:48:33 +01006431 return 0;
6432}
6433EXPORT_SYMBOL(cfg80211_check_station_change);
6434
Johannes Berg5727ef12007-12-19 02:03:34 +01006435/*
Felix Fietkauc258d2d2009-11-11 17:23:31 +01006436 * Get vlan interface making sure it is running and on the right wiphy.
Johannes Berg5727ef12007-12-19 02:03:34 +01006437 */
Johannes Berg80b99892011-11-18 16:23:01 +01006438static struct net_device *get_vlan(struct genl_info *info,
6439 struct cfg80211_registered_device *rdev)
Johannes Berg5727ef12007-12-19 02:03:34 +01006440{
Johannes Berg463d0182009-07-14 00:33:35 +02006441 struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
Johannes Berg80b99892011-11-18 16:23:01 +01006442 struct net_device *v;
6443 int ret;
Johannes Berg5727ef12007-12-19 02:03:34 +01006444
Johannes Berg80b99892011-11-18 16:23:01 +01006445 if (!vlanattr)
6446 return NULL;
6447
6448 v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
6449 if (!v)
6450 return ERR_PTR(-ENODEV);
6451
6452 if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
6453 ret = -EINVAL;
6454 goto error;
Johannes Berg5727ef12007-12-19 02:03:34 +01006455 }
Johannes Berg80b99892011-11-18 16:23:01 +01006456
Johannes Berg77ee7c82013-02-15 00:48:33 +01006457 if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
6458 v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
6459 v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
6460 ret = -EINVAL;
6461 goto error;
6462 }
6463
Johannes Berg80b99892011-11-18 16:23:01 +01006464 if (!netif_running(v)) {
6465 ret = -ENETDOWN;
6466 goto error;
6467 }
6468
6469 return v;
6470 error:
6471 dev_put(v);
6472 return ERR_PTR(ret);
Johannes Berg5727ef12007-12-19 02:03:34 +01006473}
6474
Johannes Berg94e860f2014-01-20 23:58:15 +01006475static const struct nla_policy
6476nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
Jouni Malinendf881292013-02-14 21:10:54 +02006477 [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
6478 [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
6479};
6480
Johannes Bergff276692013-02-15 00:09:01 +01006481static int nl80211_parse_sta_wme(struct genl_info *info,
6482 struct station_parameters *params)
Jouni Malinendf881292013-02-14 21:10:54 +02006483{
Jouni Malinendf881292013-02-14 21:10:54 +02006484 struct nlattr *tb[NL80211_STA_WME_MAX + 1];
6485 struct nlattr *nla;
6486 int err;
6487
Jouni Malinendf881292013-02-14 21:10:54 +02006488 /* parse WME attributes if present */
6489 if (!info->attrs[NL80211_ATTR_STA_WME])
6490 return 0;
6491
6492 nla = info->attrs[NL80211_ATTR_STA_WME];
Johannes Berg8cb08172019-04-26 14:07:28 +02006493 err = nla_parse_nested_deprecated(tb, NL80211_STA_WME_MAX, nla,
6494 nl80211_sta_wme_policy,
6495 info->extack);
Jouni Malinendf881292013-02-14 21:10:54 +02006496 if (err)
6497 return err;
6498
6499 if (tb[NL80211_STA_WME_UAPSD_QUEUES])
6500 params->uapsd_queues = nla_get_u8(
6501 tb[NL80211_STA_WME_UAPSD_QUEUES]);
6502 if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
6503 return -EINVAL;
6504
6505 if (tb[NL80211_STA_WME_MAX_SP])
6506 params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
6507
6508 if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
6509 return -EINVAL;
6510
6511 params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
6512
6513 return 0;
6514}
6515
Sunil Duttc01fc9a2013-10-09 20:45:21 +05306516static int nl80211_parse_sta_channel_info(struct genl_info *info,
6517 struct station_parameters *params)
6518{
6519 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
6520 params->supported_channels =
6521 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
6522 params->supported_channels_len =
6523 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
6524 /*
6525 * Need to include at least one (first channel, number of
Johannes Bergcb9abd42020-08-05 15:47:16 +02006526 * channels) tuple for each subband (checked in policy),
6527 * and must have proper tuples for the rest of the data as well.
Sunil Duttc01fc9a2013-10-09 20:45:21 +05306528 */
Sunil Duttc01fc9a2013-10-09 20:45:21 +05306529 if (params->supported_channels_len % 2)
6530 return -EINVAL;
6531 }
6532
6533 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
6534 params->supported_oper_classes =
6535 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
6536 params->supported_oper_classes_len =
6537 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
Sunil Duttc01fc9a2013-10-09 20:45:21 +05306538 }
6539 return 0;
6540}
6541
Johannes Bergff276692013-02-15 00:09:01 +01006542static int nl80211_set_station_tdls(struct genl_info *info,
6543 struct station_parameters *params)
6544{
Sunil Duttc01fc9a2013-10-09 20:45:21 +05306545 int err;
Johannes Bergff276692013-02-15 00:09:01 +01006546 /* Dummy STA entry gets updated once the peer capabilities are known */
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03006547 if (info->attrs[NL80211_ATTR_PEER_AID])
6548 params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Johannes Bergff276692013-02-15 00:09:01 +01006549 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
6550 params->ht_capa =
6551 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
6552 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
6553 params->vht_capa =
6554 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006555 if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
6556 params->he_capa =
6557 nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
6558 params->he_capa_len =
6559 nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006560 }
Johannes Bergff276692013-02-15 00:09:01 +01006561
Sunil Duttc01fc9a2013-10-09 20:45:21 +05306562 err = nl80211_parse_sta_channel_info(info, params);
6563 if (err)
6564 return err;
6565
Johannes Bergff276692013-02-15 00:09:01 +01006566 return nl80211_parse_sta_wme(info, params);
6567}
6568
Ashok Raj Nagarajane96d1cd2019-03-29 16:18:21 +05306569static int nl80211_parse_sta_txpower_setting(struct genl_info *info,
6570 struct station_parameters *params)
6571{
6572 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6573 int idx;
6574
6575 if (info->attrs[NL80211_ATTR_STA_TX_POWER_SETTING]) {
6576 if (!rdev->ops->set_tx_power ||
6577 !wiphy_ext_feature_isset(&rdev->wiphy,
6578 NL80211_EXT_FEATURE_STA_TX_PWR))
6579 return -EOPNOTSUPP;
6580
6581 idx = NL80211_ATTR_STA_TX_POWER_SETTING;
6582 params->txpwr.type = nla_get_u8(info->attrs[idx]);
6583
6584 if (params->txpwr.type == NL80211_TX_POWER_LIMITED) {
6585 idx = NL80211_ATTR_STA_TX_POWER;
6586
6587 if (info->attrs[idx])
6588 params->txpwr.power =
6589 nla_get_s16(info->attrs[idx]);
6590 else
6591 return -EINVAL;
6592 }
6593 params->sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER;
6594 }
6595
6596 return 0;
6597}
6598
Johannes Berg5727ef12007-12-19 02:03:34 +01006599static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
6600{
Johannes Berg4c476992010-10-04 21:36:35 +02006601 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02006602 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01006603 struct station_parameters params;
Johannes Berg77ee7c82013-02-15 00:48:33 +01006604 u8 *mac_addr;
6605 int err;
Johannes Berg5727ef12007-12-19 02:03:34 +01006606
6607 memset(&params, 0, sizeof(params));
6608
Johannes Berg77ee7c82013-02-15 00:48:33 +01006609 if (!rdev->ops->change_station)
6610 return -EOPNOTSUPP;
6611
Ayala Bekere4208422015-10-23 11:20:06 +03006612 /*
6613 * AID and listen_interval properties can be set only for unassociated
6614 * station. Include these parameters here and will check them in
6615 * cfg80211_check_station_change().
6616 */
Ayala Bekera9bc31e2015-11-26 16:26:12 +01006617 if (info->attrs[NL80211_ATTR_STA_AID])
6618 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Ayala Bekere4208422015-10-23 11:20:06 +03006619
Gurumoorthi Gnanasambandhan14f34e362019-10-31 23:46:40 +02006620 if (info->attrs[NL80211_ATTR_VLAN_ID])
6621 params.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);
6622
Ayala Bekere4208422015-10-23 11:20:06 +03006623 if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
6624 params.listen_interval =
6625 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
6626 else
6627 params.listen_interval = -1;
Johannes Berg5727ef12007-12-19 02:03:34 +01006628
Johannes Bergab0d76f2018-10-02 10:00:07 +02006629 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS])
6630 params.support_p2p_ps =
6631 nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
6632 else
Ayala Beker17b94242016-03-17 15:41:38 +02006633 params.support_p2p_ps = -1;
Ayala Beker17b94242016-03-17 15:41:38 +02006634
Johannes Berg5727ef12007-12-19 02:03:34 +01006635 if (!info->attrs[NL80211_ATTR_MAC])
6636 return -EINVAL;
6637
6638 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
6639
6640 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
6641 params.supported_rates =
6642 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
6643 params.supported_rates_len =
6644 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
6645 }
6646
Jouni Malinen9d62a982013-02-14 21:10:13 +02006647 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
6648 params.capability =
6649 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
6650 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
6651 }
6652
6653 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
6654 params.ext_capab =
6655 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
6656 params.ext_capab_len =
6657 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
6658 }
6659
Johannes Bergbdd3ae32012-01-02 13:30:03 +01006660 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01006661 return -EINVAL;
6662
Johannes Bergab0d76f2018-10-02 10:00:07 +02006663 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006664 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01006665 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01006666
Johannes Bergf8bacc22013-02-14 23:27:01 +01006667 if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
Javier Cardona9c3990a2011-05-03 16:57:11 -07006668 params.plink_state =
Johannes Bergf8bacc22013-02-14 23:27:01 +01006669 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
Johannes Bergab0d76f2018-10-02 10:00:07 +02006670 if (info->attrs[NL80211_ATTR_MESH_PEER_AID])
Masashi Honma7d27a0b2016-07-01 10:19:34 +09006671 params.peer_aid = nla_get_u16(
6672 info->attrs[NL80211_ATTR_MESH_PEER_AID]);
Johannes Bergf8bacc22013-02-14 23:27:01 +01006673 params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
6674 }
Javier Cardona9c3990a2011-05-03 16:57:11 -07006675
Johannes Bergab0d76f2018-10-02 10:00:07 +02006676 if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE])
6677 params.local_pm = nla_get_u32(
Marco Porsch3b1c5a52013-01-07 16:04:52 +01006678 info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
6679
Beni Lev06f7c882016-07-19 19:28:56 +03006680 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
6681 params.opmode_notif_used = true;
6682 params.opmode_notif =
6683 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
6684 }
6685
Rajkumar Manoharan43e64bf2020-05-28 21:34:29 +02006686 if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
6687 params.he_6ghz_capa =
Johannes Bergfce2ff72020-08-05 15:35:18 +02006688 nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
Rajkumar Manoharan43e64bf2020-05-28 21:34:29 +02006689
Toke Høiland-Jørgensen36647052018-12-18 17:02:07 -08006690 if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
6691 params.airtime_weight =
6692 nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
6693
6694 if (params.airtime_weight &&
6695 !wiphy_ext_feature_isset(&rdev->wiphy,
6696 NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
6697 return -EOPNOTSUPP;
6698
Ashok Raj Nagarajane96d1cd2019-03-29 16:18:21 +05306699 err = nl80211_parse_sta_txpower_setting(info, &params);
6700 if (err)
6701 return err;
6702
Johannes Berg77ee7c82013-02-15 00:48:33 +01006703 /* Include parameters for TDLS peer (will check later) */
6704 err = nl80211_set_station_tdls(info, &params);
6705 if (err)
6706 return err;
6707
6708 params.vlan = get_vlan(info, rdev);
6709 if (IS_ERR(params.vlan))
6710 return PTR_ERR(params.vlan);
6711
Johannes Berga97f4422009-06-18 17:23:43 +02006712 switch (dev->ieee80211_ptr->iftype) {
6713 case NL80211_IFTYPE_AP:
6714 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02006715 case NL80211_IFTYPE_P2P_GO:
Johannes Berg074ac8d2010-09-16 14:58:22 +02006716 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berga97f4422009-06-18 17:23:43 +02006717 case NL80211_IFTYPE_STATION:
Antonio Quartulli267335d2012-01-31 20:25:47 +01006718 case NL80211_IFTYPE_ADHOC:
Johannes Berga97f4422009-06-18 17:23:43 +02006719 case NL80211_IFTYPE_MESH_POINT:
Johannes Berga97f4422009-06-18 17:23:43 +02006720 break;
6721 default:
Johannes Berg77ee7c82013-02-15 00:48:33 +01006722 err = -EOPNOTSUPP;
6723 goto out_put_vlan;
Johannes Berg034d6552009-05-27 10:35:29 +02006724 }
6725
Johannes Berg77ee7c82013-02-15 00:48:33 +01006726 /* driver will call cfg80211_check_station_change() */
Hila Gonene35e4d22012-06-27 17:19:42 +03006727 err = rdev_change_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01006728
Johannes Berg77ee7c82013-02-15 00:48:33 +01006729 out_put_vlan:
Yajun Deng1160dfa2021-08-05 19:55:27 +08006730 dev_put(params.vlan);
Johannes Berg3b858752009-03-12 09:55:09 +01006731
Johannes Berg5727ef12007-12-19 02:03:34 +01006732 return err;
6733}
6734
6735static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
6736{
Johannes Berg4c476992010-10-04 21:36:35 +02006737 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg5727ef12007-12-19 02:03:34 +01006738 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02006739 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01006740 struct station_parameters params;
6741 u8 *mac_addr = NULL;
Johannes Bergbda95eb2015-11-26 16:26:13 +01006742 u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
6743 BIT(NL80211_STA_FLAG_ASSOCIATED);
Johannes Berg5727ef12007-12-19 02:03:34 +01006744
6745 memset(&params, 0, sizeof(params));
6746
Johannes Berg984c3112013-02-14 23:43:25 +01006747 if (!rdev->ops->add_station)
6748 return -EOPNOTSUPP;
6749
Johannes Berg5727ef12007-12-19 02:03:34 +01006750 if (!info->attrs[NL80211_ATTR_MAC])
6751 return -EINVAL;
6752
Johannes Berg5727ef12007-12-19 02:03:34 +01006753 if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
6754 return -EINVAL;
6755
6756 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
6757 return -EINVAL;
6758
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03006759 if (!info->attrs[NL80211_ATTR_STA_AID] &&
6760 !info->attrs[NL80211_ATTR_PEER_AID])
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02006761 return -EINVAL;
6762
Johannes Berg5727ef12007-12-19 02:03:34 +01006763 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
6764 params.supported_rates =
6765 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
6766 params.supported_rates_len =
6767 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
6768 params.listen_interval =
6769 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
Johannes Berg51b50fb2009-05-24 16:42:30 +02006770
Gurumoorthi Gnanasambandhan14f34e362019-10-31 23:46:40 +02006771 if (info->attrs[NL80211_ATTR_VLAN_ID])
6772 params.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);
6773
Ayala Beker17b94242016-03-17 15:41:38 +02006774 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
Johannes Bergab0d76f2018-10-02 10:00:07 +02006775 params.support_p2p_ps =
6776 nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
Ayala Beker17b94242016-03-17 15:41:38 +02006777 } else {
6778 /*
6779 * if not specified, assume it's supported for P2P GO interface,
6780 * and is NOT supported for AP interface
6781 */
6782 params.support_p2p_ps =
6783 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO;
6784 }
6785
Jouni Malinen3d124ea2013-05-27 18:24:02 +03006786 if (info->attrs[NL80211_ATTR_PEER_AID])
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03006787 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Jouni Malinen3d124ea2013-05-27 18:24:02 +03006788 else
6789 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Johannes Berg51b50fb2009-05-24 16:42:30 +02006790
Jouni Malinen9d62a982013-02-14 21:10:13 +02006791 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
6792 params.capability =
6793 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
6794 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
6795 }
6796
6797 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
6798 params.ext_capab =
6799 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
6800 params.ext_capab_len =
6801 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
6802 }
6803
Jouni Malinen36aedc92008-08-25 11:58:58 +03006804 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
6805 params.ht_capa =
6806 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
Johannes Berg5727ef12007-12-19 02:03:34 +01006807
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +00006808 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
6809 params.vht_capa =
6810 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
6811
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006812 if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
6813 params.he_capa =
6814 nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
6815 params.he_capa_len =
6816 nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006817 }
6818
Rajkumar Manoharan43e64bf2020-05-28 21:34:29 +02006819 if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
6820 params.he_6ghz_capa =
6821 nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
6822
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +01006823 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
6824 params.opmode_notif_used = true;
6825 params.opmode_notif =
6826 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
6827 }
6828
Johannes Bergab0d76f2018-10-02 10:00:07 +02006829 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
Javier Cardona96b78df2011-04-07 15:08:33 -07006830 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01006831 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
Javier Cardona96b78df2011-04-07 15:08:33 -07006832
Toke Høiland-Jørgensen36647052018-12-18 17:02:07 -08006833 if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
6834 params.airtime_weight =
6835 nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
6836
6837 if (params.airtime_weight &&
6838 !wiphy_ext_feature_isset(&rdev->wiphy,
6839 NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
6840 return -EOPNOTSUPP;
6841
Ashok Raj Nagarajane96d1cd2019-03-29 16:18:21 +05306842 err = nl80211_parse_sta_txpower_setting(info, &params);
6843 if (err)
6844 return err;
6845
Sunil Duttc01fc9a2013-10-09 20:45:21 +05306846 err = nl80211_parse_sta_channel_info(info, &params);
6847 if (err)
6848 return err;
6849
Johannes Bergff276692013-02-15 00:09:01 +01006850 err = nl80211_parse_sta_wme(info, &params);
6851 if (err)
6852 return err;
Johannes Bergbdd90d52011-12-14 12:20:27 +01006853
Johannes Bergbdd3ae32012-01-02 13:30:03 +01006854 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01006855 return -EINVAL;
6856
Johannes Berg496fcc22015-03-12 08:53:27 +02006857 /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
6858 * as userspace might just pass through the capabilities from the IEs
6859 * directly, rather than enforcing this restriction and returning an
6860 * error in this case.
6861 */
6862 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
6863 params.ht_capa = NULL;
6864 params.vht_capa = NULL;
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006865
6866 /* HE requires WME */
Rajkumar Manoharan43e64bf2020-05-28 21:34:29 +02006867 if (params.he_capa_len || params.he_6ghz_capa)
Luca Coelhoc4cbaf72018-06-09 09:14:42 +03006868 return -EINVAL;
Johannes Berg496fcc22015-03-12 08:53:27 +02006869 }
6870
Rajkumar Manoharan43e64bf2020-05-28 21:34:29 +02006871 /* Ensure that HT/VHT capabilities are not set for 6 GHz HE STA */
6872 if (params.he_6ghz_capa && (params.ht_capa || params.vht_capa))
6873 return -EINVAL;
6874
Johannes Berg77ee7c82013-02-15 00:48:33 +01006875 /* When you run into this, adjust the code below for the new flag */
6876 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
6877
Johannes Bergbdd90d52011-12-14 12:20:27 +01006878 switch (dev->ieee80211_ptr->iftype) {
6879 case NL80211_IFTYPE_AP:
6880 case NL80211_IFTYPE_AP_VLAN:
6881 case NL80211_IFTYPE_P2P_GO:
Johannes Berg984c3112013-02-14 23:43:25 +01006882 /* ignore WME attributes if iface/sta is not capable */
6883 if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
6884 !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
6885 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
Eliad Pellerc75786c2011-08-23 14:37:46 +03006886
Johannes Bergbdd90d52011-12-14 12:20:27 +01006887 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03006888 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
6889 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02006890 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01006891 /* but don't bother the driver with it */
6892 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
Eliad Pellerc75786c2011-08-23 14:37:46 +03006893
Johannes Bergd582cff2012-10-26 17:53:44 +02006894 /* allow authenticated/associated only if driver handles it */
6895 if (!(rdev->wiphy.features &
6896 NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
Johannes Bergbda95eb2015-11-26 16:26:13 +01006897 params.sta_flags_mask & auth_assoc)
Johannes Bergd582cff2012-10-26 17:53:44 +02006898 return -EINVAL;
6899
Johannes Bergbda95eb2015-11-26 16:26:13 +01006900 /* Older userspace, or userspace wanting to be compatible with
6901 * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
6902 * and assoc flags in the mask, but assumes the station will be
6903 * added as associated anyway since this was the required driver
6904 * behaviour before NL80211_FEATURE_FULL_AP_CLIENT_STATE was
6905 * introduced.
6906 * In order to not bother drivers with this quirk in the API
6907 * set the flags in both the mask and set for new stations in
6908 * this case.
6909 */
6910 if (!(params.sta_flags_mask & auth_assoc)) {
6911 params.sta_flags_mask |= auth_assoc;
6912 params.sta_flags_set |= auth_assoc;
6913 }
6914
Johannes Bergbdd90d52011-12-14 12:20:27 +01006915 /* must be last in here for error handling */
6916 params.vlan = get_vlan(info, rdev);
6917 if (IS_ERR(params.vlan))
6918 return PTR_ERR(params.vlan);
6919 break;
6920 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg984c3112013-02-14 23:43:25 +01006921 /* ignore uAPSD data */
6922 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
6923
Johannes Bergd582cff2012-10-26 17:53:44 +02006924 /* associated is disallowed */
6925 if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
6926 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01006927 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03006928 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
6929 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02006930 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01006931 break;
6932 case NL80211_IFTYPE_STATION:
Johannes Berg93d08f02013-03-04 09:29:46 +01006933 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg984c3112013-02-14 23:43:25 +01006934 /* ignore uAPSD data */
6935 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
6936
Johannes Berg77ee7c82013-02-15 00:48:33 +01006937 /* these are disallowed */
6938 if (params.sta_flags_mask &
6939 (BIT(NL80211_STA_FLAG_ASSOCIATED) |
6940 BIT(NL80211_STA_FLAG_AUTHENTICATED)))
Johannes Bergd582cff2012-10-26 17:53:44 +02006941 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01006942 /* Only TDLS peers can be added */
6943 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
6944 return -EINVAL;
6945 /* Can only add if TDLS ... */
6946 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
6947 return -EOPNOTSUPP;
6948 /* ... with external setup is supported */
6949 if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
6950 return -EOPNOTSUPP;
Johannes Berg77ee7c82013-02-15 00:48:33 +01006951 /*
6952 * Older wpa_supplicant versions always mark the TDLS peer
6953 * as authorized, but it shouldn't yet be.
6954 */
6955 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
Johannes Bergbdd90d52011-12-14 12:20:27 +01006956 break;
6957 default:
6958 return -EOPNOTSUPP;
Eliad Pellerc75786c2011-08-23 14:37:46 +03006959 }
6960
Johannes Bergbdd90d52011-12-14 12:20:27 +01006961 /* be aware of params.vlan when changing code here */
Johannes Berg5727ef12007-12-19 02:03:34 +01006962
Hila Gonene35e4d22012-06-27 17:19:42 +03006963 err = rdev_add_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01006964
Yajun Deng1160dfa2021-08-05 19:55:27 +08006965 dev_put(params.vlan);
Johannes Berg5727ef12007-12-19 02:03:34 +01006966 return err;
6967}
6968
6969static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
6970{
Johannes Berg4c476992010-10-04 21:36:35 +02006971 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6972 struct net_device *dev = info->user_ptr[1];
Jouni Malinen89c771e2014-10-10 20:52:40 +03006973 struct station_del_parameters params;
6974
6975 memset(&params, 0, sizeof(params));
Johannes Berg5727ef12007-12-19 02:03:34 +01006976
6977 if (info->attrs[NL80211_ATTR_MAC])
Jouni Malinen89c771e2014-10-10 20:52:40 +03006978 params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg5727ef12007-12-19 02:03:34 +01006979
Johannes Berg306b79e2020-03-20 11:38:35 +01006980 switch (dev->ieee80211_ptr->iftype) {
6981 case NL80211_IFTYPE_AP:
6982 case NL80211_IFTYPE_AP_VLAN:
6983 case NL80211_IFTYPE_MESH_POINT:
6984 case NL80211_IFTYPE_P2P_GO:
6985 /* always accept these */
6986 break;
6987 case NL80211_IFTYPE_ADHOC:
6988 /* conditionally accept */
6989 if (wiphy_ext_feature_isset(&rdev->wiphy,
6990 NL80211_EXT_FEATURE_DEL_IBSS_STA))
6991 break;
Nicolas Cavallariedafcf42020-03-05 14:57:53 +01006992 return -EINVAL;
Johannes Berg306b79e2020-03-20 11:38:35 +01006993 default:
Johannes Berg4c476992010-10-04 21:36:35 +02006994 return -EINVAL;
Johannes Berg306b79e2020-03-20 11:38:35 +01006995 }
Johannes Berge80cf852009-05-11 14:43:13 +02006996
Johannes Berg4c476992010-10-04 21:36:35 +02006997 if (!rdev->ops->del_station)
6998 return -EOPNOTSUPP;
Johannes Berg5727ef12007-12-19 02:03:34 +01006999
Jouni Malinen98856862014-10-20 13:20:45 +03007000 if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
7001 params.subtype =
7002 nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
7003 if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
7004 params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
7005 return -EINVAL;
7006 } else {
7007 /* Default to Deauthentication frame */
7008 params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
7009 }
7010
7011 if (info->attrs[NL80211_ATTR_REASON_CODE]) {
7012 params.reason_code =
7013 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
7014 if (params.reason_code == 0)
7015 return -EINVAL; /* 0 is reserved */
7016 } else {
7017 /* Default to reason code 2 */
7018 params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
7019 }
7020
Jouni Malinen89c771e2014-10-10 20:52:40 +03007021 return rdev_del_station(rdev, dev, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01007022}
7023
Eric W. Biederman15e47302012-09-07 20:12:54 +00007024static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007025 int flags, struct net_device *dev,
7026 u8 *dst, u8 *next_hop,
7027 struct mpath_info *pinfo)
7028{
7029 void *hdr;
7030 struct nlattr *pinfoattr;
7031
Henning Rogge1ef4c852014-11-04 16:14:58 +01007032 hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007033 if (!hdr)
7034 return -1;
7035
David S. Miller9360ffd2012-03-29 04:41:26 -04007036 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
7037 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
7038 nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
7039 nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
7040 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02007041
Michal Kubecekae0be8d2019-04-26 11:13:06 +02007042 pinfoattr = nla_nest_start_noflag(msg, NL80211_ATTR_MPATH_INFO);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007043 if (!pinfoattr)
7044 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04007045 if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
7046 nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
7047 pinfo->frame_qlen))
7048 goto nla_put_failure;
7049 if (((pinfo->filled & MPATH_INFO_SN) &&
7050 nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
7051 ((pinfo->filled & MPATH_INFO_METRIC) &&
7052 nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
7053 pinfo->metric)) ||
7054 ((pinfo->filled & MPATH_INFO_EXPTIME) &&
7055 nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
7056 pinfo->exptime)) ||
7057 ((pinfo->filled & MPATH_INFO_FLAGS) &&
7058 nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
7059 pinfo->flags)) ||
7060 ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
7061 nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
7062 pinfo->discovery_timeout)) ||
7063 ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
7064 nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
Julan Hsucc241632019-01-15 15:28:42 -08007065 pinfo->discovery_retries)) ||
7066 ((pinfo->filled & MPATH_INFO_HOP_COUNT) &&
7067 nla_put_u8(msg, NL80211_MPATH_INFO_HOP_COUNT,
Julan Hsu540bbcb2019-01-15 15:28:43 -08007068 pinfo->hop_count)) ||
7069 ((pinfo->filled & MPATH_INFO_PATH_CHANGE) &&
7070 nla_put_u32(msg, NL80211_MPATH_INFO_PATH_CHANGE,
7071 pinfo->path_change_count)))
David S. Miller9360ffd2012-03-29 04:41:26 -04007072 goto nla_put_failure;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007073
7074 nla_nest_end(msg, pinfoattr);
7075
Johannes Berg053c0952015-01-16 22:09:00 +01007076 genlmsg_end(msg, hdr);
7077 return 0;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007078
7079 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07007080 genlmsg_cancel(msg, hdr);
7081 return -EMSGSIZE;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007082}
7083
7084static int nl80211_dump_mpath(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02007085 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007086{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007087 struct mpath_info pinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007088 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007089 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007090 u8 dst[ETH_ALEN];
7091 u8 next_hop[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02007092 int path_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007093 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007094
Johannes Berg5297c652018-09-27 14:36:44 +02007095 err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02007096 if (err)
Johannes Berga05829a2021-01-22 16:19:43 +01007097 return err;
7098 /* nl80211_prepare_wdev_dump acquired it in the successful case */
7099 __acquire(&rdev->wiphy.mtx);
Johannes Bergbba95fe2008-07-29 13:22:51 +02007100
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007101 if (!rdev->ops->dump_mpath) {
Jouni Malineneec60b02009-03-20 21:21:19 +02007102 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02007103 goto out_err;
7104 }
7105
Johannes Berg97990a02013-04-19 01:02:55 +02007106 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
Jouni Malineneec60b02009-03-20 21:21:19 +02007107 err = -EOPNOTSUPP;
Roel Kluin0448b5f2009-08-22 21:15:49 +02007108 goto out_err;
Jouni Malineneec60b02009-03-20 21:21:19 +02007109 }
7110
Johannes Bergbba95fe2008-07-29 13:22:51 +02007111 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007112 err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
Johannes Berg97990a02013-04-19 01:02:55 +02007113 next_hop, &pinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02007114 if (err == -ENOENT)
7115 break;
7116 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01007117 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02007118
Eric W. Biederman15e47302012-09-07 20:12:54 +00007119 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02007120 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg97990a02013-04-19 01:02:55 +02007121 wdev->netdev, dst, next_hop,
Johannes Bergbba95fe2008-07-29 13:22:51 +02007122 &pinfo) < 0)
7123 goto out;
7124
7125 path_idx++;
7126 }
7127
Johannes Bergbba95fe2008-07-29 13:22:51 +02007128 out:
Johannes Berg97990a02013-04-19 01:02:55 +02007129 cb->args[2] = path_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02007130 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02007131 out_err:
Johannes Berga05829a2021-01-22 16:19:43 +01007132 wiphy_unlock(&rdev->wiphy);
Johannes Bergbba95fe2008-07-29 13:22:51 +02007133 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007134}
7135
7136static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
7137{
Johannes Berg4c476992010-10-04 21:36:35 +02007138 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007139 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02007140 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007141 struct mpath_info pinfo;
7142 struct sk_buff *msg;
7143 u8 *dst = NULL;
7144 u8 next_hop[ETH_ALEN];
7145
7146 memset(&pinfo, 0, sizeof(pinfo));
7147
7148 if (!info->attrs[NL80211_ATTR_MAC])
7149 return -EINVAL;
7150
7151 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
7152
Johannes Berg4c476992010-10-04 21:36:35 +02007153 if (!rdev->ops->get_mpath)
7154 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01007155
Johannes Berg4c476992010-10-04 21:36:35 +02007156 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
7157 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02007158
Hila Gonene35e4d22012-06-27 17:19:42 +03007159 err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007160 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02007161 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007162
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07007163 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007164 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02007165 return -ENOMEM;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007166
Eric W. Biederman15e47302012-09-07 20:12:54 +00007167 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg4c476992010-10-04 21:36:35 +02007168 dev, dst, next_hop, &pinfo) < 0) {
7169 nlmsg_free(msg);
7170 return -ENOBUFS;
7171 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007172
Johannes Berg4c476992010-10-04 21:36:35 +02007173 return genlmsg_reply(msg, info);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007174}
7175
7176static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
7177{
Johannes Berg4c476992010-10-04 21:36:35 +02007178 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7179 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007180 u8 *dst = NULL;
7181 u8 *next_hop = NULL;
7182
7183 if (!info->attrs[NL80211_ATTR_MAC])
7184 return -EINVAL;
7185
7186 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
7187 return -EINVAL;
7188
7189 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
7190 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
7191
Johannes Berg4c476992010-10-04 21:36:35 +02007192 if (!rdev->ops->change_mpath)
7193 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01007194
Johannes Berg4c476992010-10-04 21:36:35 +02007195 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
7196 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007197
Hila Gonene35e4d22012-06-27 17:19:42 +03007198 return rdev_change_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007199}
Johannes Berg4c476992010-10-04 21:36:35 +02007200
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007201static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
7202{
Johannes Berg4c476992010-10-04 21:36:35 +02007203 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7204 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007205 u8 *dst = NULL;
7206 u8 *next_hop = NULL;
7207
7208 if (!info->attrs[NL80211_ATTR_MAC])
7209 return -EINVAL;
7210
7211 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
7212 return -EINVAL;
7213
7214 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
7215 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
7216
Johannes Berg4c476992010-10-04 21:36:35 +02007217 if (!rdev->ops->add_mpath)
7218 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01007219
Johannes Berg4c476992010-10-04 21:36:35 +02007220 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
7221 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007222
Hila Gonene35e4d22012-06-27 17:19:42 +03007223 return rdev_add_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007224}
7225
7226static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
7227{
Johannes Berg4c476992010-10-04 21:36:35 +02007228 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7229 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007230 u8 *dst = NULL;
7231
7232 if (info->attrs[NL80211_ATTR_MAC])
7233 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
7234
Johannes Berg4c476992010-10-04 21:36:35 +02007235 if (!rdev->ops->del_mpath)
7236 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01007237
Miaoqing Panb5014262019-09-26 16:16:50 +08007238 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
7239 return -EOPNOTSUPP;
7240
Hila Gonene35e4d22012-06-27 17:19:42 +03007241 return rdev_del_mpath(rdev, dev, dst);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01007242}
7243
Henning Rogge66be7d22014-09-12 08:58:49 +02007244static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
7245{
7246 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7247 int err;
7248 struct net_device *dev = info->user_ptr[1];
7249 struct mpath_info pinfo;
7250 struct sk_buff *msg;
7251 u8 *dst = NULL;
7252 u8 mpp[ETH_ALEN];
7253
7254 memset(&pinfo, 0, sizeof(pinfo));
7255
7256 if (!info->attrs[NL80211_ATTR_MAC])
7257 return -EINVAL;
7258
7259 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
7260
7261 if (!rdev->ops->get_mpp)
7262 return -EOPNOTSUPP;
7263
7264 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
7265 return -EOPNOTSUPP;
7266
7267 err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
7268 if (err)
7269 return err;
7270
7271 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7272 if (!msg)
7273 return -ENOMEM;
7274
7275 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
7276 dev, dst, mpp, &pinfo) < 0) {
7277 nlmsg_free(msg);
7278 return -ENOBUFS;
7279 }
7280
7281 return genlmsg_reply(msg, info);
7282}
7283
7284static int nl80211_dump_mpp(struct sk_buff *skb,
7285 struct netlink_callback *cb)
7286{
7287 struct mpath_info pinfo;
7288 struct cfg80211_registered_device *rdev;
7289 struct wireless_dev *wdev;
7290 u8 dst[ETH_ALEN];
7291 u8 mpp[ETH_ALEN];
7292 int path_idx = cb->args[2];
7293 int err;
7294
Johannes Berg5297c652018-09-27 14:36:44 +02007295 err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
Henning Rogge66be7d22014-09-12 08:58:49 +02007296 if (err)
Johannes Berga05829a2021-01-22 16:19:43 +01007297 return err;
7298 /* nl80211_prepare_wdev_dump acquired it in the successful case */
7299 __acquire(&rdev->wiphy.mtx);
Henning Rogge66be7d22014-09-12 08:58:49 +02007300
7301 if (!rdev->ops->dump_mpp) {
7302 err = -EOPNOTSUPP;
7303 goto out_err;
7304 }
7305
7306 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
7307 err = -EOPNOTSUPP;
7308 goto out_err;
7309 }
7310
7311 while (1) {
7312 err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
7313 mpp, &pinfo);
7314 if (err == -ENOENT)
7315 break;
7316 if (err)
7317 goto out_err;
7318
7319 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
7320 cb->nlh->nlmsg_seq, NLM_F_MULTI,
7321 wdev->netdev, dst, mpp,
7322 &pinfo) < 0)
7323 goto out;
7324
7325 path_idx++;
7326 }
7327
7328 out:
7329 cb->args[2] = path_idx;
7330 err = skb->len;
7331 out_err:
Johannes Berga05829a2021-01-22 16:19:43 +01007332 wiphy_unlock(&rdev->wiphy);
Henning Rogge66be7d22014-09-12 08:58:49 +02007333 return err;
7334}
7335
Jouni Malinen9f1ba902008-08-07 20:07:01 +03007336static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
7337{
Johannes Berg4c476992010-10-04 21:36:35 +02007338 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7339 struct net_device *dev = info->user_ptr[1];
Simon Wunderlichc56589e2013-11-21 18:19:49 +01007340 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03007341 struct bss_parameters params;
Simon Wunderlichc56589e2013-11-21 18:19:49 +01007342 int err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03007343
7344 memset(&params, 0, sizeof(params));
7345 /* default to not changing parameters */
7346 params.use_cts_prot = -1;
7347 params.use_short_preamble = -1;
7348 params.use_short_slot_time = -1;
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02007349 params.ap_isolate = -1;
Helmut Schaa50b12f52010-11-19 12:40:25 +01007350 params.ht_opmode = -1;
Johannes Berg53cabad2012-11-14 15:17:28 +01007351 params.p2p_ctwindow = -1;
7352 params.p2p_opp_ps = -1;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03007353
7354 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
7355 params.use_cts_prot =
7356 nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
7357 if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
7358 params.use_short_preamble =
7359 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
7360 if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
7361 params.use_short_slot_time =
7362 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
Jouni Malinen90c97a02008-10-30 16:59:22 +02007363 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
7364 params.basic_rates =
7365 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
7366 params.basic_rates_len =
7367 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
7368 }
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02007369 if (info->attrs[NL80211_ATTR_AP_ISOLATE])
7370 params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
Helmut Schaa50b12f52010-11-19 12:40:25 +01007371 if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
7372 params.ht_opmode =
7373 nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
Jouni Malinen9f1ba902008-08-07 20:07:01 +03007374
Johannes Berg53cabad2012-11-14 15:17:28 +01007375 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
7376 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
7377 return -EINVAL;
7378 params.p2p_ctwindow =
Johannes Bergab0d76f2018-10-02 10:00:07 +02007379 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
Johannes Berg53cabad2012-11-14 15:17:28 +01007380 if (params.p2p_ctwindow != 0 &&
7381 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
7382 return -EINVAL;
7383 }
7384
7385 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
7386 u8 tmp;
7387
7388 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
7389 return -EINVAL;
7390 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
Johannes Berg53cabad2012-11-14 15:17:28 +01007391 params.p2p_opp_ps = tmp;
7392 if (params.p2p_opp_ps &&
7393 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
7394 return -EINVAL;
7395 }
7396
Johannes Berg4c476992010-10-04 21:36:35 +02007397 if (!rdev->ops->change_bss)
7398 return -EOPNOTSUPP;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03007399
Johannes Berg074ac8d2010-09-16 14:58:22 +02007400 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Johannes Berg4c476992010-10-04 21:36:35 +02007401 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
7402 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02007403
Simon Wunderlichc56589e2013-11-21 18:19:49 +01007404 wdev_lock(wdev);
7405 err = rdev_change_bss(rdev, dev, &params);
7406 wdev_unlock(wdev);
7407
7408 return err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03007409}
7410
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007411static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
7412{
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007413 char *data = NULL;
Ilan peer05050752015-03-04 00:32:06 -05007414 bool is_indoor;
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07007415 enum nl80211_user_reg_hint_type user_reg_hint_type;
Ilan peer05050752015-03-04 00:32:06 -05007416 u32 owner_nlportid;
7417
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05007418 /*
7419 * You should only get this when cfg80211 hasn't yet initialized
7420 * completely when built-in to the kernel right between the time
7421 * window between nl80211_init() and regulatory_init(), if that is
7422 * even possible.
7423 */
Johannes Berg458f4f92012-12-06 15:47:38 +01007424 if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
Luis R. Rodriguezfe33eb32009-02-21 00:04:30 -05007425 return -EINPROGRESS;
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05007426
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07007427 if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
7428 user_reg_hint_type =
7429 nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
7430 else
7431 user_reg_hint_type = NL80211_USER_REG_HINT_USER;
7432
7433 switch (user_reg_hint_type) {
7434 case NL80211_USER_REG_HINT_USER:
7435 case NL80211_USER_REG_HINT_CELL_BASE:
Ilan Peer52616f22014-02-25 16:26:00 +02007436 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
7437 return -EINVAL;
7438
7439 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
7440 return regulatory_hint_user(data, user_reg_hint_type);
7441 case NL80211_USER_REG_HINT_INDOOR:
Ilan peer05050752015-03-04 00:32:06 -05007442 if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
7443 owner_nlportid = info->snd_portid;
7444 is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
7445 } else {
7446 owner_nlportid = 0;
7447 is_indoor = true;
7448 }
7449
7450 return regulatory_hint_indoor(is_indoor, owner_nlportid);
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07007451 default:
7452 return -EINVAL;
7453 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07007454}
7455
Johannes Berg1ea4ff3e92017-09-13 16:07:22 +02007456static int nl80211_reload_regdb(struct sk_buff *skb, struct genl_info *info)
7457{
7458 return reg_reload_regdb();
7459}
7460
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007461static int nl80211_get_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01007462 struct genl_info *info)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007463{
Johannes Berg4c476992010-10-04 21:36:35 +02007464 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02007465 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01007466 struct wireless_dev *wdev = dev->ieee80211_ptr;
7467 struct mesh_config cur_params;
7468 int err = 0;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007469 void *hdr;
7470 struct nlattr *pinfoattr;
7471 struct sk_buff *msg;
7472
Johannes Berg29cbe682010-12-03 09:20:44 +01007473 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
7474 return -EOPNOTSUPP;
7475
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007476 if (!rdev->ops->get_mesh_config)
Johannes Berg4c476992010-10-04 21:36:35 +02007477 return -EOPNOTSUPP;
Jouni Malinenf3f92582009-03-20 17:57:36 +02007478
Johannes Berg29cbe682010-12-03 09:20:44 +01007479 wdev_lock(wdev);
7480 /* If not connected, get default parameters */
7481 if (!wdev->mesh_id_len)
7482 memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
7483 else
Hila Gonene35e4d22012-06-27 17:19:42 +03007484 err = rdev_get_mesh_config(rdev, dev, &cur_params);
Johannes Berg29cbe682010-12-03 09:20:44 +01007485 wdev_unlock(wdev);
7486
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007487 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02007488 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007489
7490 /* Draw up a netlink message to send back */
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07007491 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02007492 if (!msg)
7493 return -ENOMEM;
Eric W. Biederman15e47302012-09-07 20:12:54 +00007494 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007495 NL80211_CMD_GET_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007496 if (!hdr)
Julia Lawallefe1cf02011-01-28 15:17:11 +01007497 goto out;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02007498 pinfoattr = nla_nest_start_noflag(msg, NL80211_ATTR_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007499 if (!pinfoattr)
7500 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04007501 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
7502 nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
7503 cur_params.dot11MeshRetryTimeout) ||
7504 nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
7505 cur_params.dot11MeshConfirmTimeout) ||
7506 nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
7507 cur_params.dot11MeshHoldingTimeout) ||
7508 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
7509 cur_params.dot11MeshMaxPeerLinks) ||
7510 nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
7511 cur_params.dot11MeshMaxRetries) ||
7512 nla_put_u8(msg, NL80211_MESHCONF_TTL,
7513 cur_params.dot11MeshTTL) ||
7514 nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
7515 cur_params.element_ttl) ||
7516 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
7517 cur_params.auto_open_plinks) ||
John W. Linville7eab0f62012-04-12 14:25:14 -04007518 nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
7519 cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04007520 nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
7521 cur_params.dot11MeshHWMPmaxPREQretries) ||
7522 nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
7523 cur_params.path_refresh_time) ||
7524 nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
7525 cur_params.min_discovery_timeout) ||
7526 nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
7527 cur_params.dot11MeshHWMPactivePathTimeout) ||
7528 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
7529 cur_params.dot11MeshHWMPpreqMinInterval) ||
7530 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
7531 cur_params.dot11MeshHWMPperrMinInterval) ||
7532 nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
7533 cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
7534 nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
7535 cur_params.dot11MeshHWMPRootMode) ||
7536 nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
7537 cur_params.dot11MeshHWMPRannInterval) ||
7538 nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
7539 cur_params.dot11MeshGateAnnouncementProtocol) ||
7540 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
7541 cur_params.dot11MeshForwarding) ||
Masashi Honma335d5342017-03-16 10:57:17 +09007542 nla_put_s32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
Ashok Nagarajan70c33ea2012-04-30 14:20:32 -07007543 cur_params.rssi_threshold) ||
7544 nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08007545 cur_params.ht_opmode) ||
7546 nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
7547 cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
7548 nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08007549 cur_params.dot11MeshHWMProotInterval) ||
7550 nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Marco Porsch3b1c5a52013-01-07 16:04:52 +01007551 cur_params.dot11MeshHWMPconfirmationInterval) ||
7552 nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
7553 cur_params.power_mode) ||
7554 nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07007555 cur_params.dot11MeshAwakeWindowDuration) ||
7556 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
Bob Copeland01d66fb2018-10-25 17:36:34 -04007557 cur_params.plink_timeout) ||
7558 nla_put_u8(msg, NL80211_MESHCONF_CONNECTED_TO_GATE,
Linus Lüssinge3718a62020-06-17 09:30:33 +02007559 cur_params.dot11MeshConnectedToMeshGate) ||
7560 nla_put_u8(msg, NL80211_MESHCONF_NOLEARN,
Markus Theil184eebe2020-06-11 16:02:37 +02007561 cur_params.dot11MeshNolearn) ||
7562 nla_put_u8(msg, NL80211_MESHCONF_CONNECTED_TO_AS,
7563 cur_params.dot11MeshConnectedToAuthServer))
David S. Miller9360ffd2012-03-29 04:41:26 -04007564 goto nla_put_failure;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007565 nla_nest_end(msg, pinfoattr);
7566 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02007567 return genlmsg_reply(msg, info);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007568
Johannes Berg3b858752009-03-12 09:55:09 +01007569 nla_put_failure:
Julia Lawallefe1cf02011-01-28 15:17:11 +01007570 out:
Yuri Ershovd080e272010-06-29 15:08:07 +04007571 nlmsg_free(msg);
Johannes Berg4c476992010-10-04 21:36:35 +02007572 return -ENOBUFS;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007573}
7574
Johannes Bergab0d76f2018-10-02 10:00:07 +02007575static const struct nla_policy
7576nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
7577 [NL80211_MESHCONF_RETRY_TIMEOUT] =
7578 NLA_POLICY_RANGE(NLA_U16, 1, 255),
7579 [NL80211_MESHCONF_CONFIRM_TIMEOUT] =
7580 NLA_POLICY_RANGE(NLA_U16, 1, 255),
7581 [NL80211_MESHCONF_HOLDING_TIMEOUT] =
7582 NLA_POLICY_RANGE(NLA_U16, 1, 255),
7583 [NL80211_MESHCONF_MAX_PEER_LINKS] =
7584 NLA_POLICY_RANGE(NLA_U16, 0, 255),
7585 [NL80211_MESHCONF_MAX_RETRIES] = NLA_POLICY_MAX(NLA_U8, 16),
7586 [NL80211_MESHCONF_TTL] = NLA_POLICY_MIN(NLA_U8, 1),
7587 [NL80211_MESHCONF_ELEMENT_TTL] = NLA_POLICY_MIN(NLA_U8, 1),
7588 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = NLA_POLICY_MAX(NLA_U8, 1),
7589 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] =
7590 NLA_POLICY_RANGE(NLA_U32, 1, 255),
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007591 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
7592 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
Johannes Bergab0d76f2018-10-02 10:00:07 +02007593 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = NLA_POLICY_MIN(NLA_U16, 1),
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007594 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
Johannes Bergab0d76f2018-10-02 10:00:07 +02007595 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] =
7596 NLA_POLICY_MIN(NLA_U16, 1),
7597 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] =
7598 NLA_POLICY_MIN(NLA_U16, 1),
7599 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] =
7600 NLA_POLICY_MIN(NLA_U16, 1),
7601 [NL80211_MESHCONF_HWMP_ROOTMODE] = NLA_POLICY_MAX(NLA_U8, 4),
7602 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] =
7603 NLA_POLICY_MIN(NLA_U16, 1),
7604 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = NLA_POLICY_MAX(NLA_U8, 1),
7605 [NL80211_MESHCONF_FORWARDING] = NLA_POLICY_MAX(NLA_U8, 1),
7606 [NL80211_MESHCONF_RSSI_THRESHOLD] =
7607 NLA_POLICY_RANGE(NLA_S32, -255, 0),
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08007608 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08007609 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
Johannes Bergab0d76f2018-10-02 10:00:07 +02007610 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] =
7611 NLA_POLICY_MIN(NLA_U16, 1),
7612 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] =
7613 NLA_POLICY_MIN(NLA_U16, 1),
7614 [NL80211_MESHCONF_POWER_MODE] =
7615 NLA_POLICY_RANGE(NLA_U32,
7616 NL80211_MESH_POWER_ACTIVE,
7617 NL80211_MESH_POWER_MAX),
Marco Porsch3b1c5a52013-01-07 16:04:52 +01007618 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
Colleen Twitty8e7c0532013-06-03 09:53:39 -07007619 [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
Bob Copeland01d66fb2018-10-25 17:36:34 -04007620 [NL80211_MESHCONF_CONNECTED_TO_GATE] = NLA_POLICY_RANGE(NLA_U8, 0, 1),
Linus Lüssinge3718a62020-06-17 09:30:33 +02007621 [NL80211_MESHCONF_NOLEARN] = NLA_POLICY_RANGE(NLA_U8, 0, 1),
Markus Theil184eebe2020-06-11 16:02:37 +02007622 [NL80211_MESHCONF_CONNECTED_TO_AS] = NLA_POLICY_RANGE(NLA_U8, 0, 1),
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007623};
7624
Javier Cardonac80d5452010-12-16 17:37:49 -08007625static const struct nla_policy
7626 nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
Javier Cardonad299a1f2012-03-31 11:31:33 -07007627 [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
Javier Cardonac80d5452010-12-16 17:37:49 -08007628 [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
7629 [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
Javier Cardona15d5dda2011-04-07 15:08:28 -07007630 [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
Colleen Twitty6e16d902013-05-08 11:45:59 -07007631 [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 },
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08007632 [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
Johannes Berg3d7af872018-10-02 10:00:08 +02007633 [NL80211_MESH_SETUP_IE] =
7634 NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
7635 IEEE80211_MAX_DATA_LEN),
Javier Cardonab130e5c2011-05-03 16:57:07 -07007636 [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
Javier Cardonac80d5452010-12-16 17:37:49 -08007637};
7638
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007639static int nl80211_parse_mesh_config(struct genl_info *info,
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007640 struct mesh_config *cfg,
7641 u32 *mask_out)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007642{
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007643 struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007644 u32 mask = 0;
Masashi Honma97572352016-08-03 10:07:44 +09007645 u16 ht_opmode;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007646
Johannes Bergab0d76f2018-10-02 10:00:07 +02007647#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, mask, attr, fn) \
7648do { \
7649 if (tb[attr]) { \
7650 cfg->param = fn(tb[attr]); \
7651 mask |= BIT((attr) - 1); \
7652 } \
Marco Porschea54fba2013-01-07 16:04:48 +01007653} while (0)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007654
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007655 if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007656 return -EINVAL;
Johannes Berg8cb08172019-04-26 14:07:28 +02007657 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 -07007658 return -EINVAL;
7659
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007660 /* This makes sure that there aren't more than 32 mesh config
7661 * parameters (otherwise our bitfield scheme would not work.) */
7662 BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
7663
7664 /* Fill in the params struct */
Johannes Bergab0d76f2018-10-02 10:00:07 +02007665 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, mask,
7666 NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16);
7667 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, mask,
7668 NL80211_MESHCONF_CONFIRM_TIMEOUT,
7669 nla_get_u16);
7670 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, mask,
7671 NL80211_MESHCONF_HOLDING_TIMEOUT,
7672 nla_get_u16);
7673 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, mask,
7674 NL80211_MESHCONF_MAX_PEER_LINKS,
7675 nla_get_u16);
7676 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, mask,
7677 NL80211_MESHCONF_MAX_RETRIES, nla_get_u8);
7678 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, mask,
7679 NL80211_MESHCONF_TTL, nla_get_u8);
7680 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, mask,
7681 NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8);
7682 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, mask,
7683 NL80211_MESHCONF_AUTO_OPEN_PLINKS,
7684 nla_get_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01007685 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007686 mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08007687 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007688 nla_get_u32);
7689 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, mask,
7690 NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
7691 nla_get_u8);
7692 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, mask,
7693 NL80211_MESHCONF_PATH_REFRESH_TIME,
7694 nla_get_u32);
7695 if (mask & BIT(NL80211_MESHCONF_PATH_REFRESH_TIME) &&
7696 (cfg->path_refresh_time < 1 || cfg->path_refresh_time > 65535))
7697 return -EINVAL;
7698 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, mask,
7699 NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
7700 nla_get_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01007701 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007702 mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08007703 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007704 nla_get_u32);
7705 if (mask & BIT(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT) &&
7706 (cfg->dot11MeshHWMPactivePathTimeout < 1 ||
7707 cfg->dot11MeshHWMPactivePathTimeout > 65535))
7708 return -EINVAL;
7709 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, mask,
Marco Porschea54fba2013-01-07 16:04:48 +01007710 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007711 nla_get_u16);
7712 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, mask,
Marco Porschea54fba2013-01-07 16:04:48 +01007713 NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007714 nla_get_u16);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007715 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007716 dot11MeshHWMPnetDiameterTraversalTime, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08007717 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007718 nla_get_u16);
7719 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask,
7720 NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8);
7721 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask,
7722 NL80211_MESHCONF_HWMP_RANN_INTERVAL,
7723 nla_get_u16);
7724 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshGateAnnouncementProtocol,
Marco Porschea54fba2013-01-07 16:04:48 +01007725 mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007726 nla_get_u8);
7727 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, mask,
7728 NL80211_MESHCONF_FORWARDING, nla_get_u8);
7729 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, mask,
7730 NL80211_MESHCONF_RSSI_THRESHOLD,
7731 nla_get_s32);
Bob Copeland01d66fb2018-10-25 17:36:34 -04007732 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConnectedToMeshGate, mask,
7733 NL80211_MESHCONF_CONNECTED_TO_GATE,
7734 nla_get_u8);
Markus Theil184eebe2020-06-11 16:02:37 +02007735 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConnectedToAuthServer, mask,
7736 NL80211_MESHCONF_CONNECTED_TO_AS,
7737 nla_get_u8);
Masashi Honma97572352016-08-03 10:07:44 +09007738 /*
7739 * Check HT operation mode based on
Bob Copeland188f60a2018-06-24 21:10:49 -04007740 * IEEE 802.11-2016 9.4.2.57 HT Operation element.
Masashi Honma97572352016-08-03 10:07:44 +09007741 */
7742 if (tb[NL80211_MESHCONF_HT_OPMODE]) {
7743 ht_opmode = nla_get_u16(tb[NL80211_MESHCONF_HT_OPMODE]);
7744
7745 if (ht_opmode & ~(IEEE80211_HT_OP_MODE_PROTECTION |
7746 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
7747 IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
7748 return -EINVAL;
7749
Bob Copeland188f60a2018-06-24 21:10:49 -04007750 /* NON_HT_STA bit is reserved, but some programs set it */
7751 ht_opmode &= ~IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT;
Masashi Honma97572352016-08-03 10:07:44 +09007752
Masashi Honma97572352016-08-03 10:07:44 +09007753 cfg->ht_opmode = ht_opmode;
Masashi Honmafd551ba2017-01-26 08:56:13 +09007754 mask |= (1 << (NL80211_MESHCONF_HT_OPMODE - 1));
Masashi Honma97572352016-08-03 10:07:44 +09007755 }
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08007756 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007757 dot11MeshHWMPactivePathToRootTimeout, mask,
7758 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
7759 nla_get_u32);
7760 if (mask & BIT(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT) &&
7761 (cfg->dot11MeshHWMPactivePathToRootTimeout < 1 ||
7762 cfg->dot11MeshHWMPactivePathToRootTimeout > 65535))
7763 return -EINVAL;
7764 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, mask,
7765 NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
7766 nla_get_u16);
7767 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPconfirmationInterval,
7768 mask,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08007769 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Johannes Bergab0d76f2018-10-02 10:00:07 +02007770 nla_get_u16);
7771 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode, mask,
7772 NL80211_MESHCONF_POWER_MODE, nla_get_u32);
7773 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, mask,
7774 NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
7775 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, mask,
7776 NL80211_MESHCONF_PLINK_TIMEOUT, nla_get_u32);
Linus Lüssinge3718a62020-06-17 09:30:33 +02007777 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNolearn, mask,
7778 NL80211_MESHCONF_NOLEARN, nla_get_u8);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007779 if (mask_out)
7780 *mask_out = mask;
Javier Cardonac80d5452010-12-16 17:37:49 -08007781
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007782 return 0;
7783
7784#undef FILL_IN_MESH_PARAM_IF_SET
7785}
7786
Javier Cardonac80d5452010-12-16 17:37:49 -08007787static int nl80211_parse_mesh_setup(struct genl_info *info,
7788 struct mesh_setup *setup)
7789{
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08007790 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Javier Cardonac80d5452010-12-16 17:37:49 -08007791 struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
7792
7793 if (!info->attrs[NL80211_ATTR_MESH_SETUP])
7794 return -EINVAL;
Johannes Berg8cb08172019-04-26 14:07:28 +02007795 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 -08007796 return -EINVAL;
7797
Javier Cardonad299a1f2012-03-31 11:31:33 -07007798 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
7799 setup->sync_method =
7800 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
7801 IEEE80211_SYNC_METHOD_VENDOR :
7802 IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
7803
Javier Cardonac80d5452010-12-16 17:37:49 -08007804 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
7805 setup->path_sel_proto =
7806 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
7807 IEEE80211_PATH_PROTOCOL_VENDOR :
7808 IEEE80211_PATH_PROTOCOL_HWMP;
7809
7810 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
7811 setup->path_metric =
7812 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
7813 IEEE80211_PATH_METRIC_VENDOR :
7814 IEEE80211_PATH_METRIC_AIRTIME;
7815
Javier Cardona581a8b02011-04-07 15:08:27 -07007816 if (tb[NL80211_MESH_SETUP_IE]) {
Javier Cardonac80d5452010-12-16 17:37:49 -08007817 struct nlattr *ieattr =
Javier Cardona581a8b02011-04-07 15:08:27 -07007818 tb[NL80211_MESH_SETUP_IE];
Javier Cardona581a8b02011-04-07 15:08:27 -07007819 setup->ie = nla_data(ieattr);
7820 setup->ie_len = nla_len(ieattr);
Javier Cardonac80d5452010-12-16 17:37:49 -08007821 }
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08007822 if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
7823 !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
7824 return -EINVAL;
7825 setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
Javier Cardonab130e5c2011-05-03 16:57:07 -07007826 setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
7827 setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08007828 if (setup->is_secure)
7829 setup->user_mpm = true;
Javier Cardonac80d5452010-12-16 17:37:49 -08007830
Colleen Twitty6e16d902013-05-08 11:45:59 -07007831 if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) {
7832 if (!setup->user_mpm)
7833 return -EINVAL;
7834 setup->auth_id =
7835 nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]);
7836 }
7837
Javier Cardonac80d5452010-12-16 17:37:49 -08007838 return 0;
7839}
7840
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007841static int nl80211_update_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01007842 struct genl_info *info)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007843{
7844 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7845 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01007846 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007847 struct mesh_config cfg;
7848 u32 mask;
7849 int err;
7850
Johannes Berg29cbe682010-12-03 09:20:44 +01007851 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
7852 return -EOPNOTSUPP;
7853
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007854 if (!rdev->ops->update_mesh_config)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007855 return -EOPNOTSUPP;
7856
Javier Cardona24bdd9f2010-12-16 17:37:48 -08007857 err = nl80211_parse_mesh_config(info, &cfg, &mask);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01007858 if (err)
7859 return err;
7860
Johannes Berg29cbe682010-12-03 09:20:44 +01007861 wdev_lock(wdev);
7862 if (!wdev->mesh_id_len)
7863 err = -ENOLINK;
7864
7865 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03007866 err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01007867
7868 wdev_unlock(wdev);
7869
7870 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07007871}
7872
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007873static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
7874 struct sk_buff *msg)
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007875{
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007876 struct nlattr *nl_reg_rules;
7877 unsigned int i;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007878
Johannes Berg458f4f92012-12-06 15:47:38 +01007879 if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
7880 (regdom->dfs_region &&
7881 nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007882 goto nla_put_failure;
Johannes Berg458f4f92012-12-06 15:47:38 +01007883
Michal Kubecekae0be8d2019-04-26 11:13:06 +02007884 nl_reg_rules = nla_nest_start_noflag(msg, NL80211_ATTR_REG_RULES);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007885 if (!nl_reg_rules)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007886 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007887
Johannes Berg458f4f92012-12-06 15:47:38 +01007888 for (i = 0; i < regdom->n_reg_rules; i++) {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007889 struct nlattr *nl_reg_rule;
7890 const struct ieee80211_reg_rule *reg_rule;
7891 const struct ieee80211_freq_range *freq_range;
7892 const struct ieee80211_power_rule *power_rule;
Janusz Dziedzic97524822014-01-30 09:52:20 +01007893 unsigned int max_bandwidth_khz;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007894
Johannes Berg458f4f92012-12-06 15:47:38 +01007895 reg_rule = &regdom->reg_rules[i];
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007896 freq_range = &reg_rule->freq_range;
7897 power_rule = &reg_rule->power_rule;
7898
Michal Kubecekae0be8d2019-04-26 11:13:06 +02007899 nl_reg_rule = nla_nest_start_noflag(msg, i);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007900 if (!nl_reg_rule)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007901 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007902
Janusz Dziedzic97524822014-01-30 09:52:20 +01007903 max_bandwidth_khz = freq_range->max_bandwidth_khz;
7904 if (!max_bandwidth_khz)
7905 max_bandwidth_khz = reg_get_max_bandwidth(regdom,
7906 reg_rule);
7907
David S. Miller9360ffd2012-03-29 04:41:26 -04007908 if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
7909 reg_rule->flags) ||
7910 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
7911 freq_range->start_freq_khz) ||
7912 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
7913 freq_range->end_freq_khz) ||
7914 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
Janusz Dziedzic97524822014-01-30 09:52:20 +01007915 max_bandwidth_khz) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04007916 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
7917 power_rule->max_antenna_gain) ||
7918 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
Janusz Dziedzic089027e2014-02-21 19:46:12 +01007919 power_rule->max_eirp) ||
7920 nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
7921 reg_rule->dfs_cac_ms))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007922 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007923
7924 nla_nest_end(msg, nl_reg_rule);
7925 }
7926
7927 nla_nest_end(msg, nl_reg_rules);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007928 return 0;
7929
7930nla_put_failure:
7931 return -EMSGSIZE;
7932}
7933
7934static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
7935{
7936 const struct ieee80211_regdomain *regdom = NULL;
7937 struct cfg80211_registered_device *rdev;
7938 struct wiphy *wiphy = NULL;
7939 struct sk_buff *msg;
7940 void *hdr;
7941
7942 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7943 if (!msg)
7944 return -ENOBUFS;
7945
7946 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
7947 NL80211_CMD_GET_REG);
7948 if (!hdr)
7949 goto put_failure;
7950
Johannes Berga05829a2021-01-22 16:19:43 +01007951 rtnl_lock();
7952
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007953 if (info->attrs[NL80211_ATTR_WIPHY]) {
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02007954 bool self_managed;
7955
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007956 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
7957 if (IS_ERR(rdev)) {
7958 nlmsg_free(msg);
Johannes Berga05829a2021-01-22 16:19:43 +01007959 rtnl_unlock();
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007960 return PTR_ERR(rdev);
7961 }
7962
7963 wiphy = &rdev->wiphy;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02007964 self_managed = wiphy->regulatory_flags &
7965 REGULATORY_WIPHY_SELF_MANAGED;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007966 regdom = get_wiphy_regdom(wiphy);
7967
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02007968 /* a self-managed-reg device must have a private regdom */
7969 if (WARN_ON(!regdom && self_managed)) {
7970 nlmsg_free(msg);
Johannes Berga05829a2021-01-22 16:19:43 +01007971 rtnl_unlock();
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02007972 return -EINVAL;
7973 }
7974
Arik Nemtsovad30ca22014-12-15 19:25:59 +02007975 if (regdom &&
7976 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
7977 goto nla_put_failure;
7978 }
7979
7980 if (!wiphy && reg_last_request_cell_base() &&
7981 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
7982 NL80211_USER_REG_HINT_CELL_BASE))
7983 goto nla_put_failure;
7984
7985 rcu_read_lock();
7986
7987 if (!regdom)
7988 regdom = rcu_dereference(cfg80211_regdomain);
7989
7990 if (nl80211_put_regdom(regdom, msg))
7991 goto nla_put_failure_rcu;
7992
7993 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007994
7995 genlmsg_end(msg, hdr);
Johannes Berga05829a2021-01-22 16:19:43 +01007996 rtnl_unlock();
Johannes Berg5fe231e2013-05-08 21:45:15 +02007997 return genlmsg_reply(msg, info);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08007998
Johannes Berg458f4f92012-12-06 15:47:38 +01007999nla_put_failure_rcu:
8000 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08008001nla_put_failure:
Johannes Berga05829a2021-01-22 16:19:43 +01008002 rtnl_unlock();
Julia Lawallefe1cf02011-01-28 15:17:11 +01008003put_failure:
Yuri Ershovd080e272010-06-29 15:08:07 +04008004 nlmsg_free(msg);
Johannes Berg5fe231e2013-05-08 21:45:15 +02008005 return -EMSGSIZE;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08008006}
8007
Arik Nemtsovad30ca22014-12-15 19:25:59 +02008008static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
8009 u32 seq, int flags, struct wiphy *wiphy,
8010 const struct ieee80211_regdomain *regdom)
8011{
8012 void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
8013 NL80211_CMD_GET_REG);
8014
8015 if (!hdr)
8016 return -1;
8017
Michal Kubecek0a833c22017-11-15 13:09:32 +01008018 genl_dump_check_consistent(cb, hdr);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02008019
8020 if (nl80211_put_regdom(regdom, msg))
8021 goto nla_put_failure;
8022
8023 if (!wiphy && reg_last_request_cell_base() &&
8024 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
8025 NL80211_USER_REG_HINT_CELL_BASE))
8026 goto nla_put_failure;
8027
8028 if (wiphy &&
8029 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
8030 goto nla_put_failure;
8031
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02008032 if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
8033 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
8034 goto nla_put_failure;
8035
Johannes Berg053c0952015-01-16 22:09:00 +01008036 genlmsg_end(msg, hdr);
8037 return 0;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02008038
8039nla_put_failure:
8040 genlmsg_cancel(msg, hdr);
8041 return -EMSGSIZE;
8042}
8043
8044static int nl80211_get_reg_dump(struct sk_buff *skb,
8045 struct netlink_callback *cb)
8046{
8047 const struct ieee80211_regdomain *regdom = NULL;
8048 struct cfg80211_registered_device *rdev;
8049 int err, reg_idx, start = cb->args[2];
8050
8051 rtnl_lock();
8052
8053 if (cfg80211_regdomain && start == 0) {
8054 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
8055 NLM_F_MULTI, NULL,
8056 rtnl_dereference(cfg80211_regdomain));
8057 if (err < 0)
8058 goto out_err;
8059 }
8060
8061 /* the global regdom is idx 0 */
8062 reg_idx = 1;
8063 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
8064 regdom = get_wiphy_regdom(&rdev->wiphy);
8065 if (!regdom)
8066 continue;
8067
8068 if (++reg_idx <= start)
8069 continue;
8070
8071 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
8072 NLM_F_MULTI, &rdev->wiphy, regdom);
8073 if (err < 0) {
8074 reg_idx--;
8075 break;
8076 }
8077 }
8078
8079 cb->args[2] = reg_idx;
8080 err = skb->len;
8081out_err:
8082 rtnl_unlock();
8083 return err;
8084}
8085
Johannes Bergb6863032015-10-15 09:25:18 +02008086#ifdef CONFIG_CFG80211_CRDA_SUPPORT
8087static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
8088 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
8089 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
8090 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
8091 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
8092 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
8093 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
8094 [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
8095};
8096
8097static int parse_reg_rule(struct nlattr *tb[],
8098 struct ieee80211_reg_rule *reg_rule)
8099{
8100 struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
8101 struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
8102
8103 if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
8104 return -EINVAL;
8105 if (!tb[NL80211_ATTR_FREQ_RANGE_START])
8106 return -EINVAL;
8107 if (!tb[NL80211_ATTR_FREQ_RANGE_END])
8108 return -EINVAL;
8109 if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
8110 return -EINVAL;
8111 if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
8112 return -EINVAL;
8113
8114 reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
8115
8116 freq_range->start_freq_khz =
8117 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
8118 freq_range->end_freq_khz =
8119 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
8120 freq_range->max_bandwidth_khz =
8121 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
8122
8123 power_rule->max_eirp =
8124 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
8125
8126 if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
8127 power_rule->max_antenna_gain =
8128 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
8129
8130 if (tb[NL80211_ATTR_DFS_CAC_TIME])
8131 reg_rule->dfs_cac_ms =
8132 nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
8133
8134 return 0;
8135}
8136
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008137static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
8138{
8139 struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
8140 struct nlattr *nl_reg_rule;
Johannes Bergea372c52014-11-28 14:54:31 +01008141 char *alpha2;
8142 int rem_reg_rules, r;
Gustavo A. R. Silva391d1322019-04-03 10:37:44 -05008143 u32 num_rules = 0, rule_idx = 0;
Luis R. Rodriguez4c7d3982013-11-13 18:54:02 +01008144 enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
Johannes Bergea372c52014-11-28 14:54:31 +01008145 struct ieee80211_regdomain *rd;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008146
8147 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
8148 return -EINVAL;
8149
8150 if (!info->attrs[NL80211_ATTR_REG_RULES])
8151 return -EINVAL;
8152
8153 alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
8154
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07008155 if (info->attrs[NL80211_ATTR_DFS_REGION])
8156 dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
8157
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008158 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01008159 rem_reg_rules) {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008160 num_rules++;
8161 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
Luis R. Rodriguez4776c6e2009-05-13 17:04:39 -04008162 return -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008163 }
8164
Johannes Berga05829a2021-01-22 16:19:43 +01008165 rtnl_lock();
8166 if (!reg_is_valid_request(alpha2)) {
8167 r = -EINVAL;
8168 goto out;
8169 }
Luis R. Rodrigueze4387682013-11-05 09:18:01 -08008170
Gustavo A. R. Silva391d1322019-04-03 10:37:44 -05008171 rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL);
Johannes Berga05829a2021-01-22 16:19:43 +01008172 if (!rd) {
8173 r = -ENOMEM;
8174 goto out;
8175 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008176
8177 rd->n_reg_rules = num_rules;
8178 rd->alpha2[0] = alpha2[0];
8179 rd->alpha2[1] = alpha2[1];
8180
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07008181 /*
8182 * Disable DFS master mode if the DFS region was
8183 * not supported or known on this kernel.
8184 */
8185 if (reg_supported_dfs_region(dfs_region))
8186 rd->dfs_region = dfs_region;
8187
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008188 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01008189 rem_reg_rules) {
Johannes Berg8cb08172019-04-26 14:07:28 +02008190 r = nla_parse_nested_deprecated(tb, NL80211_REG_RULE_ATTR_MAX,
8191 nl_reg_rule, reg_rule_policy,
8192 info->extack);
Johannes Bergae811e22014-01-24 10:17:47 +01008193 if (r)
8194 goto bad_reg;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008195 r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
8196 if (r)
8197 goto bad_reg;
8198
8199 rule_idx++;
8200
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04008201 if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
8202 r = -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008203 goto bad_reg;
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04008204 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008205 }
8206
Johannes Berga05829a2021-01-22 16:19:43 +01008207 r = set_regdom(rd, REGD_SOURCE_CRDA);
Johannes Berg06627992016-06-09 10:40:09 +02008208 /* set_regdom takes ownership of rd */
Johannes Berga05829a2021-01-22 16:19:43 +01008209 rd = NULL;
Johannes Bergd2372b32008-10-24 20:32:20 +02008210 bad_reg:
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008211 kfree(rd);
Johannes Berga05829a2021-01-22 16:19:43 +01008212 out:
8213 rtnl_unlock();
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04008214 return r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008215}
Johannes Bergb6863032015-10-15 09:25:18 +02008216#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07008217
Johannes Berg83f5e2c2009-06-17 17:41:49 +02008218static int validate_scan_freqs(struct nlattr *freqs)
8219{
8220 struct nlattr *attr1, *attr2;
8221 int n_channels = 0, tmp1, tmp2;
8222
Srinivas Dasarid7f13f72017-07-07 01:43:42 +03008223 nla_for_each_nested(attr1, freqs, tmp1)
8224 if (nla_len(attr1) != sizeof(u32))
8225 return 0;
8226
Johannes Berg83f5e2c2009-06-17 17:41:49 +02008227 nla_for_each_nested(attr1, freqs, tmp1) {
8228 n_channels++;
8229 /*
8230 * Some hardware has a limited channel list for
8231 * scanning, and it is pretty much nonsensical
8232 * to scan for a channel twice, so disallow that
8233 * and don't require drivers to check that the
8234 * channel list they get isn't longer than what
8235 * they can scan, as long as they can scan all
8236 * the channels they registered at once.
8237 */
8238 nla_for_each_nested(attr2, freqs, tmp2)
8239 if (attr1 != attr2 &&
8240 nla_get_u32(attr1) == nla_get_u32(attr2))
8241 return 0;
8242 }
8243
8244 return n_channels;
8245}
8246
Johannes Berg57fbcce2016-04-12 15:56:15 +02008247static bool is_band_valid(struct wiphy *wiphy, enum nl80211_band b)
Arend van Spriel38de03d2016-03-02 20:37:18 +01008248{
Johannes Berg57fbcce2016-04-12 15:56:15 +02008249 return b < NUM_NL80211_BANDS && wiphy->bands[b];
Arend van Spriel38de03d2016-03-02 20:37:18 +01008250}
8251
8252static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
8253 struct cfg80211_bss_selection *bss_select)
8254{
8255 struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
8256 struct nlattr *nest;
8257 int err;
8258 bool found = false;
8259 int i;
8260
8261 /* only process one nested attribute */
8262 nest = nla_data(nla);
8263 if (!nla_ok(nest, nla_len(nest)))
8264 return -EINVAL;
8265
Johannes Berg8cb08172019-04-26 14:07:28 +02008266 err = nla_parse_nested_deprecated(attr, NL80211_BSS_SELECT_ATTR_MAX,
8267 nest, nl80211_bss_select_policy,
8268 NULL);
Arend van Spriel38de03d2016-03-02 20:37:18 +01008269 if (err)
8270 return err;
8271
8272 /* only one attribute may be given */
8273 for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
8274 if (attr[i]) {
8275 if (found)
8276 return -EINVAL;
8277 found = true;
8278 }
8279 }
8280
8281 bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
8282
8283 if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
8284 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
8285
8286 if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
8287 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
8288 bss_select->param.band_pref =
8289 nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
8290 if (!is_band_valid(wiphy, bss_select->param.band_pref))
8291 return -EINVAL;
8292 }
8293
8294 if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
8295 struct nl80211_bss_select_rssi_adjust *adj_param;
8296
8297 adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
8298 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
8299 bss_select->param.adjust.band = adj_param->band;
8300 bss_select->param.adjust.delta = adj_param->delta;
8301 if (!is_band_valid(wiphy, bss_select->param.adjust.band))
8302 return -EINVAL;
8303 }
8304
8305 /* user-space did not provide behaviour attribute */
8306 if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
8307 return -EINVAL;
8308
8309 if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
8310 return -EINVAL;
8311
8312 return 0;
8313}
8314
Johannes Berg9bb7e0f2018-09-10 13:29:12 +02008315int nl80211_parse_random_mac(struct nlattr **attrs,
8316 u8 *mac_addr, u8 *mac_addr_mask)
Johannes Bergad2b26a2014-06-12 21:39:05 +02008317{
8318 int i;
8319
8320 if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
Joe Perchesd2beae12015-03-02 19:54:58 -08008321 eth_zero_addr(mac_addr);
8322 eth_zero_addr(mac_addr_mask);
Johannes Bergad2b26a2014-06-12 21:39:05 +02008323 mac_addr[0] = 0x2;
8324 mac_addr_mask[0] = 0x3;
8325
8326 return 0;
8327 }
8328
8329 /* need both or none */
8330 if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
8331 return -EINVAL;
8332
8333 memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
8334 memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
8335
8336 /* don't allow or configure an mcast address */
8337 if (!is_multicast_ether_addr(mac_addr_mask) ||
8338 is_multicast_ether_addr(mac_addr))
8339 return -EINVAL;
8340
8341 /*
8342 * allow users to pass a MAC address that has bits set outside
8343 * of the mask, but don't bother drivers with having to deal
8344 * with such bits
8345 */
8346 for (i = 0; i < ETH_ALEN; i++)
8347 mac_addr[i] &= mac_addr_mask[i];
8348
8349 return 0;
8350}
8351
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05308352static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
8353{
8354 ASSERT_WDEV_LOCK(wdev);
8355
8356 if (!cfg80211_beaconing_iface_active(wdev))
8357 return true;
8358
8359 if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
8360 return true;
8361
8362 return regulatory_pre_cac_allowed(wdev->wiphy);
8363}
8364
Johannes Bergdb0a4ad2018-05-28 15:47:37 +02008365static bool nl80211_check_scan_feat(struct wiphy *wiphy, u32 flags, u32 flag,
8366 enum nl80211_ext_feature_index feat)
8367{
8368 if (!(flags & flag))
8369 return true;
8370 if (wiphy_ext_feature_isset(wiphy, feat))
8371 return true;
8372 return false;
8373}
8374
Roee Zamir2d23d072017-08-06 11:38:22 +03008375static int
8376nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
8377 void *request, struct nlattr **attrs,
8378 bool is_sched_scan)
8379{
8380 u8 *mac_addr, *mac_addr_mask;
8381 u32 *flags;
8382 enum nl80211_feature_flags randomness_flag;
8383
8384 if (!attrs[NL80211_ATTR_SCAN_FLAGS])
8385 return 0;
8386
8387 if (is_sched_scan) {
8388 struct cfg80211_sched_scan_request *req = request;
8389
8390 randomness_flag = wdev ?
8391 NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR :
8392 NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
8393 flags = &req->flags;
8394 mac_addr = req->mac_addr;
8395 mac_addr_mask = req->mac_addr_mask;
8396 } else {
8397 struct cfg80211_scan_request *req = request;
8398
8399 randomness_flag = NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
8400 flags = &req->flags;
8401 mac_addr = req->mac_addr;
8402 mac_addr_mask = req->mac_addr_mask;
8403 }
8404
8405 *flags = nla_get_u32(attrs[NL80211_ATTR_SCAN_FLAGS]);
8406
Sunil Dutt5037a002018-01-25 17:13:37 +02008407 if (((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
8408 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
Johannes Bergdb0a4ad2018-05-28 15:47:37 +02008409 !nl80211_check_scan_feat(wiphy, *flags,
8410 NL80211_SCAN_FLAG_LOW_SPAN,
8411 NL80211_EXT_FEATURE_LOW_SPAN_SCAN) ||
8412 !nl80211_check_scan_feat(wiphy, *flags,
8413 NL80211_SCAN_FLAG_LOW_POWER,
8414 NL80211_EXT_FEATURE_LOW_POWER_SCAN) ||
8415 !nl80211_check_scan_feat(wiphy, *flags,
8416 NL80211_SCAN_FLAG_HIGH_ACCURACY,
8417 NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN) ||
8418 !nl80211_check_scan_feat(wiphy, *flags,
8419 NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME,
8420 NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME) ||
8421 !nl80211_check_scan_feat(wiphy, *flags,
8422 NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP,
8423 NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP) ||
8424 !nl80211_check_scan_feat(wiphy, *flags,
8425 NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
8426 NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) ||
8427 !nl80211_check_scan_feat(wiphy, *flags,
8428 NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE,
Johannes Berg2e076f12018-05-28 15:47:40 +02008429 NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE) ||
8430 !nl80211_check_scan_feat(wiphy, *flags,
8431 NL80211_SCAN_FLAG_RANDOM_SN,
8432 NL80211_EXT_FEATURE_SCAN_RANDOM_SN) ||
8433 !nl80211_check_scan_feat(wiphy, *flags,
8434 NL80211_SCAN_FLAG_MIN_PREQ_CONTENT,
8435 NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT))
Roee Zamir2d23d072017-08-06 11:38:22 +03008436 return -EOPNOTSUPP;
8437
8438 if (*flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
8439 int err;
8440
8441 if (!(wiphy->features & randomness_flag) ||
8442 (wdev && wdev->current_bss))
8443 return -EOPNOTSUPP;
8444
8445 err = nl80211_parse_random_mac(attrs, mac_addr, mac_addr_mask);
8446 if (err)
8447 return err;
8448 }
8449
Roee Zamir2d23d072017-08-06 11:38:22 +03008450 return 0;
8451}
8452
Johannes Berg2a519312009-02-10 21:25:55 +01008453static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
8454{
Johannes Berg4c476992010-10-04 21:36:35 +02008455 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfd014282012-06-18 19:17:03 +02008456 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2a519312009-02-10 21:25:55 +01008457 struct cfg80211_scan_request *request;
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07008458 struct nlattr *scan_freqs = NULL;
8459 bool scan_freqs_khz = false;
Johannes Berg2a519312009-02-10 21:25:55 +01008460 struct nlattr *attr;
8461 struct wiphy *wiphy;
Johannes Berg83f5e2c2009-06-17 17:41:49 +02008462 int err, tmp, n_ssids = 0, n_channels, i;
Jouni Malinen70692ad2009-02-16 19:39:13 +02008463 size_t ie_len;
Johannes Berg2a519312009-02-10 21:25:55 +01008464
Johannes Berg79c97e92009-07-07 03:56:12 +02008465 wiphy = &rdev->wiphy;
Johannes Berg2a519312009-02-10 21:25:55 +01008466
Ayala Bekercb3b7d82016-09-20 17:31:13 +03008467 if (wdev->iftype == NL80211_IFTYPE_NAN)
8468 return -EOPNOTSUPP;
8469
Johannes Berg4c476992010-10-04 21:36:35 +02008470 if (!rdev->ops->scan)
8471 return -EOPNOTSUPP;
Johannes Berg2a519312009-02-10 21:25:55 +01008472
Christophe JAILLET83286852020-07-12 19:35:39 +02008473 if (rdev->scan_req || rdev->scan_msg)
8474 return -EBUSY;
Johannes Berg2a519312009-02-10 21:25:55 +01008475
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07008476 if (info->attrs[NL80211_ATTR_SCAN_FREQ_KHZ]) {
8477 if (!wiphy_ext_feature_isset(wiphy,
8478 NL80211_EXT_FEATURE_SCAN_FREQ_KHZ))
8479 return -EOPNOTSUPP;
8480 scan_freqs = info->attrs[NL80211_ATTR_SCAN_FREQ_KHZ];
8481 scan_freqs_khz = true;
8482 } else if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES])
8483 scan_freqs = info->attrs[NL80211_ATTR_SCAN_FREQUENCIES];
8484
8485 if (scan_freqs) {
8486 n_channels = validate_scan_freqs(scan_freqs);
Christophe JAILLET83286852020-07-12 19:35:39 +02008487 if (!n_channels)
8488 return -EINVAL;
Johannes Berg2a519312009-02-10 21:25:55 +01008489 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02008490 n_channels = ieee80211_get_num_supported_channels(wiphy);
Johannes Berg2a519312009-02-10 21:25:55 +01008491 }
8492
8493 if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
8494 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
8495 n_ssids++;
8496
Christophe JAILLET83286852020-07-12 19:35:39 +02008497 if (n_ssids > wiphy->max_scan_ssids)
8498 return -EINVAL;
Johannes Berg2a519312009-02-10 21:25:55 +01008499
Jouni Malinen70692ad2009-02-16 19:39:13 +02008500 if (info->attrs[NL80211_ATTR_IE])
8501 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8502 else
8503 ie_len = 0;
8504
Christophe JAILLET83286852020-07-12 19:35:39 +02008505 if (ie_len > wiphy->max_scan_ie_len)
8506 return -EINVAL;
Johannes Berg18a83652009-03-31 12:12:05 +02008507
Johannes Berg2a519312009-02-10 21:25:55 +01008508 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03008509 + sizeof(*request->ssids) * n_ssids
8510 + sizeof(*request->channels) * n_channels
Jouni Malinen70692ad2009-02-16 19:39:13 +02008511 + ie_len, GFP_KERNEL);
Christophe JAILLET83286852020-07-12 19:35:39 +02008512 if (!request)
8513 return -ENOMEM;
Johannes Berg2a519312009-02-10 21:25:55 +01008514
Johannes Berg2a519312009-02-10 21:25:55 +01008515 if (n_ssids)
Johannes Berg5ba63532009-08-07 17:54:07 +02008516 request->ssids = (void *)&request->channels[n_channels];
Johannes Berg2a519312009-02-10 21:25:55 +01008517 request->n_ssids = n_ssids;
Jouni Malinen70692ad2009-02-16 19:39:13 +02008518 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01008519 if (n_ssids)
Jouni Malinen70692ad2009-02-16 19:39:13 +02008520 request->ie = (void *)(request->ssids + n_ssids);
8521 else
8522 request->ie = (void *)(request->channels + n_channels);
8523 }
Johannes Berg2a519312009-02-10 21:25:55 +01008524
Johannes Berg584991d2009-11-02 13:32:03 +01008525 i = 0;
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07008526 if (scan_freqs) {
Johannes Berg2a519312009-02-10 21:25:55 +01008527 /* user specified, bail out if channel not found */
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07008528 nla_for_each_nested(attr, scan_freqs, tmp) {
Johannes Berg584991d2009-11-02 13:32:03 +01008529 struct ieee80211_channel *chan;
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07008530 int freq = nla_get_u32(attr);
Johannes Berg584991d2009-11-02 13:32:03 +01008531
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07008532 if (!scan_freqs_khz)
8533 freq = MHZ_TO_KHZ(freq);
Johannes Berg584991d2009-11-02 13:32:03 +01008534
Thomas Pedersen2032f3b2020-04-30 10:25:52 -07008535 chan = ieee80211_get_channel_khz(wiphy, freq);
Johannes Berg584991d2009-11-02 13:32:03 +01008536 if (!chan) {
Johannes Berg2a519312009-02-10 21:25:55 +01008537 err = -EINVAL;
8538 goto out_free;
8539 }
Johannes Berg584991d2009-11-02 13:32:03 +01008540
8541 /* ignore disabled channels */
8542 if (chan->flags & IEEE80211_CHAN_DISABLED)
8543 continue;
8544
8545 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01008546 i++;
8547 }
8548 } else {
Johannes Berg57fbcce2016-04-12 15:56:15 +02008549 enum nl80211_band band;
Johannes Berg34850ab2011-07-18 18:08:35 +02008550
Johannes Berg2a519312009-02-10 21:25:55 +01008551 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02008552 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Johannes Berg2a519312009-02-10 21:25:55 +01008553 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07008554
Johannes Berg2a519312009-02-10 21:25:55 +01008555 if (!wiphy->bands[band])
8556 continue;
8557 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
Johannes Berg584991d2009-11-02 13:32:03 +01008558 struct ieee80211_channel *chan;
8559
8560 chan = &wiphy->bands[band]->channels[j];
8561
8562 if (chan->flags & IEEE80211_CHAN_DISABLED)
8563 continue;
8564
8565 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01008566 i++;
8567 }
8568 }
8569 }
8570
Johannes Berg584991d2009-11-02 13:32:03 +01008571 if (!i) {
8572 err = -EINVAL;
8573 goto out_free;
8574 }
8575
8576 request->n_channels = i;
8577
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05308578 wdev_lock(wdev);
8579 if (!cfg80211_off_channel_oper_allowed(wdev)) {
8580 struct ieee80211_channel *chan;
8581
8582 if (request->n_channels != 1) {
8583 wdev_unlock(wdev);
8584 err = -EBUSY;
8585 goto out_free;
8586 }
8587
8588 chan = request->channels[0];
8589 if (chan->center_freq != wdev->chandef.chan->center_freq) {
8590 wdev_unlock(wdev);
8591 err = -EBUSY;
8592 goto out_free;
8593 }
8594 }
8595 wdev_unlock(wdev);
8596
Johannes Berg2a519312009-02-10 21:25:55 +01008597 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01008598 if (n_ssids) {
Johannes Berg2a519312009-02-10 21:25:55 +01008599 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03008600 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Johannes Berg2a519312009-02-10 21:25:55 +01008601 err = -EINVAL;
8602 goto out_free;
8603 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03008604 request->ssids[i].ssid_len = nla_len(attr);
Johannes Berg2a519312009-02-10 21:25:55 +01008605 memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
Johannes Berg2a519312009-02-10 21:25:55 +01008606 i++;
8607 }
8608 }
8609
Jouni Malinen70692ad2009-02-16 19:39:13 +02008610 if (info->attrs[NL80211_ATTR_IE]) {
8611 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Johannes Bergde95a54b2009-04-01 11:58:36 +02008612 memcpy((void *)request->ie,
8613 nla_data(info->attrs[NL80211_ATTR_IE]),
Jouni Malinen70692ad2009-02-16 19:39:13 +02008614 request->ie_len);
8615 }
8616
Johannes Berg57fbcce2016-04-12 15:56:15 +02008617 for (i = 0; i < NUM_NL80211_BANDS; i++)
Johannes Berga401d2b2011-07-20 00:52:16 +02008618 if (wiphy->bands[i])
8619 request->rates[i] =
8620 (1 << wiphy->bands[i]->n_bitrates) - 1;
Johannes Berg34850ab2011-07-18 18:08:35 +02008621
8622 if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
8623 nla_for_each_nested(attr,
8624 info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
8625 tmp) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02008626 enum nl80211_band band = nla_type(attr);
Johannes Berg34850ab2011-07-18 18:08:35 +02008627
Johannes Berg57fbcce2016-04-12 15:56:15 +02008628 if (band < 0 || band >= NUM_NL80211_BANDS) {
Johannes Berg34850ab2011-07-18 18:08:35 +02008629 err = -EINVAL;
8630 goto out_free;
8631 }
Felix Fietkau1b09cd82013-11-20 19:40:41 +01008632
8633 if (!wiphy->bands[band])
8634 continue;
8635
Johannes Berg34850ab2011-07-18 18:08:35 +02008636 err = ieee80211_get_ratemask(wiphy->bands[band],
8637 nla_data(attr),
8638 nla_len(attr),
8639 &request->rates[band]);
8640 if (err)
8641 goto out_free;
8642 }
8643 }
8644
Avraham Stern1d762502016-07-05 17:10:13 +03008645 if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
Avraham Stern1d762502016-07-05 17:10:13 +03008646 request->duration =
8647 nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
8648 request->duration_mandatory =
8649 nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
8650 }
8651
Roee Zamir2d23d072017-08-06 11:38:22 +03008652 err = nl80211_check_scan_flags(wiphy, wdev, request, info->attrs,
8653 false);
8654 if (err)
8655 goto out_free;
Sam Lefflered4737712012-10-11 21:03:31 -07008656
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05308657 request->no_cck =
8658 nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
8659
Vamsi Krishna2fa436b2016-12-02 23:59:08 +02008660 /* Initial implementation used NL80211_ATTR_MAC to set the specific
8661 * BSSID to scan for. This was problematic because that same attribute
8662 * was already used for another purpose (local random MAC address). The
8663 * NL80211_ATTR_BSSID attribute was added to fix this. For backwards
8664 * compatibility with older userspace components, also use the
8665 * NL80211_ATTR_MAC value here if it can be determined to be used for
8666 * the specific BSSID use case instead of the random MAC address
8667 * (NL80211_ATTR_SCAN_FLAGS is used to enable random MAC address use).
8668 */
8669 if (info->attrs[NL80211_ATTR_BSSID])
8670 memcpy(request->bssid,
8671 nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
8672 else if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
8673 info->attrs[NL80211_ATTR_MAC])
Jouni Malinen818965d2016-02-26 22:12:47 +02008674 memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
8675 ETH_ALEN);
8676 else
8677 eth_broadcast_addr(request->bssid);
8678
Johannes Bergfd014282012-06-18 19:17:03 +02008679 request->wdev = wdev;
Johannes Berg79c97e92009-07-07 03:56:12 +02008680 request->wiphy = &rdev->wiphy;
Sam Leffler15d60302012-10-11 21:03:34 -07008681 request->scan_start = jiffies;
Johannes Berg2a519312009-02-10 21:25:55 +01008682
Johannes Berg79c97e92009-07-07 03:56:12 +02008683 rdev->scan_req = request;
Tova Mussaic8cb5b82020-09-18 11:33:13 +02008684 err = cfg80211_scan(rdev);
Johannes Berg2a519312009-02-10 21:25:55 +01008685
Christophe JAILLET504776b2020-07-12 19:35:51 +02008686 if (err)
8687 goto out_free;
8688
8689 nl80211_send_scan_start(rdev, wdev);
Yajun Deng1160dfa2021-08-05 19:55:27 +08008690 dev_hold(wdev->netdev);
Christophe JAILLET504776b2020-07-12 19:35:51 +02008691
8692 return 0;
8693
Johannes Berg2a519312009-02-10 21:25:55 +01008694 out_free:
Christophe JAILLET504776b2020-07-12 19:35:51 +02008695 rdev->scan_req = NULL;
8696 kfree(request);
Johannes Berg3b858752009-03-12 09:55:09 +01008697
Johannes Berg2a519312009-02-10 21:25:55 +01008698 return err;
8699}
8700
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +05308701static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
8702{
8703 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8704 struct wireless_dev *wdev = info->user_ptr[1];
8705
8706 if (!rdev->ops->abort_scan)
8707 return -EOPNOTSUPP;
8708
8709 if (rdev->scan_msg)
8710 return 0;
8711
8712 if (!rdev->scan_req)
8713 return -ENOENT;
8714
8715 rdev_abort_scan(rdev, wdev);
8716 return 0;
8717}
8718
Avraham Stern3b06d272015-10-12 09:51:34 +03008719static int
8720nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
8721 struct cfg80211_sched_scan_request *request,
8722 struct nlattr **attrs)
8723{
8724 int tmp, err, i = 0;
8725 struct nlattr *attr;
8726
8727 if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
8728 u32 interval;
8729
8730 /*
8731 * If scan plans are not specified,
Arend Van Spriel5a88de52016-11-17 09:02:40 +00008732 * %NL80211_ATTR_SCHED_SCAN_INTERVAL will be specified. In this
Avraham Stern3b06d272015-10-12 09:51:34 +03008733 * case one scan plan will be set with the specified scan
8734 * interval and infinite number of iterations.
8735 */
Avraham Stern3b06d272015-10-12 09:51:34 +03008736 interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
8737 if (!interval)
8738 return -EINVAL;
8739
8740 request->scan_plans[0].interval =
8741 DIV_ROUND_UP(interval, MSEC_PER_SEC);
8742 if (!request->scan_plans[0].interval)
8743 return -EINVAL;
8744
8745 if (request->scan_plans[0].interval >
8746 wiphy->max_sched_scan_plan_interval)
8747 request->scan_plans[0].interval =
8748 wiphy->max_sched_scan_plan_interval;
8749
8750 return 0;
8751 }
8752
8753 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
8754 struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
8755
8756 if (WARN_ON(i >= n_plans))
8757 return -EINVAL;
8758
Johannes Berg8cb08172019-04-26 14:07:28 +02008759 err = nla_parse_nested_deprecated(plan,
8760 NL80211_SCHED_SCAN_PLAN_MAX,
8761 attr, nl80211_plan_policy,
8762 NULL);
Avraham Stern3b06d272015-10-12 09:51:34 +03008763 if (err)
8764 return err;
8765
8766 if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
8767 return -EINVAL;
8768
8769 request->scan_plans[i].interval =
8770 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
8771 if (!request->scan_plans[i].interval ||
8772 request->scan_plans[i].interval >
8773 wiphy->max_sched_scan_plan_interval)
8774 return -EINVAL;
8775
8776 if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
8777 request->scan_plans[i].iterations =
8778 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
8779 if (!request->scan_plans[i].iterations ||
8780 (request->scan_plans[i].iterations >
8781 wiphy->max_sched_scan_plan_iterations))
8782 return -EINVAL;
8783 } else if (i < n_plans - 1) {
8784 /*
8785 * All scan plans but the last one must specify
8786 * a finite number of iterations
8787 */
8788 return -EINVAL;
8789 }
8790
8791 i++;
8792 }
8793
8794 /*
8795 * The last scan plan must not specify the number of
8796 * iterations, it is supposed to run infinitely
8797 */
8798 if (request->scan_plans[n_plans - 1].iterations)
8799 return -EINVAL;
8800
8801 return 0;
8802}
8803
vamsi krishna1e1b11b2019-02-01 18:34:51 +05308804static int
8805nl80211_parse_sched_scan_per_band_rssi(struct wiphy *wiphy,
8806 struct cfg80211_match_set *match_sets,
8807 struct nlattr *tb_band_rssi,
8808 s32 rssi_thold)
8809{
8810 struct nlattr *attr;
8811 int i, tmp, ret = 0;
8812
8813 if (!wiphy_ext_feature_isset(wiphy,
8814 NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD)) {
8815 if (tb_band_rssi)
8816 ret = -EOPNOTSUPP;
8817 else
8818 for (i = 0; i < NUM_NL80211_BANDS; i++)
8819 match_sets->per_band_rssi_thold[i] =
8820 NL80211_SCAN_RSSI_THOLD_OFF;
8821 return ret;
8822 }
8823
8824 for (i = 0; i < NUM_NL80211_BANDS; i++)
8825 match_sets->per_band_rssi_thold[i] = rssi_thold;
8826
8827 nla_for_each_nested(attr, tb_band_rssi, tmp) {
8828 enum nl80211_band band = nla_type(attr);
8829
8830 if (band < 0 || band >= NUM_NL80211_BANDS)
8831 return -EINVAL;
8832
8833 match_sets->per_band_rssi_thold[band] = nla_get_s32(attr);
8834 }
8835
8836 return 0;
8837}
8838
Luciano Coelho256da022014-11-10 16:13:46 +02008839static struct cfg80211_sched_scan_request *
Johannes Bergad2b26a2014-06-12 21:39:05 +02008840nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00008841 struct nlattr **attrs, int max_match_sets)
Luciano Coelho807f8a82011-05-11 17:09:35 +03008842{
8843 struct cfg80211_sched_scan_request *request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008844 struct nlattr *attr;
Avraham Stern3b06d272015-10-12 09:51:34 +03008845 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
Johannes Berg57fbcce2016-04-12 15:56:15 +02008846 enum nl80211_band band;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008847 size_t ie_len;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008848 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
Johannes Bergea73cbc2014-01-24 10:53:53 +01008849 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelho807f8a82011-05-11 17:09:35 +03008850
Luciano Coelho256da022014-11-10 16:13:46 +02008851 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03008852 n_channels = validate_scan_freqs(
Luciano Coelho256da022014-11-10 16:13:46 +02008853 attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008854 if (!n_channels)
Luciano Coelho256da022014-11-10 16:13:46 +02008855 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008856 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02008857 n_channels = ieee80211_get_num_supported_channels(wiphy);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008858 }
8859
Luciano Coelho256da022014-11-10 16:13:46 +02008860 if (attrs[NL80211_ATTR_SCAN_SSIDS])
8861 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03008862 tmp)
8863 n_ssids++;
8864
Luciano Coelho93b6aa62011-07-13 14:57:28 +03008865 if (n_ssids > wiphy->max_sched_scan_ssids)
Luciano Coelho256da022014-11-10 16:13:46 +02008866 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008867
Johannes Bergea73cbc2014-01-24 10:53:53 +01008868 /*
8869 * First, count the number of 'real' matchsets. Due to an issue with
8870 * the old implementation, matchsets containing only the RSSI attribute
8871 * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
8872 * RSSI for all matchsets, rather than their own matchset for reporting
8873 * all APs with a strong RSSI. This is needed to be compatible with
8874 * older userspace that treated a matchset with only the RSSI as the
8875 * global RSSI for all other matchsets - if there are other matchsets.
8876 */
Luciano Coelho256da022014-11-10 16:13:46 +02008877 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008878 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02008879 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Johannes Bergea73cbc2014-01-24 10:53:53 +01008880 tmp) {
8881 struct nlattr *rssi;
8882
Johannes Berg8cb08172019-04-26 14:07:28 +02008883 err = nla_parse_nested_deprecated(tb,
8884 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
8885 attr,
8886 nl80211_match_policy,
8887 NULL);
Johannes Bergea73cbc2014-01-24 10:53:53 +01008888 if (err)
Luciano Coelho256da022014-11-10 16:13:46 +02008889 return ERR_PTR(err);
Arend Van Spriel3007e352017-04-21 13:05:01 +01008890
8891 /* SSID and BSSID are mutually exclusive */
8892 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] &&
8893 tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID])
8894 return ERR_PTR(-EINVAL);
8895
Johannes Bergea73cbc2014-01-24 10:53:53 +01008896 /* add other standalone attributes here */
Arend Van Spriel3007e352017-04-21 13:05:01 +01008897 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] ||
8898 tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID]) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01008899 n_match_sets++;
8900 continue;
8901 }
8902 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
8903 if (rssi)
8904 default_match_rssi = nla_get_s32(rssi);
8905 }
8906 }
8907
8908 /* However, if there's no other matchset, add the RSSI one */
8909 if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
8910 n_match_sets = 1;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008911
Arend Van Sprielaad1e812017-01-27 12:27:44 +00008912 if (n_match_sets > max_match_sets)
Luciano Coelho256da022014-11-10 16:13:46 +02008913 return ERR_PTR(-EINVAL);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008914
Luciano Coelho256da022014-11-10 16:13:46 +02008915 if (attrs[NL80211_ATTR_IE])
8916 ie_len = nla_len(attrs[NL80211_ATTR_IE]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008917 else
8918 ie_len = 0;
8919
Luciano Coelho5a865ba2011-07-13 14:57:29 +03008920 if (ie_len > wiphy->max_sched_scan_ie_len)
Luciano Coelho256da022014-11-10 16:13:46 +02008921 return ERR_PTR(-EINVAL);
Luciano Coelhoc10841c2011-06-30 08:32:41 +03008922
Avraham Stern3b06d272015-10-12 09:51:34 +03008923 if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
8924 /*
8925 * NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
8926 * each scan plan already specifies its own interval
8927 */
8928 if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
8929 return ERR_PTR(-EINVAL);
8930
8931 nla_for_each_nested(attr,
8932 attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
8933 n_plans++;
8934 } else {
8935 /*
8936 * The scan interval attribute is kept for backward
8937 * compatibility. If no scan plans are specified and sched scan
8938 * interval is specified, one scan plan will be set with this
8939 * scan interval and infinite number of iterations.
8940 */
8941 if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
8942 return ERR_PTR(-EINVAL);
8943
8944 n_plans = 1;
8945 }
8946
8947 if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
8948 return ERR_PTR(-EINVAL);
8949
vamsi krishnabf95ecd2017-01-13 01:12:20 +02008950 if (!wiphy_ext_feature_isset(
8951 wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
8952 (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
8953 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
8954 return ERR_PTR(-EINVAL);
8955
Luciano Coelho807f8a82011-05-11 17:09:35 +03008956 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03008957 + sizeof(*request->ssids) * n_ssids
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008958 + sizeof(*request->match_sets) * n_match_sets
Avraham Stern3b06d272015-10-12 09:51:34 +03008959 + sizeof(*request->scan_plans) * n_plans
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03008960 + sizeof(*request->channels) * n_channels
Luciano Coelho807f8a82011-05-11 17:09:35 +03008961 + ie_len, GFP_KERNEL);
Luciano Coelho256da022014-11-10 16:13:46 +02008962 if (!request)
8963 return ERR_PTR(-ENOMEM);
Luciano Coelho807f8a82011-05-11 17:09:35 +03008964
8965 if (n_ssids)
8966 request->ssids = (void *)&request->channels[n_channels];
8967 request->n_ssids = n_ssids;
8968 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01008969 if (n_ssids)
Luciano Coelho807f8a82011-05-11 17:09:35 +03008970 request->ie = (void *)(request->ssids + n_ssids);
8971 else
8972 request->ie = (void *)(request->channels + n_channels);
8973 }
8974
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008975 if (n_match_sets) {
8976 if (request->ie)
8977 request->match_sets = (void *)(request->ie + ie_len);
Johannes Berg13874e42015-01-23 11:25:20 +01008978 else if (n_ssids)
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03008979 request->match_sets =
8980 (void *)(request->ssids + n_ssids);
8981 else
8982 request->match_sets =
8983 (void *)(request->channels + n_channels);
8984 }
8985 request->n_match_sets = n_match_sets;
8986
Avraham Stern3b06d272015-10-12 09:51:34 +03008987 if (n_match_sets)
8988 request->scan_plans = (void *)(request->match_sets +
8989 n_match_sets);
8990 else if (request->ie)
8991 request->scan_plans = (void *)(request->ie + ie_len);
8992 else if (n_ssids)
8993 request->scan_plans = (void *)(request->ssids + n_ssids);
8994 else
8995 request->scan_plans = (void *)(request->channels + n_channels);
8996
8997 request->n_scan_plans = n_plans;
8998
Luciano Coelho807f8a82011-05-11 17:09:35 +03008999 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02009000 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03009001 /* user specified, bail out if channel not found */
9002 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02009003 attrs[NL80211_ATTR_SCAN_FREQUENCIES],
Luciano Coelho807f8a82011-05-11 17:09:35 +03009004 tmp) {
9005 struct ieee80211_channel *chan;
9006
9007 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
9008
9009 if (!chan) {
9010 err = -EINVAL;
9011 goto out_free;
9012 }
9013
9014 /* ignore disabled channels */
9015 if (chan->flags & IEEE80211_CHAN_DISABLED)
9016 continue;
9017
9018 request->channels[i] = chan;
9019 i++;
9020 }
9021 } else {
9022 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02009023 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03009024 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07009025
Luciano Coelho807f8a82011-05-11 17:09:35 +03009026 if (!wiphy->bands[band])
9027 continue;
9028 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
9029 struct ieee80211_channel *chan;
9030
9031 chan = &wiphy->bands[band]->channels[j];
9032
9033 if (chan->flags & IEEE80211_CHAN_DISABLED)
9034 continue;
9035
9036 request->channels[i] = chan;
9037 i++;
9038 }
9039 }
9040 }
9041
9042 if (!i) {
9043 err = -EINVAL;
9044 goto out_free;
9045 }
9046
9047 request->n_channels = i;
9048
9049 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01009050 if (n_ssids) {
Luciano Coelho256da022014-11-10 16:13:46 +02009051 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03009052 tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03009053 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03009054 err = -EINVAL;
9055 goto out_free;
9056 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03009057 request->ssids[i].ssid_len = nla_len(attr);
Luciano Coelho807f8a82011-05-11 17:09:35 +03009058 memcpy(request->ssids[i].ssid, nla_data(attr),
9059 nla_len(attr));
Luciano Coelho807f8a82011-05-11 17:09:35 +03009060 i++;
9061 }
9062 }
9063
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03009064 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02009065 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03009066 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02009067 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03009068 tmp) {
Arend Van Spriel3007e352017-04-21 13:05:01 +01009069 struct nlattr *ssid, *bssid, *rssi;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03009070
Johannes Berg8cb08172019-04-26 14:07:28 +02009071 err = nla_parse_nested_deprecated(tb,
9072 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
9073 attr,
9074 nl80211_match_policy,
9075 NULL);
Johannes Bergae811e22014-01-24 10:17:47 +01009076 if (err)
9077 goto out_free;
Johannes Berg4a4ab0d2012-06-13 11:17:11 +02009078 ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
Arend Van Spriel3007e352017-04-21 13:05:01 +01009079 bssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID];
Johannes Bergd39f3b42019-04-08 13:40:47 +02009080
9081 if (!ssid && !bssid) {
9082 i++;
9083 continue;
9084 }
9085
9086 if (WARN_ON(i >= n_match_sets)) {
9087 /* this indicates a programming error,
9088 * the loop above should have verified
9089 * things properly
9090 */
9091 err = -EINVAL;
9092 goto out_free;
9093 }
9094
9095 if (ssid) {
Johannes Bergd39f3b42019-04-08 13:40:47 +02009096 memcpy(request->match_sets[i].ssid.ssid,
9097 nla_data(ssid), nla_len(ssid));
9098 request->match_sets[i].ssid.ssid_len =
9099 nla_len(ssid);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03009100 }
Johannes Bergcb9abd42020-08-05 15:47:16 +02009101 if (bssid)
Johannes Bergd39f3b42019-04-08 13:40:47 +02009102 memcpy(request->match_sets[i].bssid,
9103 nla_data(bssid), ETH_ALEN);
Johannes Bergd39f3b42019-04-08 13:40:47 +02009104
9105 /* special attribute - old implementation w/a */
9106 request->match_sets[i].rssi_thold = default_match_rssi;
9107 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
9108 if (rssi)
9109 request->match_sets[i].rssi_thold =
9110 nla_get_s32(rssi);
vamsi krishna1e1b11b2019-02-01 18:34:51 +05309111
9112 /* Parse per band RSSI attribute */
9113 err = nl80211_parse_sched_scan_per_band_rssi(wiphy,
9114 &request->match_sets[i],
9115 tb[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI],
9116 request->match_sets[i].rssi_thold);
9117 if (err)
9118 goto out_free;
9119
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03009120 i++;
9121 }
Johannes Bergea73cbc2014-01-24 10:53:53 +01009122
9123 /* there was no other matchset, so the RSSI one is alone */
Luciano Coelhof89f46c2014-12-01 11:32:09 +02009124 if (i == 0 && n_match_sets)
Johannes Bergea73cbc2014-01-24 10:53:53 +01009125 request->match_sets[0].rssi_thold = default_match_rssi;
9126
9127 request->min_rssi_thold = INT_MAX;
9128 for (i = 0; i < n_match_sets; i++)
9129 request->min_rssi_thold =
9130 min(request->match_sets[i].rssi_thold,
9131 request->min_rssi_thold);
9132 } else {
9133 request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03009134 }
9135
Johannes Berg9900e482014-02-04 21:01:25 +01009136 if (ie_len) {
9137 request->ie_len = ie_len;
Luciano Coelho807f8a82011-05-11 17:09:35 +03009138 memcpy((void *)request->ie,
Luciano Coelho256da022014-11-10 16:13:46 +02009139 nla_data(attrs[NL80211_ATTR_IE]),
Luciano Coelho807f8a82011-05-11 17:09:35 +03009140 request->ie_len);
9141 }
9142
Roee Zamir2d23d072017-08-06 11:38:22 +03009143 err = nl80211_check_scan_flags(wiphy, wdev, request, attrs, true);
9144 if (err)
9145 goto out_free;
Sam Lefflered4737712012-10-11 21:03:31 -07009146
Luciano Coelho9c748932015-01-16 16:04:09 +02009147 if (attrs[NL80211_ATTR_SCHED_SCAN_DELAY])
9148 request->delay =
9149 nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
9150
vamsi krishnabf95ecd2017-01-13 01:12:20 +02009151 if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
9152 request->relative_rssi = nla_get_s8(
9153 attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
9154 request->relative_rssi_set = true;
9155 }
9156
9157 if (request->relative_rssi_set &&
9158 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
9159 struct nl80211_bss_select_rssi_adjust *rssi_adjust;
9160
9161 rssi_adjust = nla_data(
9162 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
9163 request->rssi_adjust.band = rssi_adjust->band;
9164 request->rssi_adjust.delta = rssi_adjust->delta;
9165 if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
9166 err = -EINVAL;
9167 goto out_free;
9168 }
9169 }
9170
Avraham Stern3b06d272015-10-12 09:51:34 +03009171 err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
9172 if (err)
9173 goto out_free;
9174
Sam Leffler15d60302012-10-11 21:03:34 -07009175 request->scan_start = jiffies;
Luciano Coelho807f8a82011-05-11 17:09:35 +03009176
Luciano Coelho256da022014-11-10 16:13:46 +02009177 return request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03009178
9179out_free:
9180 kfree(request);
Luciano Coelho256da022014-11-10 16:13:46 +02009181 return ERR_PTR(err);
9182}
9183
9184static int nl80211_start_sched_scan(struct sk_buff *skb,
9185 struct genl_info *info)
9186{
9187 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9188 struct net_device *dev = info->user_ptr[1];
Johannes Bergad2b26a2014-06-12 21:39:05 +02009189 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02009190 struct cfg80211_sched_scan_request *sched_scan_req;
Arend Van Sprielca986ad2017-04-21 13:05:00 +01009191 bool want_multi;
Luciano Coelho256da022014-11-10 16:13:46 +02009192 int err;
9193
Arend Van Sprielca986ad2017-04-21 13:05:00 +01009194 if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_start)
Luciano Coelho256da022014-11-10 16:13:46 +02009195 return -EOPNOTSUPP;
9196
Arend Van Sprielca986ad2017-04-21 13:05:00 +01009197 want_multi = info->attrs[NL80211_ATTR_SCHED_SCAN_MULTI];
9198 err = cfg80211_sched_scan_req_possible(rdev, want_multi);
9199 if (err)
9200 return err;
Luciano Coelho256da022014-11-10 16:13:46 +02009201
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02009202 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00009203 info->attrs,
9204 rdev->wiphy.max_match_sets);
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02009205
9206 err = PTR_ERR_OR_ZERO(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02009207 if (err)
9208 goto out_err;
9209
Arend Van Sprielca986ad2017-04-21 13:05:00 +01009210 /* leave request id zero for legacy request
9211 * or if driver does not support multi-scheduled scan
9212 */
Denis Kenzior2fd351a2019-10-08 11:43:50 -05009213 if (want_multi && rdev->wiphy.max_sched_scan_reqs > 1)
9214 sched_scan_req->reqid = cfg80211_assign_cookie(rdev);
Arend Van Sprielca986ad2017-04-21 13:05:00 +01009215
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02009216 err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02009217 if (err)
9218 goto out_free;
9219
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02009220 sched_scan_req->dev = dev;
9221 sched_scan_req->wiphy = &rdev->wiphy;
9222
Jukka Rissanen93a1e862014-12-15 13:25:39 +02009223 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
9224 sched_scan_req->owner_nlportid = info->snd_portid;
9225
Arend Van Sprielca986ad2017-04-21 13:05:00 +01009226 cfg80211_add_sched_scan_req(rdev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02009227
Arend Van Spriel96b08fd2017-04-13 13:06:27 +01009228 nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN);
Luciano Coelho256da022014-11-10 16:13:46 +02009229 return 0;
9230
9231out_free:
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02009232 kfree(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02009233out_err:
Luciano Coelho807f8a82011-05-11 17:09:35 +03009234 return err;
9235}
9236
9237static int nl80211_stop_sched_scan(struct sk_buff *skb,
9238 struct genl_info *info)
9239{
Arend Van Sprielca986ad2017-04-21 13:05:00 +01009240 struct cfg80211_sched_scan_request *req;
Luciano Coelho807f8a82011-05-11 17:09:35 +03009241 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Arend Van Sprielca986ad2017-04-21 13:05:00 +01009242 u64 cookie;
Luciano Coelho807f8a82011-05-11 17:09:35 +03009243
Arend Van Sprielca986ad2017-04-21 13:05:00 +01009244 if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_stop)
Luciano Coelho807f8a82011-05-11 17:09:35 +03009245 return -EOPNOTSUPP;
9246
Arend Van Sprielca986ad2017-04-21 13:05:00 +01009247 if (info->attrs[NL80211_ATTR_COOKIE]) {
9248 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9249 return __cfg80211_stop_sched_scan(rdev, cookie, false);
9250 }
9251
9252 req = list_first_or_null_rcu(&rdev->sched_scan_req_list,
9253 struct cfg80211_sched_scan_request,
9254 list);
9255 if (!req || req->reqid ||
9256 (req->owner_nlportid &&
9257 req->owner_nlportid != info->snd_portid))
9258 return -ENOENT;
9259
9260 return cfg80211_stop_sched_scan_req(rdev, req, false);
Luciano Coelho807f8a82011-05-11 17:09:35 +03009261}
9262
Simon Wunderlich04f39042013-02-08 18:16:19 +01009263static int nl80211_start_radar_detection(struct sk_buff *skb,
9264 struct genl_info *info)
9265{
9266 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9267 struct net_device *dev = info->user_ptr[1];
9268 struct wireless_dev *wdev = dev->ieee80211_ptr;
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03009269 struct wiphy *wiphy = wdev->wiphy;
Simon Wunderlich04f39042013-02-08 18:16:19 +01009270 struct cfg80211_chan_def chandef;
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01009271 enum nl80211_dfs_regions dfs_region;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01009272 unsigned int cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01009273 int err;
9274
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03009275 dfs_region = reg_get_dfs_region(wiphy);
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01009276 if (dfs_region == NL80211_DFS_UNSET)
9277 return -EINVAL;
9278
Simon Wunderlich04f39042013-02-08 18:16:19 +01009279 err = nl80211_parse_chandef(rdev, info, &chandef);
9280 if (err)
9281 return err;
9282
Simon Wunderlichff311bc2013-09-03 19:43:18 +02009283 if (netif_carrier_ok(dev))
9284 return -EBUSY;
9285
Simon Wunderlich04f39042013-02-08 18:16:19 +01009286 if (wdev->cac_started)
9287 return -EBUSY;
9288
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03009289 err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
Simon Wunderlich04f39042013-02-08 18:16:19 +01009290 if (err < 0)
9291 return err;
9292
9293 if (err == 0)
9294 return -EINVAL;
9295
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03009296 if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
Simon Wunderlich04f39042013-02-08 18:16:19 +01009297 return -EINVAL;
9298
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03009299 /* CAC start is offloaded to HW and can't be started manually */
9300 if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))
9301 return -EOPNOTSUPP;
9302
Simon Wunderlich04f39042013-02-08 18:16:19 +01009303 if (!rdev->ops->start_radar_detection)
9304 return -EOPNOTSUPP;
9305
Janusz Dziedzic31559f32014-02-21 19:46:13 +01009306 cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
9307 if (WARN_ON(!cac_time_ms))
9308 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
9309
Ilan Peera1056b1b2015-10-22 22:27:46 +03009310 err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
Simon Wunderlich04f39042013-02-08 18:16:19 +01009311 if (!err) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01009312 wdev->chandef = chandef;
Simon Wunderlich04f39042013-02-08 18:16:19 +01009313 wdev->cac_started = true;
9314 wdev->cac_start_time = jiffies;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01009315 wdev->cac_time_ms = cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01009316 }
Simon Wunderlich04f39042013-02-08 18:16:19 +01009317 return err;
9318}
9319
Sriram R30c63112018-12-04 17:46:52 +05309320static int nl80211_notify_radar_detection(struct sk_buff *skb,
9321 struct genl_info *info)
9322{
9323 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9324 struct net_device *dev = info->user_ptr[1];
9325 struct wireless_dev *wdev = dev->ieee80211_ptr;
9326 struct wiphy *wiphy = wdev->wiphy;
9327 struct cfg80211_chan_def chandef;
9328 enum nl80211_dfs_regions dfs_region;
9329 int err;
9330
9331 dfs_region = reg_get_dfs_region(wiphy);
9332 if (dfs_region == NL80211_DFS_UNSET) {
9333 GENL_SET_ERR_MSG(info,
9334 "DFS Region is not set. Unexpected Radar indication");
9335 return -EINVAL;
9336 }
9337
9338 err = nl80211_parse_chandef(rdev, info, &chandef);
9339 if (err) {
9340 GENL_SET_ERR_MSG(info, "Unable to extract chandef info");
9341 return err;
9342 }
9343
9344 err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
9345 if (err < 0) {
9346 GENL_SET_ERR_MSG(info, "chandef is invalid");
9347 return err;
9348 }
9349
9350 if (err == 0) {
9351 GENL_SET_ERR_MSG(info,
9352 "Unexpected Radar indication for chandef/iftype");
9353 return -EINVAL;
9354 }
9355
9356 /* Do not process this notification if radar is already detected
9357 * by kernel on this channel, and return success.
9358 */
9359 if (chandef.chan->dfs_state == NL80211_DFS_UNAVAILABLE)
9360 return 0;
9361
9362 cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_UNAVAILABLE);
9363
9364 cfg80211_sched_dfs_chan_update(rdev);
9365
Luca Coelhoa680fe42019-04-17 09:34:40 +03009366 rdev->radar_chandef = chandef;
Sriram R30c63112018-12-04 17:46:52 +05309367
9368 /* Propagate this notification to other radios as well */
9369 queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
9370
9371 return 0;
9372}
9373
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009374static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
9375{
9376 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9377 struct net_device *dev = info->user_ptr[1];
9378 struct wireless_dev *wdev = dev->ieee80211_ptr;
9379 struct cfg80211_csa_settings params;
Johannes Berga05829a2021-01-22 16:19:43 +01009380 struct nlattr **csa_attrs = NULL;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009381 int err;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02009382 bool need_new_beacon = false;
Benjamin Berg8d9de162017-05-16 11:23:12 +02009383 bool need_handle_dfs_flag = true;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009384 int len, i;
Luciano Coelho252e07c2014-10-08 09:48:34 +03009385 u32 cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009386
9387 if (!rdev->ops->channel_switch ||
9388 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
9389 return -EOPNOTSUPP;
9390
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02009391 switch (dev->ieee80211_ptr->iftype) {
9392 case NL80211_IFTYPE_AP:
9393 case NL80211_IFTYPE_P2P_GO:
9394 need_new_beacon = true;
Benjamin Berg8d9de162017-05-16 11:23:12 +02009395 /* For all modes except AP the handle_dfs flag needs to be
9396 * supplied to tell the kernel that userspace will handle radar
9397 * events when they happen. Otherwise a switch to a channel
9398 * requiring DFS will be rejected.
9399 */
9400 need_handle_dfs_flag = false;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02009401
9402 /* useless if AP is not running */
9403 if (!wdev->beacon_interval)
Johannes Berg1ff79df2014-01-22 10:05:27 +01009404 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02009405 break;
9406 case NL80211_IFTYPE_ADHOC:
Johannes Berg1ff79df2014-01-22 10:05:27 +01009407 if (!wdev->ssid_len)
9408 return -ENOTCONN;
9409 break;
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07009410 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg1ff79df2014-01-22 10:05:27 +01009411 if (!wdev->mesh_id_len)
9412 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02009413 break;
9414 default:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009415 return -EOPNOTSUPP;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02009416 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009417
9418 memset(&params, 0, sizeof(params));
Johannes Bergc177db22018-10-30 09:17:44 +01009419 params.beacon_csa.ftm_responder = -1;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009420
9421 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
9422 !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
9423 return -EINVAL;
9424
9425 /* only important for AP, IBSS and mesh create IEs internally */
Andrei Otcheretianskid0a361a2013-10-17 10:52:17 +02009426 if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009427 return -EINVAL;
9428
Luciano Coelho252e07c2014-10-08 09:48:34 +03009429 /* Even though the attribute is u32, the specification says
9430 * u8, so let's make sure we don't overflow.
9431 */
9432 cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
9433 if (cs_count > 255)
9434 return -EINVAL;
9435
9436 params.count = cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009437
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02009438 if (!need_new_beacon)
9439 goto skip_beacons;
9440
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07009441 err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_after);
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009442 if (err)
John Crispindc1e3cb2021-09-15 19:54:34 -07009443 goto free;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009444
Johannes Berga05829a2021-01-22 16:19:43 +01009445 csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs),
9446 GFP_KERNEL);
John Crispindc1e3cb2021-09-15 19:54:34 -07009447 if (!csa_attrs) {
9448 err = -ENOMEM;
9449 goto free;
9450 }
Johannes Berga05829a2021-01-22 16:19:43 +01009451
Johannes Berg8cb08172019-04-26 14:07:28 +02009452 err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX,
9453 info->attrs[NL80211_ATTR_CSA_IES],
9454 nl80211_policy, info->extack);
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009455 if (err)
Johannes Berga05829a2021-01-22 16:19:43 +01009456 goto free;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009457
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -07009458 err = nl80211_parse_beacon(rdev, csa_attrs, &params.beacon_csa);
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009459 if (err)
Johannes Berga05829a2021-01-22 16:19:43 +01009460 goto free;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009461
Johannes Berga05829a2021-01-22 16:19:43 +01009462 if (!csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]) {
9463 err = -EINVAL;
9464 goto free;
9465 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009466
John Crispin00c207e2020-08-11 10:01:03 +02009467 len = nla_len(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]);
Johannes Berga05829a2021-01-22 16:19:43 +01009468 if (!len || (len % sizeof(u16))) {
9469 err = -EINVAL;
9470 goto free;
9471 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009472
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009473 params.n_counter_offsets_beacon = len / sizeof(u16);
9474 if (rdev->wiphy.max_num_csa_counters &&
9475 (params.n_counter_offsets_beacon >
Johannes Berga05829a2021-01-22 16:19:43 +01009476 rdev->wiphy.max_num_csa_counters)) {
9477 err = -EINVAL;
9478 goto free;
9479 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009480
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009481 params.counter_offsets_beacon =
John Crispin00c207e2020-08-11 10:01:03 +02009482 nla_data(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]);
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009483
9484 /* sanity checks - counters should fit and be the same */
9485 for (i = 0; i < params.n_counter_offsets_beacon; i++) {
9486 u16 offset = params.counter_offsets_beacon[i];
9487
Johannes Berga05829a2021-01-22 16:19:43 +01009488 if (offset >= params.beacon_csa.tail_len) {
9489 err = -EINVAL;
9490 goto free;
9491 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009492
Johannes Berga05829a2021-01-22 16:19:43 +01009493 if (params.beacon_csa.tail[offset] != params.count) {
9494 err = -EINVAL;
9495 goto free;
9496 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009497 }
9498
John Crispin00c207e2020-08-11 10:01:03 +02009499 if (csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]) {
9500 len = nla_len(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]);
Johannes Berga05829a2021-01-22 16:19:43 +01009501 if (!len || (len % sizeof(u16))) {
9502 err = -EINVAL;
9503 goto free;
9504 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009505
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009506 params.n_counter_offsets_presp = len / sizeof(u16);
9507 if (rdev->wiphy.max_num_csa_counters &&
Johannes Bergad5987b2016-09-13 15:53:55 +02009508 (params.n_counter_offsets_presp >
Johannes Berga05829a2021-01-22 16:19:43 +01009509 rdev->wiphy.max_num_csa_counters)) {
9510 err = -EINVAL;
9511 goto free;
9512 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009513
9514 params.counter_offsets_presp =
John Crispin00c207e2020-08-11 10:01:03 +02009515 nla_data(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]);
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009516
9517 /* sanity checks - counters should fit and be the same */
9518 for (i = 0; i < params.n_counter_offsets_presp; i++) {
9519 u16 offset = params.counter_offsets_presp[i];
9520
Johannes Berga05829a2021-01-22 16:19:43 +01009521 if (offset >= params.beacon_csa.probe_resp_len) {
9522 err = -EINVAL;
9523 goto free;
9524 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009525
9526 if (params.beacon_csa.probe_resp[offset] !=
Johannes Berga05829a2021-01-22 16:19:43 +01009527 params.count) {
9528 err = -EINVAL;
9529 goto free;
9530 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03009531 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009532 }
9533
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02009534skip_beacons:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009535 err = nl80211_parse_chandef(rdev, info, &params.chandef);
9536 if (err)
Johannes Berga05829a2021-01-22 16:19:43 +01009537 goto free;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009538
Arik Nemtsov923b3522015-07-08 15:41:44 +03009539 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
Johannes Berga05829a2021-01-22 16:19:43 +01009540 wdev->iftype)) {
9541 err = -EINVAL;
9542 goto free;
9543 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009544
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02009545 err = cfg80211_chandef_dfs_required(wdev->wiphy,
9546 &params.chandef,
9547 wdev->iftype);
9548 if (err < 0)
Johannes Berga05829a2021-01-22 16:19:43 +01009549 goto free;
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02009550
Benjamin Berg8d9de162017-05-16 11:23:12 +02009551 if (err > 0) {
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02009552 params.radar_required = true;
Benjamin Berg8d9de162017-05-16 11:23:12 +02009553 if (need_handle_dfs_flag &&
9554 !nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) {
Johannes Berga05829a2021-01-22 16:19:43 +01009555 err = -EINVAL;
9556 goto free;
Benjamin Berg8d9de162017-05-16 11:23:12 +02009557 }
9558 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009559
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009560 if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
9561 params.block_tx = true;
9562
Simon Wunderlichc56589e2013-11-21 18:19:49 +01009563 wdev_lock(wdev);
9564 err = rdev_channel_switch(rdev, dev, &params);
9565 wdev_unlock(wdev);
9566
Johannes Berga05829a2021-01-22 16:19:43 +01009567free:
John Crispindc1e3cb2021-09-15 19:54:34 -07009568 kfree(params.beacon_after.mbssid_ies);
9569 kfree(params.beacon_csa.mbssid_ies);
Johannes Berga05829a2021-01-22 16:19:43 +01009570 kfree(csa_attrs);
Simon Wunderlichc56589e2013-11-21 18:19:49 +01009571 return err;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02009572}
9573
Johannes Berg9720bb32011-06-21 09:45:33 +02009574static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
9575 u32 seq, int flags,
Johannes Berg2a519312009-02-10 21:25:55 +01009576 struct cfg80211_registered_device *rdev,
Johannes Berg48ab9052009-07-10 18:42:31 +02009577 struct wireless_dev *wdev,
9578 struct cfg80211_internal_bss *intbss)
Johannes Berg2a519312009-02-10 21:25:55 +01009579{
Johannes Berg48ab9052009-07-10 18:42:31 +02009580 struct cfg80211_bss *res = &intbss->pub;
Johannes Berg9caf0362012-11-29 01:25:20 +01009581 const struct cfg80211_bss_ies *ies;
Johannes Berg2a519312009-02-10 21:25:55 +01009582 void *hdr;
9583 struct nlattr *bss;
Johannes Berg48ab9052009-07-10 18:42:31 +02009584
9585 ASSERT_WDEV_LOCK(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01009586
Eric W. Biederman15e47302012-09-07 20:12:54 +00009587 hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
Johannes Berg2a519312009-02-10 21:25:55 +01009588 NL80211_CMD_NEW_SCAN_RESULTS);
9589 if (!hdr)
9590 return -1;
9591
Michal Kubecek0a833c22017-11-15 13:09:32 +01009592 genl_dump_check_consistent(cb, hdr);
Johannes Berg9720bb32011-06-21 09:45:33 +02009593
Johannes Berg97990a02013-04-19 01:02:55 +02009594 if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
9595 goto nla_put_failure;
9596 if (wdev->netdev &&
David S. Miller9360ffd2012-03-29 04:41:26 -04009597 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
9598 goto nla_put_failure;
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009599 if (nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
9600 NL80211_ATTR_PAD))
Johannes Berg97990a02013-04-19 01:02:55 +02009601 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01009602
Michal Kubecekae0be8d2019-04-26 11:13:06 +02009603 bss = nla_nest_start_noflag(msg, NL80211_ATTR_BSS);
Johannes Berg2a519312009-02-10 21:25:55 +01009604 if (!bss)
9605 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04009606 if ((!is_zero_ether_addr(res->bssid) &&
Johannes Berg9caf0362012-11-29 01:25:20 +01009607 nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
David S. Miller9360ffd2012-03-29 04:41:26 -04009608 goto nla_put_failure;
Johannes Berg9caf0362012-11-29 01:25:20 +01009609
9610 rcu_read_lock();
Johannes Berg0e227082014-08-12 20:34:30 +02009611 /* indicate whether we have probe response data or not */
9612 if (rcu_access_pointer(res->proberesp_ies) &&
9613 nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
9614 goto fail_unlock_rcu;
9615
9616 /* this pointer prefers to be pointed to probe response data
9617 * but is always valid
9618 */
Johannes Berg9caf0362012-11-29 01:25:20 +01009619 ies = rcu_dereference(res->ies);
Johannes Berg8cef2c92013-02-05 16:54:31 +01009620 if (ies) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009621 if (nla_put_u64_64bit(msg, NL80211_BSS_TSF, ies->tsf,
9622 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01009623 goto fail_unlock_rcu;
Johannes Berg8cef2c92013-02-05 16:54:31 +01009624 if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
9625 ies->len, ies->data))
9626 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01009627 }
Johannes Berg0e227082014-08-12 20:34:30 +02009628
9629 /* and this pointer is always (unless driver didn't know) beacon data */
Johannes Berg9caf0362012-11-29 01:25:20 +01009630 ies = rcu_dereference(res->beacon_ies);
Johannes Berg0e227082014-08-12 20:34:30 +02009631 if (ies && ies->from_beacon) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009632 if (nla_put_u64_64bit(msg, NL80211_BSS_BEACON_TSF, ies->tsf,
9633 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01009634 goto fail_unlock_rcu;
9635 if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
9636 ies->len, ies->data))
9637 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01009638 }
9639 rcu_read_unlock();
9640
David S. Miller9360ffd2012-03-29 04:41:26 -04009641 if (res->beacon_interval &&
9642 nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
9643 goto nla_put_failure;
9644 if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
9645 nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
Thomas Pedersen942ba882020-04-30 10:25:51 -07009646 nla_put_u32(msg, NL80211_BSS_FREQUENCY_OFFSET,
9647 res->channel->freq_offset) ||
Simon Wunderlichdcd6eac2013-07-08 16:55:49 +02009648 nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04009649 nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
9650 jiffies_to_msecs(jiffies - intbss->ts)))
9651 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01009652
Avraham Stern1d762502016-07-05 17:10:13 +03009653 if (intbss->parent_tsf &&
9654 (nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
9655 intbss->parent_tsf, NL80211_BSS_PAD) ||
9656 nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
9657 intbss->parent_bssid)))
9658 goto nla_put_failure;
9659
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02009660 if (intbss->ts_boottime &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009661 nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
9662 intbss->ts_boottime, NL80211_BSS_PAD))
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02009663 goto nla_put_failure;
9664
Sunil Dutt983dafa2017-12-13 19:51:36 +02009665 if (!nl80211_put_signal(msg, intbss->pub.chains,
9666 intbss->pub.chain_signal,
9667 NL80211_BSS_CHAIN_SIGNAL))
9668 goto nla_put_failure;
9669
Johannes Berg77965c972009-02-18 18:45:06 +01009670 switch (rdev->wiphy.signal_type) {
Johannes Berg2a519312009-02-10 21:25:55 +01009671 case CFG80211_SIGNAL_TYPE_MBM:
David S. Miller9360ffd2012-03-29 04:41:26 -04009672 if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
9673 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01009674 break;
9675 case CFG80211_SIGNAL_TYPE_UNSPEC:
David S. Miller9360ffd2012-03-29 04:41:26 -04009676 if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
9677 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01009678 break;
9679 default:
9680 break;
9681 }
9682
Johannes Berg48ab9052009-07-10 18:42:31 +02009683 switch (wdev->iftype) {
Johannes Berg074ac8d2010-09-16 14:58:22 +02009684 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg48ab9052009-07-10 18:42:31 +02009685 case NL80211_IFTYPE_STATION:
David S. Miller9360ffd2012-03-29 04:41:26 -04009686 if (intbss == wdev->current_bss &&
9687 nla_put_u32(msg, NL80211_BSS_STATUS,
9688 NL80211_BSS_STATUS_ASSOCIATED))
9689 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02009690 break;
9691 case NL80211_IFTYPE_ADHOC:
David S. Miller9360ffd2012-03-29 04:41:26 -04009692 if (intbss == wdev->current_bss &&
9693 nla_put_u32(msg, NL80211_BSS_STATUS,
9694 NL80211_BSS_STATUS_IBSS_JOINED))
9695 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02009696 break;
9697 default:
9698 break;
9699 }
9700
Johannes Berg2a519312009-02-10 21:25:55 +01009701 nla_nest_end(msg, bss);
9702
Johannes Berg053c0952015-01-16 22:09:00 +01009703 genlmsg_end(msg, hdr);
9704 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +01009705
Johannes Berg8cef2c92013-02-05 16:54:31 +01009706 fail_unlock_rcu:
9707 rcu_read_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01009708 nla_put_failure:
9709 genlmsg_cancel(msg, hdr);
9710 return -EMSGSIZE;
9711}
9712
Johannes Berg97990a02013-04-19 01:02:55 +02009713static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
Johannes Berg2a519312009-02-10 21:25:55 +01009714{
Johannes Berg48ab9052009-07-10 18:42:31 +02009715 struct cfg80211_registered_device *rdev;
Johannes Berg2a519312009-02-10 21:25:55 +01009716 struct cfg80211_internal_bss *scan;
Johannes Berg48ab9052009-07-10 18:42:31 +02009717 struct wireless_dev *wdev;
Johannes Berg97990a02013-04-19 01:02:55 +02009718 int start = cb->args[2], idx = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01009719 int err;
9720
Johannes Berg5297c652018-09-27 14:36:44 +02009721 err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
Johannes Berga05829a2021-01-22 16:19:43 +01009722 if (err)
Johannes Berg67748892010-10-04 21:14:06 +02009723 return err;
Johannes Berga05829a2021-01-22 16:19:43 +01009724 /* nl80211_prepare_wdev_dump acquired it in the successful case */
9725 __acquire(&rdev->wiphy.mtx);
Johannes Berg2a519312009-02-10 21:25:55 +01009726
Johannes Berg48ab9052009-07-10 18:42:31 +02009727 wdev_lock(wdev);
9728 spin_lock_bh(&rdev->bss_lock);
Denis Kenziord1e23c92018-05-21 10:31:13 -05009729
9730 /*
9731 * dump_scan will be called multiple times to break up the scan results
9732 * into multiple messages. It is unlikely that any more bss-es will be
9733 * expired after the first call, so only call only call this on the
9734 * first dump_scan invocation.
9735 */
9736 if (start == 0)
9737 cfg80211_bss_expire(rdev);
Johannes Berg48ab9052009-07-10 18:42:31 +02009738
Johannes Berg9720bb32011-06-21 09:45:33 +02009739 cb->seq = rdev->bss_generation;
9740
Johannes Berg48ab9052009-07-10 18:42:31 +02009741 list_for_each_entry(scan, &rdev->bss_list, list) {
Johannes Berg2a519312009-02-10 21:25:55 +01009742 if (++idx <= start)
9743 continue;
Johannes Berg9720bb32011-06-21 09:45:33 +02009744 if (nl80211_send_bss(skb, cb,
Johannes Berg2a519312009-02-10 21:25:55 +01009745 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg48ab9052009-07-10 18:42:31 +02009746 rdev, wdev, scan) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +01009747 idx--;
Johannes Berg67748892010-10-04 21:14:06 +02009748 break;
Johannes Berg2a519312009-02-10 21:25:55 +01009749 }
9750 }
9751
Johannes Berg48ab9052009-07-10 18:42:31 +02009752 spin_unlock_bh(&rdev->bss_lock);
9753 wdev_unlock(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01009754
Johannes Berg97990a02013-04-19 01:02:55 +02009755 cb->args[2] = idx;
Johannes Berga05829a2021-01-22 16:19:43 +01009756 wiphy_unlock(&rdev->wiphy);
Johannes Berg2a519312009-02-10 21:25:55 +01009757
Johannes Berg67748892010-10-04 21:14:06 +02009758 return skb->len;
Johannes Berg2a519312009-02-10 21:25:55 +01009759}
9760
Eric W. Biederman15e47302012-09-07 20:12:54 +00009761static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg11f78ac2014-11-14 16:43:50 +01009762 int flags, struct net_device *dev,
9763 bool allow_radio_stats,
9764 struct survey_info *survey)
Holger Schurig61fa7132009-11-11 12:25:40 +01009765{
9766 void *hdr;
9767 struct nlattr *infoattr;
9768
Johannes Berg11f78ac2014-11-14 16:43:50 +01009769 /* skip radio stats if userspace didn't request them */
9770 if (!survey->channel && !allow_radio_stats)
9771 return 0;
9772
Eric W. Biederman15e47302012-09-07 20:12:54 +00009773 hdr = nl80211hdr_put(msg, portid, seq, flags,
Holger Schurig61fa7132009-11-11 12:25:40 +01009774 NL80211_CMD_NEW_SURVEY_RESULTS);
9775 if (!hdr)
9776 return -ENOMEM;
9777
David S. Miller9360ffd2012-03-29 04:41:26 -04009778 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
9779 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01009780
Michal Kubecekae0be8d2019-04-26 11:13:06 +02009781 infoattr = nla_nest_start_noflag(msg, NL80211_ATTR_SURVEY_INFO);
Holger Schurig61fa7132009-11-11 12:25:40 +01009782 if (!infoattr)
9783 goto nla_put_failure;
9784
Johannes Berg11f78ac2014-11-14 16:43:50 +01009785 if (survey->channel &&
9786 nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
David S. Miller9360ffd2012-03-29 04:41:26 -04009787 survey->channel->center_freq))
9788 goto nla_put_failure;
9789
Thomas Pedersen58ef7c12020-09-21 19:28:16 -07009790 if (survey->channel && survey->channel->freq_offset &&
9791 nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY_OFFSET,
9792 survey->channel->freq_offset))
9793 goto nla_put_failure;
9794
David S. Miller9360ffd2012-03-29 04:41:26 -04009795 if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
9796 nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
9797 goto nla_put_failure;
9798 if ((survey->filled & SURVEY_INFO_IN_USE) &&
9799 nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
9800 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01009801 if ((survey->filled & SURVEY_INFO_TIME) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009802 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME,
9803 survey->time, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009804 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01009805 if ((survey->filled & SURVEY_INFO_TIME_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009806 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BUSY,
9807 survey->time_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009808 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01009809 if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009810 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
9811 survey->time_ext_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009812 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01009813 if ((survey->filled & SURVEY_INFO_TIME_RX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009814 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_RX,
9815 survey->time_rx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009816 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01009817 if ((survey->filled & SURVEY_INFO_TIME_TX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009818 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_TX,
9819 survey->time_tx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009820 goto nla_put_failure;
Johannes Berg052536a2014-11-14 16:44:11 +01009821 if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009822 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_SCAN,
9823 survey->time_scan, NL80211_SURVEY_INFO_PAD))
Johannes Berg052536a2014-11-14 16:44:11 +01009824 goto nla_put_failure;
Felix Fietkauc8cd6e72019-08-28 12:20:42 +02009825 if ((survey->filled & SURVEY_INFO_TIME_BSS_RX) &&
9826 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BSS_RX,
9827 survey->time_bss_rx, NL80211_SURVEY_INFO_PAD))
9828 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01009829
9830 nla_nest_end(msg, infoattr);
9831
Johannes Berg053c0952015-01-16 22:09:00 +01009832 genlmsg_end(msg, hdr);
9833 return 0;
Holger Schurig61fa7132009-11-11 12:25:40 +01009834
9835 nla_put_failure:
9836 genlmsg_cancel(msg, hdr);
9837 return -EMSGSIZE;
9838}
9839
Johannes Berg11f78ac2014-11-14 16:43:50 +01009840static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
Holger Schurig61fa7132009-11-11 12:25:40 +01009841{
Johannes Berg50508d92019-07-29 16:31:09 +02009842 struct nlattr **attrbuf;
Holger Schurig61fa7132009-11-11 12:25:40 +01009843 struct survey_info survey;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08009844 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02009845 struct wireless_dev *wdev;
9846 int survey_idx = cb->args[2];
Holger Schurig61fa7132009-11-11 12:25:40 +01009847 int res;
Johannes Berg11f78ac2014-11-14 16:43:50 +01009848 bool radio_stats;
Holger Schurig61fa7132009-11-11 12:25:40 +01009849
Johannes Berg50508d92019-07-29 16:31:09 +02009850 attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
9851 if (!attrbuf)
9852 return -ENOMEM;
9853
Johannes Berg5297c652018-09-27 14:36:44 +02009854 res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
Johannes Berga05829a2021-01-22 16:19:43 +01009855 if (res) {
9856 kfree(attrbuf);
9857 return res;
9858 }
9859 /* nl80211_prepare_wdev_dump acquired it in the successful case */
9860 __acquire(&rdev->wiphy.mtx);
Holger Schurig61fa7132009-11-11 12:25:40 +01009861
Johannes Berg11f78ac2014-11-14 16:43:50 +01009862 /* prepare_wdev_dump parsed the attributes */
Johannes Bergc90c39d2016-10-24 14:40:01 +02009863 radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
Johannes Berg11f78ac2014-11-14 16:43:50 +01009864
Johannes Berg97990a02013-04-19 01:02:55 +02009865 if (!wdev->netdev) {
9866 res = -EINVAL;
9867 goto out_err;
9868 }
9869
Zhao, Gang1b8ec872014-04-21 12:53:02 +08009870 if (!rdev->ops->dump_survey) {
Holger Schurig61fa7132009-11-11 12:25:40 +01009871 res = -EOPNOTSUPP;
9872 goto out_err;
9873 }
9874
9875 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08009876 res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
Holger Schurig61fa7132009-11-11 12:25:40 +01009877 if (res == -ENOENT)
9878 break;
9879 if (res)
9880 goto out_err;
9881
Johannes Berg11f78ac2014-11-14 16:43:50 +01009882 /* don't send disabled channels, but do send non-channel data */
9883 if (survey.channel &&
9884 survey.channel->flags & IEEE80211_CHAN_DISABLED) {
Luis R. Rodriguez180cdc72011-05-27 07:24:02 -07009885 survey_idx++;
9886 continue;
9887 }
9888
Holger Schurig61fa7132009-11-11 12:25:40 +01009889 if (nl80211_send_survey(skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00009890 NETLINK_CB(cb->skb).portid,
Holger Schurig61fa7132009-11-11 12:25:40 +01009891 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg11f78ac2014-11-14 16:43:50 +01009892 wdev->netdev, radio_stats, &survey) < 0)
Holger Schurig61fa7132009-11-11 12:25:40 +01009893 goto out;
9894 survey_idx++;
9895 }
9896
9897 out:
Johannes Berg97990a02013-04-19 01:02:55 +02009898 cb->args[2] = survey_idx;
Holger Schurig61fa7132009-11-11 12:25:40 +01009899 res = skb->len;
9900 out_err:
Johannes Berg50508d92019-07-29 16:31:09 +02009901 kfree(attrbuf);
Johannes Berga05829a2021-01-22 16:19:43 +01009902 wiphy_unlock(&rdev->wiphy);
Holger Schurig61fa7132009-11-11 12:25:40 +01009903 return res;
9904}
9905
Samuel Ortizb23aa672009-07-01 21:26:54 +02009906static bool nl80211_valid_wpa_versions(u32 wpa_versions)
9907{
9908 return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
Chung-Hsien Hsucc3e14c2019-05-09 09:49:05 +00009909 NL80211_WPA_VERSION_2 |
9910 NL80211_WPA_VERSION_3));
Samuel Ortizb23aa672009-07-01 21:26:54 +02009911}
9912
Jouni Malinen636a5d32009-03-19 13:39:22 +02009913static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
9914{
Johannes Berg4c476992010-10-04 21:36:35 +02009915 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9916 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02009917 struct ieee80211_channel *chan;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03009918 const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
9919 int err, ssid_len, ie_len = 0, auth_data_len = 0;
Johannes Berg19957bb2009-07-02 17:20:43 +02009920 enum nl80211_auth_type auth_type;
Johannes Bergfffd0932009-07-08 14:22:54 +02009921 struct key_parse key;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03009922 bool local_state_change;
Thomas Pedersen942ba882020-04-30 10:25:51 -07009923 u32 freq;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009924
Johannes Bergf4a11bb2009-03-27 12:40:28 +01009925 if (!info->attrs[NL80211_ATTR_MAC])
9926 return -EINVAL;
9927
Jouni Malinen17780922009-03-27 20:52:47 +02009928 if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
9929 return -EINVAL;
9930
Johannes Berg19957bb2009-07-02 17:20:43 +02009931 if (!info->attrs[NL80211_ATTR_SSID])
9932 return -EINVAL;
9933
9934 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
9935 return -EINVAL;
9936
Johannes Bergfffd0932009-07-08 14:22:54 +02009937 err = nl80211_parse_key(info, &key);
9938 if (err)
9939 return err;
9940
9941 if (key.idx >= 0) {
Johannes Berge31b8212010-10-05 19:39:30 +02009942 if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
9943 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02009944 if (!key.p.key || !key.p.key_len)
9945 return -EINVAL;
9946 if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
9947 key.p.key_len != WLAN_KEY_LEN_WEP40) &&
9948 (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
9949 key.p.key_len != WLAN_KEY_LEN_WEP104))
9950 return -EINVAL;
Johannes Bergb6b55552016-09-13 16:25:58 +02009951 if (key.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +02009952 return -EINVAL;
9953 } else {
9954 key.p.key_len = 0;
9955 key.p.key = NULL;
9956 }
9957
Johannes Bergafea0b72010-08-10 09:46:42 +02009958 if (key.idx >= 0) {
9959 int i;
9960 bool ok = false;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07009961
Johannes Bergafea0b72010-08-10 09:46:42 +02009962 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
9963 if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
9964 ok = true;
9965 break;
9966 }
9967 }
Johannes Berg4c476992010-10-04 21:36:35 +02009968 if (!ok)
9969 return -EINVAL;
Johannes Bergafea0b72010-08-10 09:46:42 +02009970 }
9971
Johannes Berg4c476992010-10-04 21:36:35 +02009972 if (!rdev->ops->auth)
9973 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009974
Johannes Berg074ac8d2010-09-16 14:58:22 +02009975 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009976 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9977 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02009978
Johannes Berg19957bb2009-07-02 17:20:43 +02009979 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Thomas Pedersen942ba882020-04-30 10:25:51 -07009980 freq = MHZ_TO_KHZ(nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
9981 if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
9982 freq +=
9983 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
9984
9985 chan = nl80211_get_valid_chan(&rdev->wiphy, freq);
Jouni Malinen664834d2014-01-15 00:01:44 +02009986 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02009987 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02009988
Johannes Berg19957bb2009-07-02 17:20:43 +02009989 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9990 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9991
9992 if (info->attrs[NL80211_ATTR_IE]) {
9993 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9994 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9995 }
9996
9997 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03009998 if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
Johannes Berg4c476992010-10-04 21:36:35 +02009999 return -EINVAL;
Johannes Berg19957bb2009-07-02 17:20:43 +020010000
Jouni Malinen63181062016-10-27 00:42:02 +030010001 if ((auth_type == NL80211_AUTHTYPE_SAE ||
10002 auth_type == NL80211_AUTHTYPE_FILS_SK ||
10003 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
10004 auth_type == NL80211_AUTHTYPE_FILS_PK) &&
Jouni Malinen11b6b5a2016-10-27 00:41:58 +030010005 !info->attrs[NL80211_ATTR_AUTH_DATA])
Jouni Malinene39e5b52012-09-30 19:29:39 +030010006 return -EINVAL;
10007
Jouni Malinen11b6b5a2016-10-27 00:41:58 +030010008 if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
Jouni Malinen63181062016-10-27 00:42:02 +030010009 if (auth_type != NL80211_AUTHTYPE_SAE &&
10010 auth_type != NL80211_AUTHTYPE_FILS_SK &&
10011 auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
10012 auth_type != NL80211_AUTHTYPE_FILS_PK)
Jouni Malinene39e5b52012-09-30 19:29:39 +030010013 return -EINVAL;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +030010014 auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
10015 auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
Jouni Malinene39e5b52012-09-30 19:29:39 +030010016 }
10017
Jouni Malinend5cdfac2010-04-04 09:37:19 +030010018 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
10019
Johannes Berg95de8172012-01-20 13:55:25 +010010020 /*
10021 * Since we no longer track auth state, ignore
10022 * requests to only change local state.
10023 */
10024 if (local_state_change)
10025 return 0;
10026
Johannes Berg91bf9b22013-05-15 17:44:01 +020010027 wdev_lock(dev->ieee80211_ptr);
10028 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
10029 ssid, ssid_len, ie, ie_len,
10030 key.p.key, key.p.key_len, key.idx,
Jouni Malinen11b6b5a2016-10-27 00:41:58 +030010031 auth_data, auth_data_len);
Johannes Berg91bf9b22013-05-15 17:44:01 +020010032 wdev_unlock(dev->ieee80211_ptr);
10033 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +020010034}
10035
Denis Kenzior64bf3d42018-03-26 12:52:43 -050010036static int validate_pae_over_nl80211(struct cfg80211_registered_device *rdev,
10037 struct genl_info *info)
10038{
10039 if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
10040 GENL_SET_ERR_MSG(info, "SOCKET_OWNER not set");
10041 return -EINVAL;
10042 }
10043
10044 if (!rdev->ops->tx_control_port ||
10045 !wiphy_ext_feature_isset(&rdev->wiphy,
10046 NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
10047 return -EOPNOTSUPP;
10048
10049 return 0;
10050}
10051
Johannes Bergc0692b82010-08-27 14:26:53 +030010052static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
10053 struct genl_info *info,
Johannes Berg3dc27d22009-07-02 21:36:37 +020010054 struct cfg80211_crypto_settings *settings,
10055 int cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +020010056{
Johannes Bergc0b2bbd2009-07-25 16:54:36 +020010057 memset(settings, 0, sizeof(*settings));
10058
Samuel Ortizb23aa672009-07-01 21:26:54 +020010059 settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
10060
Johannes Bergc0692b82010-08-27 14:26:53 +030010061 if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
10062 u16 proto;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -070010063
Johannes Bergc0692b82010-08-27 14:26:53 +030010064 proto = nla_get_u16(
10065 info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
10066 settings->control_port_ethertype = cpu_to_be16(proto);
10067 if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
10068 proto != ETH_P_PAE)
10069 return -EINVAL;
10070 if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
10071 settings->control_port_no_encrypt = true;
10072 } else
10073 settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
10074
Denis Kenzior64bf3d42018-03-26 12:52:43 -050010075 if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
10076 int r = validate_pae_over_nl80211(rdev, info);
10077
10078 if (r < 0)
10079 return r;
10080
10081 settings->control_port_over_nl80211 = true;
Markus Theil7f3f96c2020-03-12 10:10:54 +010010082
10083 if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_PREAUTH])
10084 settings->control_port_no_preauth = true;
Denis Kenzior64bf3d42018-03-26 12:52:43 -050010085 }
10086
Samuel Ortizb23aa672009-07-01 21:26:54 +020010087 if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
10088 void *data;
10089 int len, i;
10090
10091 data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
10092 len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
10093 settings->n_ciphers_pairwise = len / sizeof(u32);
10094
10095 if (len % sizeof(u32))
10096 return -EINVAL;
10097
Johannes Berg3dc27d22009-07-02 21:36:37 +020010098 if (settings->n_ciphers_pairwise > cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +020010099 return -EINVAL;
10100
10101 memcpy(settings->ciphers_pairwise, data, len);
10102
10103 for (i = 0; i < settings->n_ciphers_pairwise; i++)
Jouni Malinen38ba3c52011-09-21 18:14:56 +030010104 if (!cfg80211_supported_cipher_suite(
10105 &rdev->wiphy,
Samuel Ortizb23aa672009-07-01 21:26:54 +020010106 settings->ciphers_pairwise[i]))
10107 return -EINVAL;
10108 }
10109
10110 if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
10111 settings->cipher_group =
10112 nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
Jouni Malinen38ba3c52011-09-21 18:14:56 +030010113 if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
10114 settings->cipher_group))
Samuel Ortizb23aa672009-07-01 21:26:54 +020010115 return -EINVAL;
10116 }
10117
10118 if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
10119 settings->wpa_versions =
10120 nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
10121 if (!nl80211_valid_wpa_versions(settings->wpa_versions))
10122 return -EINVAL;
10123 }
10124
10125 if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
10126 void *data;
Jouni Malinen6d302402011-09-21 18:11:33 +030010127 int len;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010128
10129 data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
10130 len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
10131 settings->n_akm_suites = len / sizeof(u32);
10132
10133 if (len % sizeof(u32))
10134 return -EINVAL;
10135
Jouni Malinen1b9ca022011-09-21 16:13:07 +030010136 if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
10137 return -EINVAL;
10138
Samuel Ortizb23aa672009-07-01 21:26:54 +020010139 memcpy(settings->akm_suites, data, len);
Samuel Ortizb23aa672009-07-01 21:26:54 +020010140 }
10141
Eliad Peller91b5ab62017-06-09 13:08:42 +010010142 if (info->attrs[NL80211_ATTR_PMK]) {
10143 if (nla_len(info->attrs[NL80211_ATTR_PMK]) != WLAN_PMK_LEN)
10144 return -EINVAL;
10145 if (!wiphy_ext_feature_isset(&rdev->wiphy,
Chung-Hsien Hsuf9662272020-06-23 08:49:35 -050010146 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK) &&
10147 !wiphy_ext_feature_isset(&rdev->wiphy,
10148 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK))
Eliad Peller91b5ab62017-06-09 13:08:42 +010010149 return -EINVAL;
10150 settings->psk = nla_data(info->attrs[NL80211_ATTR_PMK]);
10151 }
10152
Chung-Hsien Hsu26f70442019-05-09 09:49:06 +000010153 if (info->attrs[NL80211_ATTR_SAE_PASSWORD]) {
10154 if (!wiphy_ext_feature_isset(&rdev->wiphy,
Chung-Hsien Hsu2831a632020-08-17 02:33:15 -050010155 NL80211_EXT_FEATURE_SAE_OFFLOAD) &&
10156 !wiphy_ext_feature_isset(&rdev->wiphy,
10157 NL80211_EXT_FEATURE_SAE_OFFLOAD_AP))
Chung-Hsien Hsu26f70442019-05-09 09:49:06 +000010158 return -EINVAL;
10159 settings->sae_pwd =
10160 nla_data(info->attrs[NL80211_ATTR_SAE_PASSWORD]);
10161 settings->sae_pwd_len =
10162 nla_len(info->attrs[NL80211_ATTR_SAE_PASSWORD]);
10163 }
10164
Rohan Dutta9f0ffa42020-10-27 12:09:10 +020010165 if (info->attrs[NL80211_ATTR_SAE_PWE])
10166 settings->sae_pwe =
10167 nla_get_u8(info->attrs[NL80211_ATTR_SAE_PWE]);
10168 else
10169 settings->sae_pwe = NL80211_SAE_PWE_UNSPECIFIED;
10170
Samuel Ortizb23aa672009-07-01 21:26:54 +020010171 return 0;
10172}
10173
Jouni Malinen636a5d32009-03-19 13:39:22 +020010174static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
10175{
Johannes Berg4c476992010-10-04 21:36:35 +020010176 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10177 struct net_device *dev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +020010178 struct ieee80211_channel *chan;
Johannes Bergf62fab72013-02-21 20:09:09 +010010179 struct cfg80211_assoc_request req = {};
10180 const u8 *bssid, *ssid;
10181 int err, ssid_len = 0;
Thomas Pedersen942ba882020-04-30 10:25:51 -070010182 u32 freq;
Jouni Malinen636a5d32009-03-19 13:39:22 +020010183
Andrew Zaborowskibad29292018-05-22 02:46:02 +020010184 if (dev->ieee80211_ptr->conn_owner_nlportid &&
10185 dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
10186 return -EPERM;
10187
Johannes Bergf4a11bb2009-03-27 12:40:28 +010010188 if (!info->attrs[NL80211_ATTR_MAC] ||
Johannes Berg19957bb2009-07-02 17:20:43 +020010189 !info->attrs[NL80211_ATTR_SSID] ||
10190 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
Johannes Bergf4a11bb2009-03-27 12:40:28 +010010191 return -EINVAL;
10192
Johannes Berg4c476992010-10-04 21:36:35 +020010193 if (!rdev->ops->assoc)
10194 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +020010195
Johannes Berg074ac8d2010-09-16 14:58:22 +020010196 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020010197 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
10198 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +020010199
Johannes Berg19957bb2009-07-02 17:20:43 +020010200 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +020010201
Thomas Pedersen942ba882020-04-30 10:25:51 -070010202 freq = MHZ_TO_KHZ(nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
10203 if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
10204 freq +=
10205 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
10206 chan = nl80211_get_valid_chan(&rdev->wiphy, freq);
Jouni Malinen664834d2014-01-15 00:01:44 +020010207 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +020010208 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +020010209
Johannes Berg19957bb2009-07-02 17:20:43 +020010210 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
10211 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
Jouni Malinen636a5d32009-03-19 13:39:22 +020010212
10213 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Bergf62fab72013-02-21 20:09:09 +010010214 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
10215 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +020010216 }
10217
Jouni Malinendc6382ce2009-05-06 22:09:37 +030010218 if (info->attrs[NL80211_ATTR_USE_MFP]) {
Johannes Berg4f5dadc2009-07-07 03:56:10 +020010219 enum nl80211_mfp mfp =
Jouni Malinendc6382ce2009-05-06 22:09:37 +030010220 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Johannes Berg4f5dadc2009-07-07 03:56:10 +020010221 if (mfp == NL80211_MFP_REQUIRED)
Johannes Bergf62fab72013-02-21 20:09:09 +010010222 req.use_mfp = true;
Johannes Berg4c476992010-10-04 21:36:35 +020010223 else if (mfp != NL80211_MFP_NO)
10224 return -EINVAL;
Jouni Malinendc6382ce2009-05-06 22:09:37 +030010225 }
10226
Johannes Berg3e5d7642009-07-07 14:37:26 +020010227 if (info->attrs[NL80211_ATTR_PREV_BSSID])
Johannes Bergf62fab72013-02-21 20:09:09 +010010228 req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
Johannes Berg3e5d7642009-07-07 14:37:26 +020010229
Ben Greear7e7c8922011-11-18 11:31:59 -080010230 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
Johannes Bergf62fab72013-02-21 20:09:09 +010010231 req.flags |= ASSOC_REQ_DISABLE_HT;
Ben Greear7e7c8922011-11-18 11:31:59 -080010232
10233 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +010010234 memcpy(&req.ht_capa_mask,
10235 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
10236 sizeof(req.ht_capa_mask));
Ben Greear7e7c8922011-11-18 11:31:59 -080010237
10238 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +010010239 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Ben Greear7e7c8922011-11-18 11:31:59 -080010240 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +010010241 memcpy(&req.ht_capa,
10242 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
10243 sizeof(req.ht_capa));
Ben Greear7e7c8922011-11-18 11:31:59 -080010244 }
10245
Johannes Bergee2aca32013-02-21 17:36:01 +010010246 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
Johannes Bergf62fab72013-02-21 20:09:09 +010010247 req.flags |= ASSOC_REQ_DISABLE_VHT;
Johannes Bergee2aca32013-02-21 17:36:01 +010010248
Ben Greearb6db0f82021-02-04 06:46:10 -080010249 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HE]))
10250 req.flags |= ASSOC_REQ_DISABLE_HE;
10251
Johannes Bergee2aca32013-02-21 17:36:01 +010010252 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +010010253 memcpy(&req.vht_capa_mask,
10254 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
10255 sizeof(req.vht_capa_mask));
Johannes Bergee2aca32013-02-21 17:36:01 +010010256
10257 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +010010258 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergee2aca32013-02-21 17:36:01 +010010259 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +010010260 memcpy(&req.vht_capa,
10261 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
10262 sizeof(req.vht_capa));
Johannes Bergee2aca32013-02-21 17:36:01 +010010263 }
10264
Assaf Kraussbab5ab72014-09-03 15:25:01 +030010265 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +020010266 if (!((rdev->wiphy.features &
10267 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
10268 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
10269 !wiphy_ext_feature_isset(&rdev->wiphy,
10270 NL80211_EXT_FEATURE_RRM))
Assaf Kraussbab5ab72014-09-03 15:25:01 +030010271 return -EINVAL;
10272 req.flags |= ASSOC_REQ_USE_RRM;
10273 }
10274
Jouni Malinen348bd452016-10-27 00:42:03 +030010275 if (info->attrs[NL80211_ATTR_FILS_KEK]) {
10276 req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
10277 req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
10278 if (!info->attrs[NL80211_ATTR_FILS_NONCES])
10279 return -EINVAL;
10280 req.fils_nonces =
10281 nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
10282 }
10283
Thomas Pedersend2b75882020-09-21 19:28:04 -070010284 if (info->attrs[NL80211_ATTR_S1G_CAPABILITY_MASK]) {
10285 if (!info->attrs[NL80211_ATTR_S1G_CAPABILITY])
10286 return -EINVAL;
10287 memcpy(&req.s1g_capa_mask,
10288 nla_data(info->attrs[NL80211_ATTR_S1G_CAPABILITY_MASK]),
10289 sizeof(req.s1g_capa_mask));
10290 }
10291
10292 if (info->attrs[NL80211_ATTR_S1G_CAPABILITY]) {
10293 if (!info->attrs[NL80211_ATTR_S1G_CAPABILITY_MASK])
10294 return -EINVAL;
10295 memcpy(&req.s1g_capa,
10296 nla_data(info->attrs[NL80211_ATTR_S1G_CAPABILITY]),
10297 sizeof(req.s1g_capa));
10298 }
10299
Johannes Bergf62fab72013-02-21 20:09:09 +010010300 err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
Johannes Berg91bf9b22013-05-15 17:44:01 +020010301 if (!err) {
10302 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050010303
Johannes Bergf62fab72013-02-21 20:09:09 +010010304 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
10305 ssid, ssid_len, &req);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050010306
10307 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
10308 dev->ieee80211_ptr->conn_owner_nlportid =
10309 info->snd_portid;
10310 memcpy(dev->ieee80211_ptr->disconnect_bssid,
10311 bssid, ETH_ALEN);
10312 }
10313
Johannes Berg91bf9b22013-05-15 17:44:01 +020010314 wdev_unlock(dev->ieee80211_ptr);
10315 }
Jouni Malinen636a5d32009-03-19 13:39:22 +020010316
Jouni Malinen636a5d32009-03-19 13:39:22 +020010317 return err;
10318}
10319
10320static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
10321{
Johannes Berg4c476992010-10-04 21:36:35 +020010322 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10323 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +020010324 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +020010325 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +020010326 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +030010327 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +020010328
Andrew Zaborowskibad29292018-05-22 02:46:02 +020010329 if (dev->ieee80211_ptr->conn_owner_nlportid &&
10330 dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
10331 return -EPERM;
10332
Johannes Bergf4a11bb2009-03-27 12:40:28 +010010333 if (!info->attrs[NL80211_ATTR_MAC])
10334 return -EINVAL;
10335
10336 if (!info->attrs[NL80211_ATTR_REASON_CODE])
10337 return -EINVAL;
10338
Johannes Berg4c476992010-10-04 21:36:35 +020010339 if (!rdev->ops->deauth)
10340 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +020010341
Johannes Berg074ac8d2010-09-16 14:58:22 +020010342 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020010343 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
10344 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +020010345
Johannes Berg19957bb2009-07-02 17:20:43 +020010346 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +020010347
Johannes Berg19957bb2009-07-02 17:20:43 +020010348 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
10349 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +010010350 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +020010351 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +020010352 }
Jouni Malinen636a5d32009-03-19 13:39:22 +020010353
10354 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +020010355 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
10356 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +020010357 }
10358
Jouni Malinend5cdfac2010-04-04 09:37:19 +030010359 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
10360
Johannes Berg91bf9b22013-05-15 17:44:01 +020010361 wdev_lock(dev->ieee80211_ptr);
10362 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
10363 local_state_change);
10364 wdev_unlock(dev->ieee80211_ptr);
10365 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +020010366}
10367
10368static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
10369{
Johannes Berg4c476992010-10-04 21:36:35 +020010370 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10371 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +020010372 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +020010373 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +020010374 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +030010375 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +020010376
Andrew Zaborowskibad29292018-05-22 02:46:02 +020010377 if (dev->ieee80211_ptr->conn_owner_nlportid &&
10378 dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
10379 return -EPERM;
10380
Johannes Bergf4a11bb2009-03-27 12:40:28 +010010381 if (!info->attrs[NL80211_ATTR_MAC])
10382 return -EINVAL;
10383
10384 if (!info->attrs[NL80211_ATTR_REASON_CODE])
10385 return -EINVAL;
10386
Johannes Berg4c476992010-10-04 21:36:35 +020010387 if (!rdev->ops->disassoc)
10388 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +020010389
Johannes Berg074ac8d2010-09-16 14:58:22 +020010390 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020010391 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
10392 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +020010393
Johannes Berg19957bb2009-07-02 17:20:43 +020010394 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +020010395
Johannes Berg19957bb2009-07-02 17:20:43 +020010396 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
10397 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +010010398 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +020010399 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +020010400 }
Jouni Malinen636a5d32009-03-19 13:39:22 +020010401
10402 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +020010403 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
10404 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +020010405 }
10406
Jouni Malinend5cdfac2010-04-04 09:37:19 +030010407 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
10408
Johannes Berg91bf9b22013-05-15 17:44:01 +020010409 wdev_lock(dev->ieee80211_ptr);
10410 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
10411 local_state_change);
10412 wdev_unlock(dev->ieee80211_ptr);
10413 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +020010414}
10415
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +010010416static bool
10417nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
Johannes Berg57fbcce2016-04-12 15:56:15 +020010418 int mcast_rate[NUM_NL80211_BANDS],
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +010010419 int rateval)
10420{
10421 struct wiphy *wiphy = &rdev->wiphy;
10422 bool found = false;
10423 int band, i;
10424
Johannes Berg57fbcce2016-04-12 15:56:15 +020010425 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +010010426 struct ieee80211_supported_band *sband;
10427
10428 sband = wiphy->bands[band];
10429 if (!sband)
10430 continue;
10431
10432 for (i = 0; i < sband->n_bitrates; i++) {
10433 if (sband->bitrates[i].bitrate == rateval) {
10434 mcast_rate[band] = i + 1;
10435 found = true;
10436 break;
10437 }
10438 }
10439 }
10440
10441 return found;
10442}
10443
Johannes Berg04a773a2009-04-19 21:24:32 +020010444static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
10445{
Johannes Berg4c476992010-10-04 21:36:35 +020010446 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10447 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +020010448 struct cfg80211_ibss_params ibss;
10449 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +020010450 struct cfg80211_cached_keys *connkeys = NULL;
Johannes Berg04a773a2009-04-19 21:24:32 +020010451 int err;
10452
Johannes Berg8e30bc52009-04-22 17:45:38 +020010453 memset(&ibss, 0, sizeof(ibss));
10454
Johannes Berg683b6d32012-11-08 21:25:48 +010010455 if (!info->attrs[NL80211_ATTR_SSID] ||
Johannes Berg04a773a2009-04-19 21:24:32 +020010456 !nla_len(info->attrs[NL80211_ATTR_SSID]))
10457 return -EINVAL;
10458
Johannes Berg8e30bc52009-04-22 17:45:38 +020010459 ibss.beacon_interval = 100;
10460
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053010461 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
Johannes Berg8e30bc52009-04-22 17:45:38 +020010462 ibss.beacon_interval =
10463 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053010464
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +053010465 err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
10466 ibss.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053010467 if (err)
10468 return err;
Johannes Berg8e30bc52009-04-22 17:45:38 +020010469
Johannes Berg4c476992010-10-04 21:36:35 +020010470 if (!rdev->ops->join_ibss)
10471 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +020010472
Johannes Berg4c476992010-10-04 21:36:35 +020010473 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
10474 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +020010475
Johannes Berg79c97e92009-07-07 03:56:12 +020010476 wiphy = &rdev->wiphy;
Johannes Berg04a773a2009-04-19 21:24:32 +020010477
Johannes Berg39193492011-09-16 13:45:25 +020010478 if (info->attrs[NL80211_ATTR_MAC]) {
Johannes Berg04a773a2009-04-19 21:24:32 +020010479 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg39193492011-09-16 13:45:25 +020010480
10481 if (!is_valid_ether_addr(ibss.bssid))
10482 return -EINVAL;
10483 }
Johannes Berg04a773a2009-04-19 21:24:32 +020010484 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
10485 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
10486
10487 if (info->attrs[NL80211_ATTR_IE]) {
10488 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
10489 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
10490 }
10491
Johannes Berg683b6d32012-11-08 21:25:48 +010010492 err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
10493 if (err)
10494 return err;
Alexander Simon54858ee5b2011-11-30 16:56:32 +010010495
Ilan Peer174e0cd2014-02-23 09:13:01 +020010496 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
10497 NL80211_IFTYPE_ADHOC))
Alexander Simon54858ee5b2011-11-30 16:56:32 +010010498 return -EINVAL;
10499
Simon Wunderlich2f301ab2013-05-16 13:00:28 +020010500 switch (ibss.chandef.width) {
Simon Wunderlichbf372642013-07-08 16:55:58 +020010501 case NL80211_CHAN_WIDTH_5:
10502 case NL80211_CHAN_WIDTH_10:
Simon Wunderlich2f301ab2013-05-16 13:00:28 +020010503 case NL80211_CHAN_WIDTH_20_NOHT:
10504 break;
10505 case NL80211_CHAN_WIDTH_20:
10506 case NL80211_CHAN_WIDTH_40:
Janusz.Dziedzic@tieto.comffc11992015-02-21 16:52:39 +010010507 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
10508 return -EINVAL;
10509 break;
10510 case NL80211_CHAN_WIDTH_80:
10511 case NL80211_CHAN_WIDTH_80P80:
10512 case NL80211_CHAN_WIDTH_160:
10513 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
10514 return -EINVAL;
10515 if (!wiphy_ext_feature_isset(&rdev->wiphy,
10516 NL80211_EXT_FEATURE_VHT_IBSS))
10517 return -EINVAL;
10518 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +020010519 default:
Johannes Bergdb9c64c2012-11-09 14:56:41 +010010520 return -EINVAL;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +020010521 }
Johannes Bergdb9c64c2012-11-09 14:56:41 +010010522
Johannes Berg04a773a2009-04-19 21:24:32 +020010523 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
Johannes Bergfffd0932009-07-08 14:22:54 +020010524 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
Johannes Berg04a773a2009-04-19 21:24:32 +020010525
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +030010526 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
10527 u8 *rates =
10528 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
10529 int n_rates =
10530 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
10531 struct ieee80211_supported_band *sband =
Johannes Berg683b6d32012-11-08 21:25:48 +010010532 wiphy->bands[ibss.chandef.chan->band];
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +030010533
Johannes Berg34850ab2011-07-18 18:08:35 +020010534 err = ieee80211_get_ratemask(sband, rates, n_rates,
10535 &ibss.basic_rates);
10536 if (err)
10537 return err;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +030010538 }
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +010010539
Simon Wunderlich803768f2013-06-28 10:39:58 +020010540 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
10541 memcpy(&ibss.ht_capa_mask,
10542 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
10543 sizeof(ibss.ht_capa_mask));
10544
10545 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
10546 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
10547 return -EINVAL;
10548 memcpy(&ibss.ht_capa,
10549 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
10550 sizeof(ibss.ht_capa));
10551 }
10552
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +010010553 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
10554 !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
10555 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
10556 return -EINVAL;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +030010557
Johannes Berg4c476992010-10-04 21:36:35 +020010558 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Sujith Manoharande7044e2012-10-18 10:19:28 +053010559 bool no_ht = false;
10560
Johannes Berg768075e2017-11-13 15:35:06 +010010561 connkeys = nl80211_parse_connkeys(rdev, info, &no_ht);
Johannes Berg4c476992010-10-04 21:36:35 +020010562 if (IS_ERR(connkeys))
10563 return PTR_ERR(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +053010564
Johannes Berg3d9d1d62012-11-08 23:14:50 +010010565 if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
10566 no_ht) {
Waiman Long453431a2020-08-06 23:18:13 -070010567 kfree_sensitive(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +053010568 return -EINVAL;
10569 }
Johannes Berg4c476992010-10-04 21:36:35 +020010570 }
Johannes Berg04a773a2009-04-19 21:24:32 +020010571
Antonio Quartulli267335d2012-01-31 20:25:47 +010010572 ibss.control_port =
10573 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
10574
Denis Kenziorc3bfe1f2018-03-26 12:52:48 -050010575 if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
10576 int r = validate_pae_over_nl80211(rdev, info);
10577
Johannes Bergd350a0f2018-12-15 11:03:22 +020010578 if (r < 0) {
Waiman Long453431a2020-08-06 23:18:13 -070010579 kfree_sensitive(connkeys);
Denis Kenziorc3bfe1f2018-03-26 12:52:48 -050010580 return r;
Johannes Bergd350a0f2018-12-15 11:03:22 +020010581 }
Denis Kenziorc3bfe1f2018-03-26 12:52:48 -050010582
10583 ibss.control_port_over_nl80211 = true;
10584 }
10585
Simon Wunderlich5336fa82013-10-07 18:41:05 +020010586 ibss.userspace_handles_dfs =
10587 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
10588
Denis Kenziorf8d16d32018-03-26 12:52:45 -050010589 wdev_lock(dev->ieee80211_ptr);
10590 err = __cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +020010591 if (err)
Waiman Long453431a2020-08-06 23:18:13 -070010592 kfree_sensitive(connkeys);
Denis Kenziorf8d16d32018-03-26 12:52:45 -050010593 else if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
10594 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
10595 wdev_unlock(dev->ieee80211_ptr);
10596
Johannes Berg04a773a2009-04-19 21:24:32 +020010597 return err;
10598}
10599
10600static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
10601{
Johannes Berg4c476992010-10-04 21:36:35 +020010602 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10603 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +020010604
Johannes Berg4c476992010-10-04 21:36:35 +020010605 if (!rdev->ops->leave_ibss)
10606 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +020010607
Johannes Berg4c476992010-10-04 21:36:35 +020010608 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
10609 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +020010610
Johannes Berg4c476992010-10-04 21:36:35 +020010611 return cfg80211_leave_ibss(rdev, dev, false);
Johannes Berg04a773a2009-04-19 21:24:32 +020010612}
10613
Antonio Quartullif4e583c2012-11-02 13:27:48 +010010614static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
10615{
10616 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10617 struct net_device *dev = info->user_ptr[1];
Johannes Berg57fbcce2016-04-12 15:56:15 +020010618 int mcast_rate[NUM_NL80211_BANDS];
Antonio Quartullif4e583c2012-11-02 13:27:48 +010010619 u32 nla_rate;
10620 int err;
10621
10622 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
Bertold Van den Bergh876dc932015-08-05 16:02:21 +020010623 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
10624 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
Antonio Quartullif4e583c2012-11-02 13:27:48 +010010625 return -EOPNOTSUPP;
10626
10627 if (!rdev->ops->set_mcast_rate)
10628 return -EOPNOTSUPP;
10629
10630 memset(mcast_rate, 0, sizeof(mcast_rate));
10631
10632 if (!info->attrs[NL80211_ATTR_MCAST_RATE])
10633 return -EINVAL;
10634
10635 nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
10636 if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
10637 return -EINVAL;
10638
Ilan Peera1056b1b2015-10-22 22:27:46 +030010639 err = rdev_set_mcast_rate(rdev, dev, mcast_rate);
Antonio Quartullif4e583c2012-11-02 13:27:48 +010010640
10641 return err;
10642}
10643
Johannes Bergad7e7182013-11-13 13:37:47 +010010644static struct sk_buff *
10645__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020010646 struct wireless_dev *wdev, int approxlen,
10647 u32 portid, u32 seq, enum nl80211_commands cmd,
Johannes Berg567ffc32013-12-18 14:43:31 +010010648 enum nl80211_attrs attr,
10649 const struct nl80211_vendor_cmd_info *info,
10650 gfp_t gfp)
Johannes Bergad7e7182013-11-13 13:37:47 +010010651{
10652 struct sk_buff *skb;
10653 void *hdr;
10654 struct nlattr *data;
10655
10656 skb = nlmsg_new(approxlen + 100, gfp);
10657 if (!skb)
10658 return NULL;
10659
10660 hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
10661 if (!hdr) {
10662 kfree_skb(skb);
10663 return NULL;
10664 }
10665
10666 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
10667 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +010010668
10669 if (info) {
10670 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
10671 info->vendor_id))
10672 goto nla_put_failure;
10673 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
10674 info->subcmd))
10675 goto nla_put_failure;
10676 }
10677
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020010678 if (wdev) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020010679 if (nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
10680 wdev_id(wdev), NL80211_ATTR_PAD))
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020010681 goto nla_put_failure;
10682 if (wdev->netdev &&
10683 nla_put_u32(skb, NL80211_ATTR_IFINDEX,
10684 wdev->netdev->ifindex))
10685 goto nla_put_failure;
10686 }
10687
Michal Kubecekae0be8d2019-04-26 11:13:06 +020010688 data = nla_nest_start_noflag(skb, attr);
Johannes Berg76e1fb42016-09-14 09:55:57 +020010689 if (!data)
10690 goto nla_put_failure;
Johannes Bergad7e7182013-11-13 13:37:47 +010010691
10692 ((void **)skb->cb)[0] = rdev;
10693 ((void **)skb->cb)[1] = hdr;
10694 ((void **)skb->cb)[2] = data;
10695
10696 return skb;
10697
10698 nla_put_failure:
10699 kfree_skb(skb);
10700 return NULL;
10701}
Antonio Quartullif4e583c2012-11-02 13:27:48 +010010702
Johannes Berge03ad6e2014-01-01 17:22:30 +010010703struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020010704 struct wireless_dev *wdev,
Johannes Berge03ad6e2014-01-01 17:22:30 +010010705 enum nl80211_commands cmd,
10706 enum nl80211_attrs attr,
Johannes Berg55c1fdf2019-02-06 13:17:19 +020010707 unsigned int portid,
Johannes Berge03ad6e2014-01-01 17:22:30 +010010708 int vendor_event_idx,
10709 int approxlen, gfp_t gfp)
10710{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080010711 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berge03ad6e2014-01-01 17:22:30 +010010712 const struct nl80211_vendor_cmd_info *info;
10713
10714 switch (cmd) {
10715 case NL80211_CMD_TESTMODE:
10716 if (WARN_ON(vendor_event_idx != -1))
10717 return NULL;
10718 info = NULL;
10719 break;
10720 case NL80211_CMD_VENDOR:
10721 if (WARN_ON(vendor_event_idx < 0 ||
10722 vendor_event_idx >= wiphy->n_vendor_events))
10723 return NULL;
10724 info = &wiphy->vendor_events[vendor_event_idx];
10725 break;
10726 default:
10727 WARN_ON(1);
10728 return NULL;
10729 }
10730
Johannes Berg55c1fdf2019-02-06 13:17:19 +020010731 return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, portid, 0,
Johannes Berge03ad6e2014-01-01 17:22:30 +010010732 cmd, attr, info, gfp);
10733}
10734EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
10735
10736void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
10737{
10738 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
10739 void *hdr = ((void **)skb->cb)[1];
Johannes Berg55c1fdf2019-02-06 13:17:19 +020010740 struct nlmsghdr *nlhdr = nlmsg_hdr(skb);
Johannes Berge03ad6e2014-01-01 17:22:30 +010010741 struct nlattr *data = ((void **)skb->cb)[2];
10742 enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
10743
Johannes Bergbd8c78e2014-07-30 14:55:26 +020010744 /* clear CB data for netlink core to own from now on */
10745 memset(skb->cb, 0, sizeof(skb->cb));
10746
Johannes Berge03ad6e2014-01-01 17:22:30 +010010747 nla_nest_end(skb, data);
10748 genlmsg_end(skb, hdr);
10749
Johannes Berg55c1fdf2019-02-06 13:17:19 +020010750 if (nlhdr->nlmsg_pid) {
10751 genlmsg_unicast(wiphy_net(&rdev->wiphy), skb,
10752 nlhdr->nlmsg_pid);
10753 } else {
10754 if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
10755 mcgrp = NL80211_MCGRP_VENDOR;
Johannes Berge03ad6e2014-01-01 17:22:30 +010010756
Johannes Berg55c1fdf2019-02-06 13:17:19 +020010757 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
10758 skb, 0, mcgrp, gfp);
10759 }
Johannes Berge03ad6e2014-01-01 17:22:30 +010010760}
10761EXPORT_SYMBOL(__cfg80211_send_event_skb);
10762
Johannes Bergaff89a92009-07-01 21:26:51 +020010763#ifdef CONFIG_NL80211_TESTMODE
Johannes Bergaff89a92009-07-01 21:26:51 +020010764static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
10765{
Johannes Berg4c476992010-10-04 21:36:35 +020010766 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berga05829a2021-01-22 16:19:43 +010010767 struct wireless_dev *wdev;
Johannes Bergaff89a92009-07-01 21:26:51 +020010768 int err;
10769
Johannes Berga05829a2021-01-22 16:19:43 +010010770 lockdep_assert_held(&rdev->wiphy.mtx);
10771
10772 wdev = __cfg80211_wdev_from_attrs(rdev, genl_info_net(info),
10773 info->attrs);
10774
David Spinadelfc73f112013-07-31 18:04:15 +030010775 if (!rdev->ops->testmode_cmd)
10776 return -EOPNOTSUPP;
10777
10778 if (IS_ERR(wdev)) {
10779 err = PTR_ERR(wdev);
10780 if (err != -EINVAL)
10781 return err;
10782 wdev = NULL;
10783 } else if (wdev->wiphy != &rdev->wiphy) {
10784 return -EINVAL;
10785 }
10786
Johannes Bergaff89a92009-07-01 21:26:51 +020010787 if (!info->attrs[NL80211_ATTR_TESTDATA])
10788 return -EINVAL;
10789
Johannes Bergad7e7182013-11-13 13:37:47 +010010790 rdev->cur_cmd_info = info;
David Spinadelfc73f112013-07-31 18:04:15 +030010791 err = rdev_testmode_cmd(rdev, wdev,
Johannes Bergaff89a92009-07-01 21:26:51 +020010792 nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
10793 nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
Johannes Bergad7e7182013-11-13 13:37:47 +010010794 rdev->cur_cmd_info = NULL;
Johannes Bergaff89a92009-07-01 21:26:51 +020010795
Johannes Bergaff89a92009-07-01 21:26:51 +020010796 return err;
10797}
10798
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010799static int nl80211_testmode_dump(struct sk_buff *skb,
10800 struct netlink_callback *cb)
10801{
Johannes Berg00918d32011-12-13 17:22:05 +010010802 struct cfg80211_registered_device *rdev;
Johannes Berg50508d92019-07-29 16:31:09 +020010803 struct nlattr **attrbuf = NULL;
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010804 int err;
10805 long phy_idx;
10806 void *data = NULL;
10807 int data_len = 0;
10808
Johannes Berg5fe231e2013-05-08 21:45:15 +020010809 rtnl_lock();
10810
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010811 if (cb->args[0]) {
10812 /*
10813 * 0 is a valid index, but not valid for args[0],
10814 * so we need to offset by 1.
10815 */
10816 phy_idx = cb->args[0] - 1;
Luca Coelhoa4956dc2017-02-07 22:13:56 +020010817
10818 rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
10819 if (!rdev) {
10820 err = -ENOENT;
10821 goto out_err;
10822 }
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010823 } else {
Johannes Berg50508d92019-07-29 16:31:09 +020010824 attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
10825 GFP_KERNEL);
10826 if (!attrbuf) {
10827 err = -ENOMEM;
10828 goto out_err;
10829 }
Johannes Bergc90c39d2016-10-24 14:40:01 +020010830
Johannes Berg8cb08172019-04-26 14:07:28 +020010831 err = nlmsg_parse_deprecated(cb->nlh,
10832 GENL_HDRLEN + nl80211_fam.hdrsize,
10833 attrbuf, nl80211_fam.maxattr,
10834 nl80211_policy, NULL);
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010835 if (err)
Johannes Berg5fe231e2013-05-08 21:45:15 +020010836 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +010010837
Johannes Bergc90c39d2016-10-24 14:40:01 +020010838 rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg2bd7e352012-06-15 14:23:16 +020010839 if (IS_ERR(rdev)) {
Johannes Berg5fe231e2013-05-08 21:45:15 +020010840 err = PTR_ERR(rdev);
10841 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +010010842 }
Johannes Berg2bd7e352012-06-15 14:23:16 +020010843 phy_idx = rdev->wiphy_idx;
Johannes Berg2bd7e352012-06-15 14:23:16 +020010844
Johannes Bergc90c39d2016-10-24 14:40:01 +020010845 if (attrbuf[NL80211_ATTR_TESTDATA])
10846 cb->args[1] = (long)attrbuf[NL80211_ATTR_TESTDATA];
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010847 }
10848
10849 if (cb->args[1]) {
10850 data = nla_data((void *)cb->args[1]);
10851 data_len = nla_len((void *)cb->args[1]);
10852 }
10853
Johannes Berg00918d32011-12-13 17:22:05 +010010854 if (!rdev->ops->testmode_dump) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010855 err = -EOPNOTSUPP;
10856 goto out_err;
10857 }
10858
10859 while (1) {
Eric W. Biederman15e47302012-09-07 20:12:54 +000010860 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010861 cb->nlh->nlmsg_seq, NLM_F_MULTI,
10862 NL80211_CMD_TESTMODE);
10863 struct nlattr *tmdata;
10864
Dan Carpentercb35fba2013-08-14 14:50:01 +030010865 if (!hdr)
10866 break;
10867
David S. Miller9360ffd2012-03-29 04:41:26 -040010868 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010869 genlmsg_cancel(skb, hdr);
10870 break;
10871 }
10872
Michal Kubecekae0be8d2019-04-26 11:13:06 +020010873 tmdata = nla_nest_start_noflag(skb, NL80211_ATTR_TESTDATA);
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010874 if (!tmdata) {
10875 genlmsg_cancel(skb, hdr);
10876 break;
10877 }
Hila Gonene35e4d22012-06-27 17:19:42 +030010878 err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010879 nla_nest_end(skb, tmdata);
10880
10881 if (err == -ENOBUFS || err == -ENOENT) {
10882 genlmsg_cancel(skb, hdr);
10883 break;
10884 } else if (err) {
10885 genlmsg_cancel(skb, hdr);
10886 goto out_err;
10887 }
10888
10889 genlmsg_end(skb, hdr);
10890 }
10891
10892 err = skb->len;
10893 /* see above */
10894 cb->args[0] = phy_idx + 1;
10895 out_err:
Johannes Berg50508d92019-07-29 16:31:09 +020010896 kfree(attrbuf);
Johannes Berg5fe231e2013-05-08 21:45:15 +020010897 rtnl_unlock();
Wey-Yi Guy71063f02011-05-20 09:05:54 -070010898 return err;
10899}
Johannes Bergaff89a92009-07-01 21:26:51 +020010900#endif
10901
Samuel Ortizb23aa672009-07-01 21:26:54 +020010902static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
10903{
Johannes Berg4c476992010-10-04 21:36:35 +020010904 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10905 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +020010906 struct cfg80211_connect_params connect;
10907 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +020010908 struct cfg80211_cached_keys *connkeys = NULL;
Thomas Pedersen942ba882020-04-30 10:25:51 -070010909 u32 freq = 0;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010910 int err;
10911
10912 memset(&connect, 0, sizeof(connect));
10913
Samuel Ortizb23aa672009-07-01 21:26:54 +020010914 if (!info->attrs[NL80211_ATTR_SSID] ||
10915 !nla_len(info->attrs[NL80211_ATTR_SSID]))
10916 return -EINVAL;
10917
10918 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
10919 connect.auth_type =
10920 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +030010921 if (!nl80211_valid_auth_type(rdev, connect.auth_type,
10922 NL80211_CMD_CONNECT))
Samuel Ortizb23aa672009-07-01 21:26:54 +020010923 return -EINVAL;
10924 } else
10925 connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
10926
10927 connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
10928
Avraham Stern3a00df52017-06-09 13:08:43 +010010929 if (info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS] &&
10930 !wiphy_ext_feature_isset(&rdev->wiphy,
10931 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
10932 return -EINVAL;
10933 connect.want_1x = info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS];
10934
Johannes Bergc0692b82010-08-27 14:26:53 +030010935 err = nl80211_crypto_settings(rdev, info, &connect.crypto,
Johannes Berg3dc27d22009-07-02 21:36:37 +020010936 NL80211_MAX_NR_CIPHER_SUITES);
Samuel Ortizb23aa672009-07-01 21:26:54 +020010937 if (err)
10938 return err;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010939
Johannes Berg074ac8d2010-09-16 14:58:22 +020010940 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020010941 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
10942 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010943
Johannes Berg79c97e92009-07-07 03:56:12 +020010944 wiphy = &rdev->wiphy;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010945
Bala Shanmugam4486ea92012-03-07 17:27:12 +053010946 connect.bg_scan_period = -1;
10947 if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
10948 (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
10949 connect.bg_scan_period =
10950 nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
10951 }
10952
Samuel Ortizb23aa672009-07-01 21:26:54 +020010953 if (info->attrs[NL80211_ATTR_MAC])
10954 connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen1df4a512014-01-15 00:00:47 +020010955 else if (info->attrs[NL80211_ATTR_MAC_HINT])
10956 connect.bssid_hint =
10957 nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
Samuel Ortizb23aa672009-07-01 21:26:54 +020010958 connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
10959 connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
10960
10961 if (info->attrs[NL80211_ATTR_IE]) {
10962 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
10963 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
10964 }
10965
Jouni Malinencee00a92013-01-15 17:15:57 +020010966 if (info->attrs[NL80211_ATTR_USE_MFP]) {
10967 connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Emmanuel Grumbach65026002017-08-18 15:31:41 +030010968 if (connect.mfp == NL80211_MFP_OPTIONAL &&
10969 !wiphy_ext_feature_isset(&rdev->wiphy,
10970 NL80211_EXT_FEATURE_MFP_OPTIONAL))
10971 return -EOPNOTSUPP;
Jouni Malinencee00a92013-01-15 17:15:57 +020010972 } else {
10973 connect.mfp = NL80211_MFP_NO;
10974 }
10975
Jouni Malinenba6fbac2016-03-29 13:53:27 +030010976 if (info->attrs[NL80211_ATTR_PREV_BSSID])
10977 connect.prev_bssid =
10978 nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
10979
Thomas Pedersen942ba882020-04-30 10:25:51 -070010980 if (info->attrs[NL80211_ATTR_WIPHY_FREQ])
10981 freq = MHZ_TO_KHZ(nla_get_u32(
10982 info->attrs[NL80211_ATTR_WIPHY_FREQ]));
10983 if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
10984 freq +=
10985 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
10986
10987 if (freq) {
10988 connect.channel = nl80211_get_valid_chan(wiphy, freq);
Jouni Malinen664834d2014-01-15 00:01:44 +020010989 if (!connect.channel)
Johannes Berg4c476992010-10-04 21:36:35 +020010990 return -EINVAL;
Jouni Malinen1df4a512014-01-15 00:00:47 +020010991 } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
Thomas Pedersen942ba882020-04-30 10:25:51 -070010992 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
10993 freq = MHZ_TO_KHZ(freq);
10994 connect.channel_hint = nl80211_get_valid_chan(wiphy, freq);
Jouni Malinen664834d2014-01-15 00:01:44 +020010995 if (!connect.channel_hint)
Jouni Malinen1df4a512014-01-15 00:00:47 +020010996 return -EINVAL;
Samuel Ortizb23aa672009-07-01 21:26:54 +020010997 }
10998
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030010999 if (info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]) {
11000 connect.edmg.channels =
11001 nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]);
11002
11003 if (info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG])
11004 connect.edmg.bw_config =
11005 nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG]);
11006 }
11007
Johannes Bergfffd0932009-07-08 14:22:54 +020011008 if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Johannes Berg768075e2017-11-13 15:35:06 +010011009 connkeys = nl80211_parse_connkeys(rdev, info, NULL);
Johannes Berg4c476992010-10-04 21:36:35 +020011010 if (IS_ERR(connkeys))
11011 return PTR_ERR(connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +020011012 }
11013
Ben Greear7e7c8922011-11-18 11:31:59 -080011014 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
11015 connect.flags |= ASSOC_REQ_DISABLE_HT;
11016
11017 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
11018 memcpy(&connect.ht_capa_mask,
11019 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
11020 sizeof(connect.ht_capa_mask));
11021
11022 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Wei Yongjunb4e4f472012-09-02 21:41:04 +080011023 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
Waiman Long453431a2020-08-06 23:18:13 -070011024 kfree_sensitive(connkeys);
Ben Greear7e7c8922011-11-18 11:31:59 -080011025 return -EINVAL;
Wei Yongjunb4e4f472012-09-02 21:41:04 +080011026 }
Ben Greear7e7c8922011-11-18 11:31:59 -080011027 memcpy(&connect.ht_capa,
11028 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
11029 sizeof(connect.ht_capa));
11030 }
11031
Johannes Bergee2aca32013-02-21 17:36:01 +010011032 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
11033 connect.flags |= ASSOC_REQ_DISABLE_VHT;
11034
Ben Greearb6db0f82021-02-04 06:46:10 -080011035 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HE]))
11036 connect.flags |= ASSOC_REQ_DISABLE_HE;
11037
Johannes Bergee2aca32013-02-21 17:36:01 +010011038 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
11039 memcpy(&connect.vht_capa_mask,
11040 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
11041 sizeof(connect.vht_capa_mask));
11042
11043 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
11044 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
Waiman Long453431a2020-08-06 23:18:13 -070011045 kfree_sensitive(connkeys);
Johannes Bergee2aca32013-02-21 17:36:01 +010011046 return -EINVAL;
11047 }
11048 memcpy(&connect.vht_capa,
11049 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
11050 sizeof(connect.vht_capa));
11051 }
11052
Assaf Kraussbab5ab72014-09-03 15:25:01 +030011053 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +020011054 if (!((rdev->wiphy.features &
11055 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
11056 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
11057 !wiphy_ext_feature_isset(&rdev->wiphy,
11058 NL80211_EXT_FEATURE_RRM)) {
Waiman Long453431a2020-08-06 23:18:13 -070011059 kfree_sensitive(connkeys);
Assaf Kraussbab5ab72014-09-03 15:25:01 +030011060 return -EINVAL;
Ola Olsson707554b2015-12-11 21:04:52 +010011061 }
Assaf Kraussbab5ab72014-09-03 15:25:01 +030011062 connect.flags |= ASSOC_REQ_USE_RRM;
11063 }
11064
Lior David34d50512016-01-28 10:58:25 +020011065 connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
Johannes Berg57fbcce2016-04-12 15:56:15 +020011066 if (connect.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
Waiman Long453431a2020-08-06 23:18:13 -070011067 kfree_sensitive(connkeys);
Lior David34d50512016-01-28 10:58:25 +020011068 return -EOPNOTSUPP;
11069 }
11070
Arend van Spriel38de03d2016-03-02 20:37:18 +010011071 if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
11072 /* bss selection makes no sense if bssid is set */
11073 if (connect.bssid) {
Waiman Long453431a2020-08-06 23:18:13 -070011074 kfree_sensitive(connkeys);
Arend van Spriel38de03d2016-03-02 20:37:18 +010011075 return -EINVAL;
11076 }
11077
11078 err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
11079 wiphy, &connect.bss_select);
11080 if (err) {
Waiman Long453431a2020-08-06 23:18:13 -070011081 kfree_sensitive(connkeys);
Arend van Spriel38de03d2016-03-02 20:37:18 +010011082 return err;
11083 }
11084 }
11085
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030011086 if (wiphy_ext_feature_isset(&rdev->wiphy,
11087 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
11088 info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
11089 info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
11090 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
11091 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
11092 connect.fils_erp_username =
11093 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
11094 connect.fils_erp_username_len =
11095 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
11096 connect.fils_erp_realm =
11097 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
11098 connect.fils_erp_realm_len =
11099 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
11100 connect.fils_erp_next_seq_num =
11101 nla_get_u16(
11102 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
11103 connect.fils_erp_rrk =
11104 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
11105 connect.fils_erp_rrk_len =
11106 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
11107 } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
11108 info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
11109 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
11110 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
Waiman Long453431a2020-08-06 23:18:13 -070011111 kfree_sensitive(connkeys);
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030011112 return -EINVAL;
11113 }
11114
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020011115 if (nla_get_flag(info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])) {
11116 if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
Waiman Long453431a2020-08-06 23:18:13 -070011117 kfree_sensitive(connkeys);
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020011118 GENL_SET_ERR_MSG(info,
11119 "external auth requires connection ownership");
11120 return -EINVAL;
11121 }
11122 connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT;
11123 }
11124
Johannes Berg83739b02013-05-15 17:44:01 +020011125 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050011126
Jouni Malinen4ce2bd92016-03-29 13:53:28 +030011127 err = cfg80211_connect(rdev, dev, &connect, connkeys,
11128 connect.prev_bssid);
Johannes Bergfffd0932009-07-08 14:22:54 +020011129 if (err)
Waiman Long453431a2020-08-06 23:18:13 -070011130 kfree_sensitive(connkeys);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050011131
11132 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
11133 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
11134 if (connect.bssid)
11135 memcpy(dev->ieee80211_ptr->disconnect_bssid,
11136 connect.bssid, ETH_ALEN);
11137 else
Miaohe Lin3b1648f2020-08-01 17:15:49 +080011138 eth_zero_addr(dev->ieee80211_ptr->disconnect_bssid);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050011139 }
11140
11141 wdev_unlock(dev->ieee80211_ptr);
11142
Samuel Ortizb23aa672009-07-01 21:26:54 +020011143 return err;
11144}
11145
vamsi krishna088e8df2016-10-27 16:51:11 +030011146static int nl80211_update_connect_params(struct sk_buff *skb,
11147 struct genl_info *info)
11148{
11149 struct cfg80211_connect_params connect = {};
11150 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11151 struct net_device *dev = info->user_ptr[1];
11152 struct wireless_dev *wdev = dev->ieee80211_ptr;
Vidyullatha Kanchanapally7f9a3e12018-05-22 10:19:08 +020011153 bool fils_sk_offload;
11154 u32 auth_type;
vamsi krishna088e8df2016-10-27 16:51:11 +030011155 u32 changed = 0;
11156 int ret;
11157
11158 if (!rdev->ops->update_connect_params)
11159 return -EOPNOTSUPP;
11160
11161 if (info->attrs[NL80211_ATTR_IE]) {
vamsi krishna088e8df2016-10-27 16:51:11 +030011162 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
11163 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
11164 changed |= UPDATE_ASSOC_IES;
11165 }
11166
Vidyullatha Kanchanapally7f9a3e12018-05-22 10:19:08 +020011167 fils_sk_offload = wiphy_ext_feature_isset(&rdev->wiphy,
11168 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
11169
11170 /*
11171 * when driver supports fils-sk offload all attributes must be
11172 * provided. So the else covers "fils-sk-not-all" and
11173 * "no-fils-sk-any".
11174 */
11175 if (fils_sk_offload &&
11176 info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
11177 info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
11178 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
11179 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
11180 connect.fils_erp_username =
11181 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
11182 connect.fils_erp_username_len =
11183 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
11184 connect.fils_erp_realm =
11185 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
11186 connect.fils_erp_realm_len =
11187 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
11188 connect.fils_erp_next_seq_num =
11189 nla_get_u16(
11190 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
11191 connect.fils_erp_rrk =
11192 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
11193 connect.fils_erp_rrk_len =
11194 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
11195 changed |= UPDATE_FILS_ERP_INFO;
11196 } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
11197 info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
11198 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
11199 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
11200 return -EINVAL;
11201 }
11202
11203 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
11204 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
11205 if (!nl80211_valid_auth_type(rdev, auth_type,
11206 NL80211_CMD_CONNECT))
11207 return -EINVAL;
11208
11209 if (auth_type == NL80211_AUTHTYPE_FILS_SK &&
11210 fils_sk_offload && !(changed & UPDATE_FILS_ERP_INFO))
11211 return -EINVAL;
11212
11213 connect.auth_type = auth_type;
11214 changed |= UPDATE_AUTH_TYPE;
11215 }
11216
vamsi krishna088e8df2016-10-27 16:51:11 +030011217 wdev_lock(dev->ieee80211_ptr);
11218 if (!wdev->current_bss)
11219 ret = -ENOLINK;
11220 else
11221 ret = rdev_update_connect_params(rdev, dev, &connect, changed);
11222 wdev_unlock(dev->ieee80211_ptr);
11223
11224 return ret;
11225}
11226
Samuel Ortizb23aa672009-07-01 21:26:54 +020011227static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
11228{
Johannes Berg4c476992010-10-04 21:36:35 +020011229 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11230 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +020011231 u16 reason;
Johannes Berg83739b02013-05-15 17:44:01 +020011232 int ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +020011233
Andrew Zaborowskibad29292018-05-22 02:46:02 +020011234 if (dev->ieee80211_ptr->conn_owner_nlportid &&
11235 dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
11236 return -EPERM;
11237
Samuel Ortizb23aa672009-07-01 21:26:54 +020011238 if (!info->attrs[NL80211_ATTR_REASON_CODE])
11239 reason = WLAN_REASON_DEAUTH_LEAVING;
11240 else
11241 reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
11242
11243 if (reason == 0)
11244 return -EINVAL;
11245
Johannes Berg074ac8d2010-09-16 14:58:22 +020011246 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020011247 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
11248 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +020011249
Johannes Berg83739b02013-05-15 17:44:01 +020011250 wdev_lock(dev->ieee80211_ptr);
11251 ret = cfg80211_disconnect(rdev, dev, reason, true);
11252 wdev_unlock(dev->ieee80211_ptr);
11253 return ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +020011254}
11255
Johannes Berg463d0182009-07-14 00:33:35 +020011256static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
11257{
Johannes Berg4c476992010-10-04 21:36:35 +020011258 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg463d0182009-07-14 00:33:35 +020011259 struct net *net;
11260 int err;
Johannes Berg463d0182009-07-14 00:33:35 +020011261
Vadim Kochan4b681c82015-01-12 16:34:05 +020011262 if (info->attrs[NL80211_ATTR_PID]) {
11263 u32 pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
11264
11265 net = get_net_ns_by_pid(pid);
11266 } else if (info->attrs[NL80211_ATTR_NETNS_FD]) {
11267 u32 fd = nla_get_u32(info->attrs[NL80211_ATTR_NETNS_FD]);
11268
11269 net = get_net_ns_by_fd(fd);
11270 } else {
Johannes Berg463d0182009-07-14 00:33:35 +020011271 return -EINVAL;
Vadim Kochan4b681c82015-01-12 16:34:05 +020011272 }
Johannes Berg463d0182009-07-14 00:33:35 +020011273
Johannes Berg4c476992010-10-04 21:36:35 +020011274 if (IS_ERR(net))
11275 return PTR_ERR(net);
Johannes Berg463d0182009-07-14 00:33:35 +020011276
11277 err = 0;
11278
11279 /* check if anything to do */
Johannes Berg4c476992010-10-04 21:36:35 +020011280 if (!net_eq(wiphy_net(&rdev->wiphy), net))
11281 err = cfg80211_switch_netns(rdev, net);
Johannes Berg463d0182009-07-14 00:33:35 +020011282
Johannes Berg463d0182009-07-14 00:33:35 +020011283 put_net(net);
Johannes Berg463d0182009-07-14 00:33:35 +020011284 return err;
11285}
11286
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011287static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
11288{
Johannes Berg4c476992010-10-04 21:36:35 +020011289 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011290 int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
11291 struct cfg80211_pmksa *pmksa) = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +020011292 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011293 struct cfg80211_pmksa pmksa;
11294
11295 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
11296
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011297 if (!info->attrs[NL80211_ATTR_PMKID])
11298 return -EINVAL;
11299
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011300 pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030011301
11302 if (info->attrs[NL80211_ATTR_MAC]) {
11303 pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
11304 } else if (info->attrs[NL80211_ATTR_SSID] &&
11305 info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
11306 (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
11307 info->attrs[NL80211_ATTR_PMK])) {
11308 pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
11309 pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
11310 pmksa.cache_id =
11311 nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
11312 } else {
11313 return -EINVAL;
11314 }
11315 if (info->attrs[NL80211_ATTR_PMK]) {
11316 pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
11317 pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
11318 }
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011319
Veerendranath Jakkam7fc82af2020-03-13 01:59:03 +020011320 if (info->attrs[NL80211_ATTR_PMK_LIFETIME])
11321 pmksa.pmk_lifetime =
11322 nla_get_u32(info->attrs[NL80211_ATTR_PMK_LIFETIME]);
11323
11324 if (info->attrs[NL80211_ATTR_PMK_REAUTH_THRESHOLD])
11325 pmksa.pmk_reauth_threshold =
11326 nla_get_u8(
11327 info->attrs[NL80211_ATTR_PMK_REAUTH_THRESHOLD]);
11328
Johannes Berg074ac8d2010-09-16 14:58:22 +020011329 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Liangwei Dong6c900362019-01-18 16:54:38 +053011330 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
11331 !(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP &&
11332 wiphy_ext_feature_isset(&rdev->wiphy,
11333 NL80211_EXT_FEATURE_AP_PMKSA_CACHING)))
Johannes Berg4c476992010-10-04 21:36:35 +020011334 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011335
11336 switch (info->genlhdr->cmd) {
11337 case NL80211_CMD_SET_PMKSA:
11338 rdev_ops = rdev->ops->set_pmksa;
11339 break;
11340 case NL80211_CMD_DEL_PMKSA:
11341 rdev_ops = rdev->ops->del_pmksa;
11342 break;
11343 default:
11344 WARN_ON(1);
11345 break;
11346 }
11347
Johannes Berg4c476992010-10-04 21:36:35 +020011348 if (!rdev_ops)
11349 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011350
Johannes Berg4c476992010-10-04 21:36:35 +020011351 return rdev_ops(&rdev->wiphy, dev, &pmksa);
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011352}
11353
11354static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
11355{
Johannes Berg4c476992010-10-04 21:36:35 +020011356 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11357 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011358
Johannes Berg074ac8d2010-09-16 14:58:22 +020011359 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020011360 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
11361 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011362
Johannes Berg4c476992010-10-04 21:36:35 +020011363 if (!rdev->ops->flush_pmksa)
11364 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011365
Hila Gonene35e4d22012-06-27 17:19:42 +030011366 return rdev_flush_pmksa(rdev, dev);
Samuel Ortiz67fbb162009-11-24 23:59:15 +010011367}
11368
Arik Nemtsov109086c2011-09-28 14:12:50 +030011369static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
11370{
11371 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11372 struct net_device *dev = info->user_ptr[1];
11373 u8 action_code, dialog_token;
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +053011374 u32 peer_capability = 0;
Arik Nemtsov109086c2011-09-28 14:12:50 +030011375 u16 status_code;
11376 u8 *peer;
Arik Nemtsov31fa97c2014-06-11 17:18:21 +030011377 bool initiator;
Arik Nemtsov109086c2011-09-28 14:12:50 +030011378
11379 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
11380 !rdev->ops->tdls_mgmt)
11381 return -EOPNOTSUPP;
11382
11383 if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
11384 !info->attrs[NL80211_ATTR_STATUS_CODE] ||
11385 !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
11386 !info->attrs[NL80211_ATTR_IE] ||
11387 !info->attrs[NL80211_ATTR_MAC])
11388 return -EINVAL;
11389
11390 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
11391 action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
11392 status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
11393 dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
Arik Nemtsov31fa97c2014-06-11 17:18:21 +030011394 initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]);
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +053011395 if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
11396 peer_capability =
11397 nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
Arik Nemtsov109086c2011-09-28 14:12:50 +030011398
Hila Gonene35e4d22012-06-27 17:19:42 +030011399 return rdev_tdls_mgmt(rdev, dev, peer, action_code,
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +053011400 dialog_token, status_code, peer_capability,
Arik Nemtsov31fa97c2014-06-11 17:18:21 +030011401 initiator,
Hila Gonene35e4d22012-06-27 17:19:42 +030011402 nla_data(info->attrs[NL80211_ATTR_IE]),
11403 nla_len(info->attrs[NL80211_ATTR_IE]));
Arik Nemtsov109086c2011-09-28 14:12:50 +030011404}
11405
11406static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
11407{
11408 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11409 struct net_device *dev = info->user_ptr[1];
11410 enum nl80211_tdls_operation operation;
11411 u8 *peer;
11412
11413 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
11414 !rdev->ops->tdls_oper)
11415 return -EOPNOTSUPP;
11416
11417 if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
11418 !info->attrs[NL80211_ATTR_MAC])
11419 return -EINVAL;
11420
11421 operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
11422 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
11423
Hila Gonene35e4d22012-06-27 17:19:42 +030011424 return rdev_tdls_oper(rdev, dev, peer, operation);
Arik Nemtsov109086c2011-09-28 14:12:50 +030011425}
11426
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011427static int nl80211_remain_on_channel(struct sk_buff *skb,
11428 struct genl_info *info)
11429{
Johannes Berg4c476992010-10-04 21:36:35 +020011430 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +020011431 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +010011432 struct cfg80211_chan_def chandef;
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +053011433 const struct cfg80211_chan_def *compat_chandef;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011434 struct sk_buff *msg;
11435 void *hdr;
11436 u64 cookie;
Johannes Berg683b6d32012-11-08 21:25:48 +010011437 u32 duration;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011438 int err;
11439
11440 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
11441 !info->attrs[NL80211_ATTR_DURATION])
11442 return -EINVAL;
11443
11444 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
11445
Johannes Berg7c4ef712011-11-18 15:33:48 +010011446 if (!rdev->ops->remain_on_channel ||
11447 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
Johannes Berg4c476992010-10-04 21:36:35 +020011448 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011449
Johannes Bergebf348f2012-06-01 12:50:54 +020011450 /*
11451 * We should be on that channel for at least a minimum amount of
11452 * time (10ms) but no longer than the driver supports.
11453 */
11454 if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
11455 duration > rdev->wiphy.max_remain_on_channel_duration)
11456 return -EINVAL;
11457
Johannes Berg683b6d32012-11-08 21:25:48 +010011458 err = nl80211_parse_chandef(rdev, info, &chandef);
11459 if (err)
11460 return err;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011461
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +053011462 wdev_lock(wdev);
11463 if (!cfg80211_off_channel_oper_allowed(wdev) &&
11464 !cfg80211_chandef_identical(&wdev->chandef, &chandef)) {
11465 compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
11466 &chandef);
11467 if (compat_chandef != &chandef) {
11468 wdev_unlock(wdev);
11469 return -EBUSY;
11470 }
11471 }
11472 wdev_unlock(wdev);
11473
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011474 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +020011475 if (!msg)
11476 return -ENOMEM;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011477
Eric W. Biederman15e47302012-09-07 20:12:54 +000011478 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011479 NL80211_CMD_REMAIN_ON_CHANNEL);
Dan Carpentercb35fba2013-08-14 14:50:01 +030011480 if (!hdr) {
11481 err = -ENOBUFS;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011482 goto free_msg;
11483 }
11484
Johannes Berg683b6d32012-11-08 21:25:48 +010011485 err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
11486 duration, &cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011487
11488 if (err)
11489 goto free_msg;
11490
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020011491 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
11492 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040011493 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011494
11495 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +020011496
11497 return genlmsg_reply(msg, info);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011498
11499 nla_put_failure:
11500 err = -ENOBUFS;
11501 free_msg:
11502 nlmsg_free(msg);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011503 return err;
11504}
11505
11506static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
11507 struct genl_info *info)
11508{
Johannes Berg4c476992010-10-04 21:36:35 +020011509 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +020011510 struct wireless_dev *wdev = info->user_ptr[1];
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011511 u64 cookie;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011512
11513 if (!info->attrs[NL80211_ATTR_COOKIE])
11514 return -EINVAL;
11515
Johannes Berg4c476992010-10-04 21:36:35 +020011516 if (!rdev->ops->cancel_remain_on_channel)
11517 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011518
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011519 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
11520
Hila Gonene35e4d22012-06-27 17:19:42 +030011521 return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010011522}
11523
Jouni Malinen13ae75b2009-12-29 12:59:45 +020011524static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
11525 struct genl_info *info)
11526{
Jouni Malinen13ae75b2009-12-29 12:59:45 +020011527 struct cfg80211_bitrate_mask mask;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +053011528 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +020011529 struct net_device *dev = info->user_ptr[1];
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +053011530 int err;
Jouni Malinen13ae75b2009-12-29 12:59:45 +020011531
Johannes Berg4c476992010-10-04 21:36:35 +020011532 if (!rdev->ops->set_bitrate_mask)
11533 return -EOPNOTSUPP;
Jouni Malinen13ae75b2009-12-29 12:59:45 +020011534
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +053011535 err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
Miles Hueb89a6a2020-08-04 10:16:29 +020011536 NL80211_ATTR_TX_RATES, &mask,
Rajkumar Manoharan857b34c2020-10-16 13:15:26 -070011537 dev, true);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +053011538 if (err)
11539 return err;
Janusz Dziedzic78693032013-12-03 09:50:44 +010011540
Hila Gonene35e4d22012-06-27 17:19:42 +030011541 return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
Jouni Malinen13ae75b2009-12-29 12:59:45 +020011542}
11543
Johannes Berg2e161f782010-08-12 15:38:38 +020011544static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +020011545{
Johannes Berg4c476992010-10-04 21:36:35 +020011546 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +020011547 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2e161f782010-08-12 15:38:38 +020011548 u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
Jouni Malinen026331c2010-02-15 12:53:10 +020011549
11550 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
11551 return -EINVAL;
11552
Johannes Berg2e161f782010-08-12 15:38:38 +020011553 if (info->attrs[NL80211_ATTR_FRAME_TYPE])
11554 frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
Jouni Malinen026331c2010-02-15 12:53:10 +020011555
Johannes Berg71bbc992012-06-15 15:30:18 +020011556 switch (wdev->iftype) {
11557 case NL80211_IFTYPE_STATION:
11558 case NL80211_IFTYPE_ADHOC:
11559 case NL80211_IFTYPE_P2P_CLIENT:
11560 case NL80211_IFTYPE_AP:
11561 case NL80211_IFTYPE_AP_VLAN:
11562 case NL80211_IFTYPE_MESH_POINT:
11563 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +020011564 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +020011565 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011566 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +020011567 default:
Johannes Berg4c476992010-10-04 21:36:35 +020011568 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +020011569 }
Jouni Malinen026331c2010-02-15 12:53:10 +020011570
11571 /* not much point in registering if we can't reply */
Johannes Berg4c476992010-10-04 21:36:35 +020011572 if (!rdev->ops->mgmt_tx)
11573 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +020011574
Johannes Berg9dba48a2020-04-17 12:40:15 +020011575 if (info->attrs[NL80211_ATTR_RECEIVE_MULTICAST] &&
11576 !wiphy_ext_feature_isset(&rdev->wiphy,
11577 NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS)) {
11578 GENL_SET_ERR_MSG(info,
11579 "multicast RX registrations are not supported");
11580 return -EOPNOTSUPP;
11581 }
11582
Eric W. Biederman15e47302012-09-07 20:12:54 +000011583 return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
Ilan Peerff74c512020-01-31 13:45:29 +020011584 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
11585 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]),
Johannes Berg9dba48a2020-04-17 12:40:15 +020011586 info->attrs[NL80211_ATTR_RECEIVE_MULTICAST],
Ilan Peerff74c512020-01-31 13:45:29 +020011587 info->extack);
Jouni Malinen026331c2010-02-15 12:53:10 +020011588}
11589
Johannes Berg2e161f782010-08-12 15:38:38 +020011590static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +020011591{
Johannes Berg4c476992010-10-04 21:36:35 +020011592 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +020011593 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +010011594 struct cfg80211_chan_def chandef;
Jouni Malinen026331c2010-02-15 12:53:10 +020011595 int err;
Johannes Bergd64d3732011-11-10 09:44:46 +010011596 void *hdr = NULL;
Jouni Malinen026331c2010-02-15 12:53:10 +020011597 u64 cookie;
Johannes Berge247bd902011-11-04 11:18:21 +010011598 struct sk_buff *msg = NULL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020011599 struct cfg80211_mgmt_tx_params params = {
11600 .dont_wait_for_ack =
11601 info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
11602 };
Jouni Malinen026331c2010-02-15 12:53:10 +020011603
Johannes Berg683b6d32012-11-08 21:25:48 +010011604 if (!info->attrs[NL80211_ATTR_FRAME])
Jouni Malinen026331c2010-02-15 12:53:10 +020011605 return -EINVAL;
11606
Johannes Berg4c476992010-10-04 21:36:35 +020011607 if (!rdev->ops->mgmt_tx)
11608 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +020011609
Johannes Berg71bbc992012-06-15 15:30:18 +020011610 switch (wdev->iftype) {
Antonio Quartulliea141b752013-06-11 14:20:03 +020011611 case NL80211_IFTYPE_P2P_DEVICE:
11612 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
11613 return -EINVAL;
Gustavo A. R. Silvad7832c72020-11-20 12:38:37 -060011614 break;
Johannes Berg71bbc992012-06-15 15:30:18 +020011615 case NL80211_IFTYPE_STATION:
11616 case NL80211_IFTYPE_ADHOC:
11617 case NL80211_IFTYPE_P2P_CLIENT:
11618 case NL80211_IFTYPE_AP:
11619 case NL80211_IFTYPE_AP_VLAN:
11620 case NL80211_IFTYPE_MESH_POINT:
11621 case NL80211_IFTYPE_P2P_GO:
11622 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011623 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +020011624 default:
Johannes Berg4c476992010-10-04 21:36:35 +020011625 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +020011626 }
Jouni Malinen026331c2010-02-15 12:53:10 +020011627
Johannes Bergf7ca38d2010-11-25 10:02:29 +010011628 if (info->attrs[NL80211_ATTR_DURATION]) {
Johannes Berg7c4ef712011-11-18 15:33:48 +010011629 if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Bergf7ca38d2010-11-25 10:02:29 +010011630 return -EINVAL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020011631 params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
Johannes Bergebf348f2012-06-01 12:50:54 +020011632
11633 /*
11634 * We should wait on the channel for at least a minimum amount
11635 * of time (10ms) but no longer than the driver supports.
11636 */
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020011637 if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
11638 params.wait > rdev->wiphy.max_remain_on_channel_duration)
Johannes Bergebf348f2012-06-01 12:50:54 +020011639 return -EINVAL;
Johannes Bergf7ca38d2010-11-25 10:02:29 +010011640 }
11641
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020011642 params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
Johannes Bergf7ca38d2010-11-25 10:02:29 +010011643
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020011644 if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Berg7c4ef712011-11-18 15:33:48 +010011645 return -EINVAL;
11646
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020011647 params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +053011648
Antonio Quartulliea141b752013-06-11 14:20:03 +020011649 /* get the channel if any has been specified, otherwise pass NULL to
11650 * the driver. The latter will use the current one
11651 */
11652 chandef.chan = NULL;
11653 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
11654 err = nl80211_parse_chandef(rdev, info, &chandef);
11655 if (err)
11656 return err;
11657 }
11658
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020011659 if (!chandef.chan && params.offchan)
Antonio Quartulliea141b752013-06-11 14:20:03 +020011660 return -EINVAL;
Jouni Malinen026331c2010-02-15 12:53:10 +020011661
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +053011662 wdev_lock(wdev);
11663 if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) {
11664 wdev_unlock(wdev);
11665 return -EBUSY;
11666 }
11667 wdev_unlock(wdev);
11668
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +030011669 params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
11670 params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
11671
11672 if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
11673 int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
11674 int i;
11675
11676 if (len % sizeof(u16))
11677 return -EINVAL;
11678
11679 params.n_csa_offsets = len / sizeof(u16);
11680 params.csa_offsets =
11681 nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
11682
11683 /* check that all the offsets fit the frame */
11684 for (i = 0; i < params.n_csa_offsets; i++) {
11685 if (params.csa_offsets[i] >= params.len)
11686 return -EINVAL;
11687 }
11688 }
11689
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020011690 if (!params.dont_wait_for_ack) {
Johannes Berge247bd902011-11-04 11:18:21 +010011691 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11692 if (!msg)
11693 return -ENOMEM;
Jouni Malinen026331c2010-02-15 12:53:10 +020011694
Eric W. Biederman15e47302012-09-07 20:12:54 +000011695 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berge247bd902011-11-04 11:18:21 +010011696 NL80211_CMD_FRAME);
Dan Carpentercb35fba2013-08-14 14:50:01 +030011697 if (!hdr) {
11698 err = -ENOBUFS;
Johannes Berge247bd902011-11-04 11:18:21 +010011699 goto free_msg;
11700 }
Jouni Malinen026331c2010-02-15 12:53:10 +020011701 }
Johannes Berge247bd902011-11-04 11:18:21 +010011702
Andrei Otcheretianskib176e622013-11-18 19:06:49 +020011703 params.chan = chandef.chan;
11704 err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
Jouni Malinen026331c2010-02-15 12:53:10 +020011705 if (err)
11706 goto free_msg;
11707
Johannes Berge247bd902011-11-04 11:18:21 +010011708 if (msg) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020011709 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
11710 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040011711 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020011712
Johannes Berge247bd902011-11-04 11:18:21 +010011713 genlmsg_end(msg, hdr);
11714 return genlmsg_reply(msg, info);
11715 }
11716
11717 return 0;
Jouni Malinen026331c2010-02-15 12:53:10 +020011718
11719 nla_put_failure:
11720 err = -ENOBUFS;
11721 free_msg:
11722 nlmsg_free(msg);
Jouni Malinen026331c2010-02-15 12:53:10 +020011723 return err;
11724}
11725
Johannes Bergf7ca38d2010-11-25 10:02:29 +010011726static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
11727{
11728 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +020011729 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Bergf7ca38d2010-11-25 10:02:29 +010011730 u64 cookie;
11731
11732 if (!info->attrs[NL80211_ATTR_COOKIE])
11733 return -EINVAL;
11734
11735 if (!rdev->ops->mgmt_tx_cancel_wait)
11736 return -EOPNOTSUPP;
11737
Johannes Berg71bbc992012-06-15 15:30:18 +020011738 switch (wdev->iftype) {
11739 case NL80211_IFTYPE_STATION:
11740 case NL80211_IFTYPE_ADHOC:
11741 case NL80211_IFTYPE_P2P_CLIENT:
11742 case NL80211_IFTYPE_AP:
11743 case NL80211_IFTYPE_AP_VLAN:
11744 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +020011745 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +020011746 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011747 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +020011748 default:
Johannes Bergf7ca38d2010-11-25 10:02:29 +010011749 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +020011750 }
Johannes Bergf7ca38d2010-11-25 10:02:29 +010011751
11752 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
11753
Hila Gonene35e4d22012-06-27 17:19:42 +030011754 return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
Johannes Bergf7ca38d2010-11-25 10:02:29 +010011755}
11756
Kalle Valoffb9eb32010-02-17 17:58:10 +020011757static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
11758{
Johannes Berg4c476992010-10-04 21:36:35 +020011759 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +020011760 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020011761 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +020011762 u8 ps_state;
11763 bool state;
11764 int err;
11765
Johannes Berg4c476992010-10-04 21:36:35 +020011766 if (!info->attrs[NL80211_ATTR_PS_STATE])
11767 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011768
11769 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
11770
Kalle Valoffb9eb32010-02-17 17:58:10 +020011771 wdev = dev->ieee80211_ptr;
11772
Johannes Berg4c476992010-10-04 21:36:35 +020011773 if (!rdev->ops->set_power_mgmt)
11774 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011775
11776 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
11777
11778 if (state == wdev->ps)
Johannes Berg4c476992010-10-04 21:36:35 +020011779 return 0;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011780
Hila Gonene35e4d22012-06-27 17:19:42 +030011781 err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
Johannes Berg4c476992010-10-04 21:36:35 +020011782 if (!err)
11783 wdev->ps = state;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011784 return err;
11785}
11786
11787static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
11788{
Johannes Berg4c476992010-10-04 21:36:35 +020011789 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +020011790 enum nl80211_ps_state ps_state;
11791 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020011792 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +020011793 struct sk_buff *msg;
11794 void *hdr;
11795 int err;
11796
Kalle Valoffb9eb32010-02-17 17:58:10 +020011797 wdev = dev->ieee80211_ptr;
11798
Johannes Berg4c476992010-10-04 21:36:35 +020011799 if (!rdev->ops->set_power_mgmt)
11800 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011801
11802 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +020011803 if (!msg)
11804 return -ENOMEM;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011805
Eric W. Biederman15e47302012-09-07 20:12:54 +000011806 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Kalle Valoffb9eb32010-02-17 17:58:10 +020011807 NL80211_CMD_GET_POWER_SAVE);
11808 if (!hdr) {
Johannes Berg4c476992010-10-04 21:36:35 +020011809 err = -ENOBUFS;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011810 goto free_msg;
11811 }
11812
11813 if (wdev->ps)
11814 ps_state = NL80211_PS_ENABLED;
11815 else
11816 ps_state = NL80211_PS_DISABLED;
11817
David S. Miller9360ffd2012-03-29 04:41:26 -040011818 if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
11819 goto nla_put_failure;
Kalle Valoffb9eb32010-02-17 17:58:10 +020011820
11821 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +020011822 return genlmsg_reply(msg, info);
Kalle Valoffb9eb32010-02-17 17:58:10 +020011823
Johannes Berg4c476992010-10-04 21:36:35 +020011824 nla_put_failure:
Kalle Valoffb9eb32010-02-17 17:58:10 +020011825 err = -ENOBUFS;
Johannes Berg4c476992010-10-04 21:36:35 +020011826 free_msg:
Kalle Valoffb9eb32010-02-17 17:58:10 +020011827 nlmsg_free(msg);
Kalle Valoffb9eb32010-02-17 17:58:10 +020011828 return err;
11829}
11830
Johannes Berg94e860f2014-01-20 23:58:15 +010011831static const struct nla_policy
11832nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011833 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011834 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
11835 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
Thomas Pedersen84f10702012-07-12 16:17:33 -070011836 [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
11837 [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
11838 [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010011839 [NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011840};
11841
Thomas Pedersen84f10702012-07-12 16:17:33 -070011842static int nl80211_set_cqm_txe(struct genl_info *info,
Johannes Bergd9d8b012012-11-26 12:51:52 +010011843 u32 rate, u32 pkts, u32 intvl)
Thomas Pedersen84f10702012-07-12 16:17:33 -070011844{
11845 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Thomas Pedersen84f10702012-07-12 16:17:33 -070011846 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +020011847 struct wireless_dev *wdev = dev->ieee80211_ptr;
Thomas Pedersen84f10702012-07-12 16:17:33 -070011848
Johannes Bergd9d8b012012-11-26 12:51:52 +010011849 if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
Thomas Pedersen84f10702012-07-12 16:17:33 -070011850 return -EINVAL;
11851
Thomas Pedersen84f10702012-07-12 16:17:33 -070011852 if (!rdev->ops->set_cqm_txe_config)
11853 return -EOPNOTSUPP;
11854
11855 if (wdev->iftype != NL80211_IFTYPE_STATION &&
11856 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
11857 return -EOPNOTSUPP;
11858
Hila Gonene35e4d22012-06-27 17:19:42 +030011859 return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
Thomas Pedersen84f10702012-07-12 16:17:33 -070011860}
11861
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011862static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
11863 struct net_device *dev)
11864{
11865 struct wireless_dev *wdev = dev->ieee80211_ptr;
11866 s32 last, low, high;
11867 u32 hyst;
Masashi Honma1222a162018-09-25 11:15:01 +090011868 int i, n, low_index;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011869 int err;
11870
11871 /* RSSI reporting disabled? */
11872 if (!wdev->cqm_config)
11873 return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
11874
11875 /*
11876 * Obtain current RSSI value if possible, if not and no RSSI threshold
11877 * event has been received yet, we should receive an event after a
11878 * connection is established and enough beacons received to calculate
11879 * the average.
11880 */
11881 if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
11882 rdev->ops->get_station) {
Johannes Berg73887fd2018-05-18 09:57:55 +020011883 struct station_info sinfo = {};
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011884 u8 *mac_addr;
11885
11886 mac_addr = wdev->current_bss->pub.bssid;
11887
Johannes Berg73887fd2018-05-18 09:57:55 +020011888 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
11889 if (err)
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011890 return err;
11891
Felix Fietkaudf167372020-01-08 18:06:30 +010011892 cfg80211_sinfo_release_content(&sinfo);
Omer Efrat397c6572018-06-17 13:06:14 +030011893 if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011894 wdev->cqm_config->last_rssi_event_value =
Johannes Berg73887fd2018-05-18 09:57:55 +020011895 (s8) sinfo.rx_beacon_signal_avg;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011896 }
11897
11898 last = wdev->cqm_config->last_rssi_event_value;
11899 hyst = wdev->cqm_config->rssi_hyst;
11900 n = wdev->cqm_config->n_rssi_thresholds;
11901
Masashi Honma4b2c5a12019-09-08 09:56:53 +090011902 for (i = 0; i < n; i++) {
11903 i = array_index_nospec(i, n);
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011904 if (last < wdev->cqm_config->rssi_thresholds[i])
11905 break;
Masashi Honma4b2c5a12019-09-08 09:56:53 +090011906 }
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011907
Masashi Honma1222a162018-09-25 11:15:01 +090011908 low_index = i - 1;
11909 if (low_index >= 0) {
11910 low_index = array_index_nospec(low_index, n);
11911 low = wdev->cqm_config->rssi_thresholds[low_index] - hyst;
11912 } else {
11913 low = S32_MIN;
11914 }
11915 if (i < n) {
11916 i = array_index_nospec(i, n);
11917 high = wdev->cqm_config->rssi_thresholds[i] + hyst - 1;
11918 } else {
11919 high = S32_MAX;
11920 }
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011921
11922 return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
11923}
11924
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011925static int nl80211_set_cqm_rssi(struct genl_info *info,
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011926 const s32 *thresholds, int n_thresholds,
11927 u32 hysteresis)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011928{
Johannes Berg4c476992010-10-04 21:36:35 +020011929 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +020011930 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +020011931 struct wireless_dev *wdev = dev->ieee80211_ptr;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011932 int i, err;
11933 s32 prev = S32_MIN;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011934
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011935 /* Check all values negative and sorted */
11936 for (i = 0; i < n_thresholds; i++) {
11937 if (thresholds[i] > 0 || thresholds[i] <= prev)
11938 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011939
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011940 prev = thresholds[i];
11941 }
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011942
Johannes Berg074ac8d2010-09-16 14:58:22 +020011943 if (wdev->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020011944 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
11945 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011946
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011947 wdev_lock(wdev);
11948 cfg80211_cqm_config_free(wdev);
11949 wdev_unlock(wdev);
11950
11951 if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
11952 if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
11953 return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
11954
11955 return rdev_set_cqm_rssi_config(rdev, dev,
11956 thresholds[0], hysteresis);
11957 }
11958
11959 if (!wiphy_ext_feature_isset(&rdev->wiphy,
11960 NL80211_EXT_FEATURE_CQM_RSSI_LIST))
11961 return -EOPNOTSUPP;
11962
11963 if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */
11964 n_thresholds = 0;
11965
11966 wdev_lock(wdev);
11967 if (n_thresholds) {
11968 struct cfg80211_cqm_config *cqm_config;
11969
Len Baker40f231e2021-09-19 13:40:40 +020011970 cqm_config = kzalloc(struct_size(cqm_config, rssi_thresholds,
11971 n_thresholds),
11972 GFP_KERNEL);
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011973 if (!cqm_config) {
11974 err = -ENOMEM;
11975 goto unlock;
11976 }
11977
11978 cqm_config->rssi_hyst = hysteresis;
11979 cqm_config->n_rssi_thresholds = n_thresholds;
11980 memcpy(cqm_config->rssi_thresholds, thresholds,
Len Baker40f231e2021-09-19 13:40:40 +020011981 flex_array_size(cqm_config, rssi_thresholds,
11982 n_thresholds));
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010011983
11984 wdev->cqm_config = cqm_config;
11985 }
11986
11987 err = cfg80211_cqm_rssi_update(rdev, dev);
11988
11989unlock:
11990 wdev_unlock(wdev);
11991
11992 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020011993}
11994
11995static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
11996{
11997 struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
11998 struct nlattr *cqm;
11999 int err;
12000
12001 cqm = info->attrs[NL80211_ATTR_CQM];
Johannes Berg1da5fcc2013-08-06 14:10:48 +020012002 if (!cqm)
12003 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012004
Johannes Berg8cb08172019-04-26 14:07:28 +020012005 err = nla_parse_nested_deprecated(attrs, NL80211_ATTR_CQM_MAX, cqm,
12006 nl80211_attr_cqm_policy,
12007 info->extack);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012008 if (err)
Johannes Berg1da5fcc2013-08-06 14:10:48 +020012009 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012010
12011 if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
12012 attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010012013 const s32 *thresholds =
12014 nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
12015 int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
Johannes Berg1da5fcc2013-08-06 14:10:48 +020012016 u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012017
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010012018 if (len % 4)
12019 return -EINVAL;
12020
12021 return nl80211_set_cqm_rssi(info, thresholds, len / 4,
12022 hysteresis);
Johannes Berg1da5fcc2013-08-06 14:10:48 +020012023 }
12024
12025 if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
12026 attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
12027 attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
12028 u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
12029 u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
12030 u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
12031
12032 return nl80211_set_cqm_txe(info, rate, pkts, intvl);
12033 }
12034
12035 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012036}
12037
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012038static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
12039{
12040 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12041 struct net_device *dev = info->user_ptr[1];
12042 struct ocb_setup setup = {};
12043 int err;
12044
12045 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
12046 if (err)
12047 return err;
12048
12049 return cfg80211_join_ocb(rdev, dev, &setup);
12050}
12051
12052static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
12053{
12054 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12055 struct net_device *dev = info->user_ptr[1];
12056
12057 return cfg80211_leave_ocb(rdev, dev);
12058}
12059
Johannes Berg29cbe682010-12-03 09:20:44 +010012060static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
12061{
12062 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12063 struct net_device *dev = info->user_ptr[1];
12064 struct mesh_config cfg;
Javier Cardonac80d5452010-12-16 17:37:49 -080012065 struct mesh_setup setup;
Johannes Berg29cbe682010-12-03 09:20:44 +010012066 int err;
12067
12068 /* start with default */
12069 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
Javier Cardonac80d5452010-12-16 17:37:49 -080012070 memcpy(&setup, &default_mesh_setup, sizeof(setup));
Johannes Berg29cbe682010-12-03 09:20:44 +010012071
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012072 if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
Johannes Berg29cbe682010-12-03 09:20:44 +010012073 /* and parse parameters if given */
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012074 err = nl80211_parse_mesh_config(info, &cfg, NULL);
Johannes Berg29cbe682010-12-03 09:20:44 +010012075 if (err)
12076 return err;
12077 }
12078
12079 if (!info->attrs[NL80211_ATTR_MESH_ID] ||
12080 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
12081 return -EINVAL;
12082
Javier Cardonac80d5452010-12-16 17:37:49 -080012083 setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
12084 setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
12085
Chun-Yeow Yeoh4bb62342011-11-24 17:15:20 -080012086 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
12087 !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
12088 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
12089 return -EINVAL;
12090
Marco Porsch9bdbf042013-01-07 16:04:51 +010012091 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
12092 setup.beacon_interval =
12093 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053012094
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +053012095 err = cfg80211_validate_beacon_int(rdev,
12096 NL80211_IFTYPE_MESH_POINT,
12097 setup.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053012098 if (err)
12099 return err;
Marco Porsch9bdbf042013-01-07 16:04:51 +010012100 }
12101
12102 if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
12103 setup.dtim_period =
12104 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
12105 if (setup.dtim_period < 1 || setup.dtim_period > 100)
12106 return -EINVAL;
12107 }
12108
Javier Cardonac80d5452010-12-16 17:37:49 -080012109 if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
12110 /* parse additional setup parameters if given */
12111 err = nl80211_parse_mesh_setup(info, &setup);
12112 if (err)
12113 return err;
12114 }
12115
Thomas Pedersend37bb182013-03-04 13:06:13 -080012116 if (setup.user_mpm)
12117 cfg.auto_open_plinks = false;
12118
Johannes Bergcc1d2802012-05-16 23:50:20 +020012119 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +010012120 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
12121 if (err)
12122 return err;
Johannes Bergcc1d2802012-05-16 23:50:20 +020012123 } else {
Denis Kenzior188c1b32018-03-26 12:52:46 -050012124 /* __cfg80211_join_mesh() will sort it out */
Johannes Berg683b6d32012-11-08 21:25:48 +010012125 setup.chandef.chan = NULL;
Johannes Bergcc1d2802012-05-16 23:50:20 +020012126 }
12127
Ashok Nagarajanffb3cf32013-06-03 10:33:36 -070012128 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
12129 u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
12130 int n_rates =
12131 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
12132 struct ieee80211_supported_band *sband;
12133
12134 if (!setup.chandef.chan)
12135 return -EINVAL;
12136
12137 sband = rdev->wiphy.bands[setup.chandef.chan->band];
12138
12139 err = ieee80211_get_ratemask(sband, rates, n_rates,
12140 &setup.basic_rates);
12141 if (err)
12142 return err;
12143 }
12144
Johannes Berg8564e382016-09-19 09:44:44 +020012145 if (info->attrs[NL80211_ATTR_TX_RATES]) {
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +053012146 err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
12147 NL80211_ATTR_TX_RATES,
Miles Hueb89a6a2020-08-04 10:16:29 +020012148 &setup.beacon_rate,
Rajkumar Manoharan857b34c2020-10-16 13:15:26 -070012149 dev, false);
Johannes Berg8564e382016-09-19 09:44:44 +020012150 if (err)
12151 return err;
12152
Johannes Berg265698d2017-09-18 22:46:36 +020012153 if (!setup.chandef.chan)
12154 return -EINVAL;
12155
Johannes Berg8564e382016-09-19 09:44:44 +020012156 err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band,
12157 &setup.beacon_rate);
12158 if (err)
12159 return err;
12160 }
12161
Benjamin Bergd37d49c2017-05-16 11:23:11 +020012162 setup.userspace_handles_dfs =
12163 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
12164
Denis Kenzior1224f582018-03-26 12:52:49 -050012165 if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
12166 int r = validate_pae_over_nl80211(rdev, info);
12167
12168 if (r < 0)
12169 return r;
12170
12171 setup.control_port_over_nl80211 = true;
12172 }
12173
Denis Kenzior188c1b32018-03-26 12:52:46 -050012174 wdev_lock(dev->ieee80211_ptr);
12175 err = __cfg80211_join_mesh(rdev, dev, &setup, &cfg);
12176 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER])
12177 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
12178 wdev_unlock(dev->ieee80211_ptr);
12179
12180 return err;
Johannes Berg29cbe682010-12-03 09:20:44 +010012181}
12182
12183static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
12184{
12185 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12186 struct net_device *dev = info->user_ptr[1];
12187
12188 return cfg80211_leave_mesh(rdev, dev);
12189}
12190
Johannes Bergdfb89c52012-06-27 09:23:48 +020012191#ifdef CONFIG_PM
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080012192static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
12193 struct cfg80211_registered_device *rdev)
12194{
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012195 struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080012196 struct nlattr *nl_pats, *nl_pat;
12197 int i, pat_len;
12198
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012199 if (!wowlan->n_patterns)
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080012200 return 0;
12201
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012202 nl_pats = nla_nest_start_noflag(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080012203 if (!nl_pats)
12204 return -ENOBUFS;
12205
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012206 for (i = 0; i < wowlan->n_patterns; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012207 nl_pat = nla_nest_start_noflag(msg, i + 1);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080012208 if (!nl_pat)
12209 return -ENOBUFS;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012210 pat_len = wowlan->patterns[i].pattern_len;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070012211 if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012212 wowlan->patterns[i].mask) ||
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070012213 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
12214 wowlan->patterns[i].pattern) ||
12215 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012216 wowlan->patterns[i].pkt_offset))
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080012217 return -ENOBUFS;
12218 nla_nest_end(msg, nl_pat);
12219 }
12220 nla_nest_end(msg, nl_pats);
12221
12222 return 0;
12223}
12224
Johannes Berg2a0e0472013-01-23 22:57:40 +010012225static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
12226 struct cfg80211_wowlan_tcp *tcp)
12227{
12228 struct nlattr *nl_tcp;
12229
12230 if (!tcp)
12231 return 0;
12232
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012233 nl_tcp = nla_nest_start_noflag(msg,
12234 NL80211_WOWLAN_TRIG_TCP_CONNECTION);
Johannes Berg2a0e0472013-01-23 22:57:40 +010012235 if (!nl_tcp)
12236 return -ENOBUFS;
12237
Jiri Benc930345e2015-03-29 16:59:25 +020012238 if (nla_put_in_addr(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
12239 nla_put_in_addr(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
Johannes Berg2a0e0472013-01-23 22:57:40 +010012240 nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
12241 nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
12242 nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
12243 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
12244 tcp->payload_len, tcp->payload) ||
12245 nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
12246 tcp->data_interval) ||
12247 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
12248 tcp->wake_len, tcp->wake_data) ||
12249 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK,
12250 DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask))
12251 return -ENOBUFS;
12252
12253 if (tcp->payload_seq.len &&
12254 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
12255 sizeof(tcp->payload_seq), &tcp->payload_seq))
12256 return -ENOBUFS;
12257
12258 if (tcp->payload_tok.len &&
12259 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
12260 sizeof(tcp->payload_tok) + tcp->tokens_size,
12261 &tcp->payload_tok))
12262 return -ENOBUFS;
12263
Johannes Berge248ad32013-05-16 10:24:28 +020012264 nla_nest_end(msg, nl_tcp);
12265
Johannes Berg2a0e0472013-01-23 22:57:40 +010012266 return 0;
12267}
12268
Luciano Coelho75453cc2015-01-09 14:06:37 +020012269static int nl80211_send_wowlan_nd(struct sk_buff *msg,
12270 struct cfg80211_sched_scan_request *req)
12271{
Avraham Stern3b06d272015-10-12 09:51:34 +030012272 struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
Luciano Coelho75453cc2015-01-09 14:06:37 +020012273 int i;
12274
12275 if (!req)
12276 return 0;
12277
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012278 nd = nla_nest_start_noflag(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
Luciano Coelho75453cc2015-01-09 14:06:37 +020012279 if (!nd)
12280 return -ENOBUFS;
12281
Avraham Stern3b06d272015-10-12 09:51:34 +030012282 if (req->n_scan_plans == 1 &&
12283 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
12284 req->scan_plans[0].interval * 1000))
Luciano Coelho75453cc2015-01-09 14:06:37 +020012285 return -ENOBUFS;
12286
Luciano Coelho21fea562015-03-17 16:36:01 +020012287 if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
12288 return -ENOBUFS;
12289
vamsi krishnabf95ecd2017-01-13 01:12:20 +020012290 if (req->relative_rssi_set) {
12291 struct nl80211_bss_select_rssi_adjust rssi_adjust;
12292
12293 if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
12294 req->relative_rssi))
12295 return -ENOBUFS;
12296
12297 rssi_adjust.band = req->rssi_adjust.band;
12298 rssi_adjust.delta = req->rssi_adjust.delta;
12299 if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
12300 sizeof(rssi_adjust), &rssi_adjust))
12301 return -ENOBUFS;
12302 }
12303
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012304 freqs = nla_nest_start_noflag(msg, NL80211_ATTR_SCAN_FREQUENCIES);
Luciano Coelho75453cc2015-01-09 14:06:37 +020012305 if (!freqs)
12306 return -ENOBUFS;
12307
Johannes Berg53b18982016-09-14 09:59:21 +020012308 for (i = 0; i < req->n_channels; i++) {
12309 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
12310 return -ENOBUFS;
12311 }
Luciano Coelho75453cc2015-01-09 14:06:37 +020012312
12313 nla_nest_end(msg, freqs);
12314
12315 if (req->n_match_sets) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012316 matches = nla_nest_start_noflag(msg,
12317 NL80211_ATTR_SCHED_SCAN_MATCH);
Johannes Berg76e1fb42016-09-14 09:55:57 +020012318 if (!matches)
12319 return -ENOBUFS;
12320
Luciano Coelho75453cc2015-01-09 14:06:37 +020012321 for (i = 0; i < req->n_match_sets; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012322 match = nla_nest_start_noflag(msg, i);
Johannes Berg76e1fb42016-09-14 09:55:57 +020012323 if (!match)
12324 return -ENOBUFS;
12325
Johannes Berg53b18982016-09-14 09:59:21 +020012326 if (nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
12327 req->match_sets[i].ssid.ssid_len,
12328 req->match_sets[i].ssid.ssid))
12329 return -ENOBUFS;
Luciano Coelho75453cc2015-01-09 14:06:37 +020012330 nla_nest_end(msg, match);
12331 }
12332 nla_nest_end(msg, matches);
12333 }
12334
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012335 scan_plans = nla_nest_start_noflag(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
Avraham Stern3b06d272015-10-12 09:51:34 +030012336 if (!scan_plans)
12337 return -ENOBUFS;
12338
12339 for (i = 0; i < req->n_scan_plans; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012340 scan_plan = nla_nest_start_noflag(msg, i + 1);
Johannes Berg76e1fb42016-09-14 09:55:57 +020012341 if (!scan_plan)
12342 return -ENOBUFS;
12343
Colin Ian King67626962018-09-06 10:58:44 +010012344 if (nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
Avraham Stern3b06d272015-10-12 09:51:34 +030012345 req->scan_plans[i].interval) ||
12346 (req->scan_plans[i].iterations &&
12347 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
12348 req->scan_plans[i].iterations)))
12349 return -ENOBUFS;
12350 nla_nest_end(msg, scan_plan);
12351 }
12352 nla_nest_end(msg, scan_plans);
12353
Luciano Coelho75453cc2015-01-09 14:06:37 +020012354 nla_nest_end(msg, nd);
12355
12356 return 0;
12357}
12358
Johannes Bergff1b6e62011-05-04 15:37:28 +020012359static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
12360{
12361 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12362 struct sk_buff *msg;
12363 void *hdr;
Johannes Berg2a0e0472013-01-23 22:57:40 +010012364 u32 size = NLMSG_DEFAULT_SIZE;
Johannes Bergff1b6e62011-05-04 15:37:28 +020012365
Johannes Berg964dc9e2013-06-03 17:25:34 +020012366 if (!rdev->wiphy.wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020012367 return -EOPNOTSUPP;
12368
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012369 if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
Johannes Berg2a0e0472013-01-23 22:57:40 +010012370 /* adjust size to have room for all the data */
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012371 size += rdev->wiphy.wowlan_config->tcp->tokens_size +
12372 rdev->wiphy.wowlan_config->tcp->payload_len +
12373 rdev->wiphy.wowlan_config->tcp->wake_len +
12374 rdev->wiphy.wowlan_config->tcp->wake_len / 8;
Johannes Berg2a0e0472013-01-23 22:57:40 +010012375 }
12376
12377 msg = nlmsg_new(size, GFP_KERNEL);
Johannes Bergff1b6e62011-05-04 15:37:28 +020012378 if (!msg)
12379 return -ENOMEM;
12380
Eric W. Biederman15e47302012-09-07 20:12:54 +000012381 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Bergff1b6e62011-05-04 15:37:28 +020012382 NL80211_CMD_GET_WOWLAN);
12383 if (!hdr)
12384 goto nla_put_failure;
12385
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012386 if (rdev->wiphy.wowlan_config) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020012387 struct nlattr *nl_wowlan;
12388
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012389 nl_wowlan = nla_nest_start_noflag(msg,
12390 NL80211_ATTR_WOWLAN_TRIGGERS);
Johannes Bergff1b6e62011-05-04 15:37:28 +020012391 if (!nl_wowlan)
12392 goto nla_put_failure;
12393
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012394 if ((rdev->wiphy.wowlan_config->any &&
David S. Miller9360ffd2012-03-29 04:41:26 -040012395 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012396 (rdev->wiphy.wowlan_config->disconnect &&
David S. Miller9360ffd2012-03-29 04:41:26 -040012397 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012398 (rdev->wiphy.wowlan_config->magic_pkt &&
David S. Miller9360ffd2012-03-29 04:41:26 -040012399 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012400 (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
David S. Miller9360ffd2012-03-29 04:41:26 -040012401 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012402 (rdev->wiphy.wowlan_config->eap_identity_req &&
David S. Miller9360ffd2012-03-29 04:41:26 -040012403 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012404 (rdev->wiphy.wowlan_config->four_way_handshake &&
David S. Miller9360ffd2012-03-29 04:41:26 -040012405 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012406 (rdev->wiphy.wowlan_config->rfkill_release &&
David S. Miller9360ffd2012-03-29 04:41:26 -040012407 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
12408 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +010012409
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080012410 if (nl80211_send_wowlan_patterns(msg, rdev))
12411 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +010012412
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012413 if (nl80211_send_wowlan_tcp(msg,
12414 rdev->wiphy.wowlan_config->tcp))
Johannes Berg2a0e0472013-01-23 22:57:40 +010012415 goto nla_put_failure;
12416
Luciano Coelho75453cc2015-01-09 14:06:37 +020012417 if (nl80211_send_wowlan_nd(
12418 msg,
12419 rdev->wiphy.wowlan_config->nd_config))
12420 goto nla_put_failure;
12421
Johannes Bergff1b6e62011-05-04 15:37:28 +020012422 nla_nest_end(msg, nl_wowlan);
12423 }
12424
12425 genlmsg_end(msg, hdr);
12426 return genlmsg_reply(msg, info);
12427
12428nla_put_failure:
12429 nlmsg_free(msg);
12430 return -ENOBUFS;
12431}
12432
Johannes Berg2a0e0472013-01-23 22:57:40 +010012433static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
12434 struct nlattr *attr,
12435 struct cfg80211_wowlan *trig)
12436{
12437 struct nlattr *tb[NUM_NL80211_WOWLAN_TCP];
12438 struct cfg80211_wowlan_tcp *cfg;
12439 struct nl80211_wowlan_tcp_data_token *tok = NULL;
12440 struct nl80211_wowlan_tcp_data_seq *seq = NULL;
12441 u32 size;
12442 u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
12443 int err, port;
12444
Johannes Berg964dc9e2013-06-03 17:25:34 +020012445 if (!rdev->wiphy.wowlan->tcp)
Johannes Berg2a0e0472013-01-23 22:57:40 +010012446 return -EINVAL;
12447
Johannes Berg8cb08172019-04-26 14:07:28 +020012448 err = nla_parse_nested_deprecated(tb, MAX_NL80211_WOWLAN_TCP, attr,
12449 nl80211_wowlan_tcp_policy, NULL);
Johannes Berg2a0e0472013-01-23 22:57:40 +010012450 if (err)
12451 return err;
12452
12453 if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] ||
12454 !tb[NL80211_WOWLAN_TCP_DST_IPV4] ||
12455 !tb[NL80211_WOWLAN_TCP_DST_MAC] ||
12456 !tb[NL80211_WOWLAN_TCP_DST_PORT] ||
12457 !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] ||
12458 !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] ||
12459 !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] ||
12460 !tb[NL80211_WOWLAN_TCP_WAKE_MASK])
12461 return -EINVAL;
12462
12463 data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020012464 if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010012465 return -EINVAL;
12466
12467 if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
Johannes Berg964dc9e2013-06-03 17:25:34 +020012468 rdev->wiphy.wowlan->tcp->data_interval_max ||
Johannes Berg723d5682013-02-26 13:56:40 +010012469 nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
Johannes Berg2a0e0472013-01-23 22:57:40 +010012470 return -EINVAL;
12471
12472 wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020012473 if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010012474 return -EINVAL;
12475
12476 wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
12477 if (wake_mask_size != DIV_ROUND_UP(wake_size, 8))
12478 return -EINVAL;
12479
12480 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) {
12481 u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
12482
12483 tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
12484 tokens_size = tokln - sizeof(*tok);
12485
12486 if (!tok->len || tokens_size % tok->len)
12487 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020012488 if (!rdev->wiphy.wowlan->tcp->tok)
Johannes Berg2a0e0472013-01-23 22:57:40 +010012489 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020012490 if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010012491 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020012492 if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010012493 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020012494 if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
Johannes Berg2a0e0472013-01-23 22:57:40 +010012495 return -EINVAL;
12496 if (tok->offset + tok->len > data_size)
12497 return -EINVAL;
12498 }
12499
12500 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
12501 seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020012502 if (!rdev->wiphy.wowlan->tcp->seq)
Johannes Berg2a0e0472013-01-23 22:57:40 +010012503 return -EINVAL;
12504 if (seq->len == 0 || seq->len > 4)
12505 return -EINVAL;
12506 if (seq->len + seq->offset > data_size)
12507 return -EINVAL;
12508 }
12509
12510 size = sizeof(*cfg);
12511 size += data_size;
12512 size += wake_size + wake_mask_size;
12513 size += tokens_size;
12514
12515 cfg = kzalloc(size, GFP_KERNEL);
12516 if (!cfg)
12517 return -ENOMEM;
Jiri Benc67b61f62015-03-29 16:59:26 +020012518 cfg->src = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
12519 cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
Johannes Berg2a0e0472013-01-23 22:57:40 +010012520 memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
12521 ETH_ALEN);
12522 if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
12523 port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
12524 else
12525 port = 0;
12526#ifdef CONFIG_INET
12527 /* allocate a socket and port for it and use it */
12528 err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
12529 IPPROTO_TCP, &cfg->sock, 1);
12530 if (err) {
12531 kfree(cfg);
12532 return err;
12533 }
12534 if (inet_csk_get_port(cfg->sock->sk, port)) {
12535 sock_release(cfg->sock);
12536 kfree(cfg);
12537 return -EADDRINUSE;
12538 }
12539 cfg->src_port = inet_sk(cfg->sock->sk)->inet_num;
12540#else
12541 if (!port) {
12542 kfree(cfg);
12543 return -EINVAL;
12544 }
12545 cfg->src_port = port;
12546#endif
12547
12548 cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]);
12549 cfg->payload_len = data_size;
12550 cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size;
12551 memcpy((void *)cfg->payload,
12552 nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]),
12553 data_size);
12554 if (seq)
12555 cfg->payload_seq = *seq;
12556 cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]);
12557 cfg->wake_len = wake_size;
12558 cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size;
12559 memcpy((void *)cfg->wake_data,
12560 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]),
12561 wake_size);
12562 cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size +
12563 data_size + wake_size;
12564 memcpy((void *)cfg->wake_mask,
12565 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]),
12566 wake_mask_size);
12567 if (tok) {
12568 cfg->tokens_size = tokens_size;
12569 memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size);
12570 }
12571
12572 trig->tcp = cfg;
12573
12574 return 0;
12575}
12576
Luciano Coelho8cd4d452014-09-17 11:55:28 +030012577static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
12578 const struct wiphy_wowlan_support *wowlan,
12579 struct nlattr *attr,
12580 struct cfg80211_wowlan *trig)
12581{
12582 struct nlattr **tb;
12583 int err;
12584
Kees Cook6396bb22018-06-12 14:03:40 -070012585 tb = kcalloc(NUM_NL80211_ATTR, sizeof(*tb), GFP_KERNEL);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030012586 if (!tb)
12587 return -ENOMEM;
12588
12589 if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) {
12590 err = -EOPNOTSUPP;
12591 goto out;
12592 }
12593
Johannes Berg8cb08172019-04-26 14:07:28 +020012594 err = nla_parse_nested_deprecated(tb, NL80211_ATTR_MAX, attr,
12595 nl80211_policy, NULL);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030012596 if (err)
12597 goto out;
12598
Arend Van Sprielaad1e812017-01-27 12:27:44 +000012599 trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb,
12600 wowlan->max_nd_match_sets);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030012601 err = PTR_ERR_OR_ZERO(trig->nd_config);
12602 if (err)
12603 trig->nd_config = NULL;
12604
12605out:
12606 kfree(tb);
12607 return err;
12608}
12609
Johannes Bergff1b6e62011-05-04 15:37:28 +020012610static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
12611{
12612 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12613 struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
Johannes Bergff1b6e62011-05-04 15:37:28 +020012614 struct cfg80211_wowlan new_triggers = {};
Johannes Bergae33bd82012-07-12 16:25:02 +020012615 struct cfg80211_wowlan *ntrig;
Johannes Berg964dc9e2013-06-03 17:25:34 +020012616 const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
Johannes Bergff1b6e62011-05-04 15:37:28 +020012617 int err, i;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012618 bool prev_enabled = rdev->wiphy.wowlan_config;
Johannes Berg98fc4382015-03-01 09:10:13 +020012619 bool regular = false;
Johannes Bergff1b6e62011-05-04 15:37:28 +020012620
Johannes Berg964dc9e2013-06-03 17:25:34 +020012621 if (!wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020012622 return -EOPNOTSUPP;
12623
Johannes Bergae33bd82012-07-12 16:25:02 +020012624 if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
12625 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012626 rdev->wiphy.wowlan_config = NULL;
Johannes Bergae33bd82012-07-12 16:25:02 +020012627 goto set_wakeup;
12628 }
Johannes Bergff1b6e62011-05-04 15:37:28 +020012629
Johannes Berg8cb08172019-04-26 14:07:28 +020012630 err = nla_parse_nested_deprecated(tb, MAX_NL80211_WOWLAN_TRIG,
12631 info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS],
12632 nl80211_wowlan_policy, info->extack);
Johannes Bergff1b6e62011-05-04 15:37:28 +020012633 if (err)
12634 return err;
12635
12636 if (tb[NL80211_WOWLAN_TRIG_ANY]) {
12637 if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
12638 return -EINVAL;
12639 new_triggers.any = true;
12640 }
12641
12642 if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
12643 if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
12644 return -EINVAL;
12645 new_triggers.disconnect = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020012646 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020012647 }
12648
12649 if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
12650 if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
12651 return -EINVAL;
12652 new_triggers.magic_pkt = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020012653 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020012654 }
12655
Johannes Berg77dbbb12011-07-13 10:48:55 +020012656 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
12657 return -EINVAL;
12658
12659 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) {
12660 if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
12661 return -EINVAL;
12662 new_triggers.gtk_rekey_failure = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020012663 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020012664 }
12665
12666 if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
12667 if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
12668 return -EINVAL;
12669 new_triggers.eap_identity_req = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020012670 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020012671 }
12672
12673 if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
12674 if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
12675 return -EINVAL;
12676 new_triggers.four_way_handshake = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020012677 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020012678 }
12679
12680 if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
12681 if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
12682 return -EINVAL;
12683 new_triggers.rfkill_release = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020012684 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020012685 }
12686
Johannes Bergff1b6e62011-05-04 15:37:28 +020012687 if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
12688 struct nlattr *pat;
12689 int n_patterns = 0;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080012690 int rem, pat_len, mask_len, pkt_offset;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070012691 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
Johannes Bergff1b6e62011-05-04 15:37:28 +020012692
Johannes Berg98fc4382015-03-01 09:10:13 +020012693 regular = true;
12694
Johannes Bergff1b6e62011-05-04 15:37:28 +020012695 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
12696 rem)
12697 n_patterns++;
12698 if (n_patterns > wowlan->n_patterns)
12699 return -EINVAL;
12700
12701 new_triggers.patterns = kcalloc(n_patterns,
12702 sizeof(new_triggers.patterns[0]),
12703 GFP_KERNEL);
12704 if (!new_triggers.patterns)
12705 return -ENOMEM;
12706
12707 new_triggers.n_patterns = n_patterns;
12708 i = 0;
12709
12710 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
12711 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020012712 u8 *mask_pat;
12713
Johannes Berg8cb08172019-04-26 14:07:28 +020012714 err = nla_parse_nested_deprecated(pat_tb,
12715 MAX_NL80211_PKTPAT,
12716 pat,
12717 nl80211_packet_pattern_policy,
12718 info->extack);
Johannes Berg95bca622018-06-29 09:33:39 +020012719 if (err)
12720 goto error;
12721
Johannes Bergff1b6e62011-05-04 15:37:28 +020012722 err = -EINVAL;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070012723 if (!pat_tb[NL80211_PKTPAT_MASK] ||
12724 !pat_tb[NL80211_PKTPAT_PATTERN])
Johannes Bergff1b6e62011-05-04 15:37:28 +020012725 goto error;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070012726 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
Johannes Bergff1b6e62011-05-04 15:37:28 +020012727 mask_len = DIV_ROUND_UP(pat_len, 8);
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070012728 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
Johannes Bergff1b6e62011-05-04 15:37:28 +020012729 goto error;
12730 if (pat_len > wowlan->pattern_max_len ||
12731 pat_len < wowlan->pattern_min_len)
12732 goto error;
12733
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070012734 if (!pat_tb[NL80211_PKTPAT_OFFSET])
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080012735 pkt_offset = 0;
12736 else
12737 pkt_offset = nla_get_u32(
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070012738 pat_tb[NL80211_PKTPAT_OFFSET]);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080012739 if (pkt_offset > wowlan->max_pkt_offset)
12740 goto error;
12741 new_triggers.patterns[i].pkt_offset = pkt_offset;
12742
Johannes Berg922bd802014-05-19 17:59:50 +020012743 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
12744 if (!mask_pat) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020012745 err = -ENOMEM;
12746 goto error;
12747 }
Johannes Berg922bd802014-05-19 17:59:50 +020012748 new_triggers.patterns[i].mask = mask_pat;
12749 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020012750 mask_len);
Johannes Berg922bd802014-05-19 17:59:50 +020012751 mask_pat += mask_len;
12752 new_triggers.patterns[i].pattern = mask_pat;
Johannes Bergff1b6e62011-05-04 15:37:28 +020012753 new_triggers.patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020012754 memcpy(mask_pat,
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070012755 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020012756 pat_len);
12757 i++;
12758 }
12759 }
12760
Johannes Berg2a0e0472013-01-23 22:57:40 +010012761 if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020012762 regular = true;
Johannes Berg2a0e0472013-01-23 22:57:40 +010012763 err = nl80211_parse_wowlan_tcp(
12764 rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
12765 &new_triggers);
12766 if (err)
12767 goto error;
12768 }
12769
Luciano Coelho8cd4d452014-09-17 11:55:28 +030012770 if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020012771 regular = true;
Luciano Coelho8cd4d452014-09-17 11:55:28 +030012772 err = nl80211_parse_wowlan_nd(
12773 rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
12774 &new_triggers);
12775 if (err)
12776 goto error;
12777 }
12778
Johannes Berg98fc4382015-03-01 09:10:13 +020012779 /* The 'any' trigger means the device continues operating more or less
12780 * as in its normal operation mode and wakes up the host on most of the
12781 * normal interrupts (like packet RX, ...)
12782 * It therefore makes little sense to combine with the more constrained
12783 * wakeup trigger modes.
12784 */
12785 if (new_triggers.any && regular) {
12786 err = -EINVAL;
12787 goto error;
12788 }
12789
Johannes Bergae33bd82012-07-12 16:25:02 +020012790 ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
12791 if (!ntrig) {
12792 err = -ENOMEM;
12793 goto error;
Johannes Bergff1b6e62011-05-04 15:37:28 +020012794 }
Johannes Bergae33bd82012-07-12 16:25:02 +020012795 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012796 rdev->wiphy.wowlan_config = ntrig;
Johannes Bergff1b6e62011-05-04 15:37:28 +020012797
Johannes Bergae33bd82012-07-12 16:25:02 +020012798 set_wakeup:
Johannes Berg6abb9cb2013-05-15 09:30:07 +020012799 if (rdev->ops->set_wakeup &&
12800 prev_enabled != !!rdev->wiphy.wowlan_config)
12801 rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
Johannes Berg6d525632012-04-04 15:05:25 +020012802
Johannes Bergff1b6e62011-05-04 15:37:28 +020012803 return 0;
12804 error:
12805 for (i = 0; i < new_triggers.n_patterns; i++)
12806 kfree(new_triggers.patterns[i].mask);
12807 kfree(new_triggers.patterns);
Johannes Berg2a0e0472013-01-23 22:57:40 +010012808 if (new_triggers.tcp && new_triggers.tcp->sock)
12809 sock_release(new_triggers.tcp->sock);
12810 kfree(new_triggers.tcp);
Ola Olssone5dbe072015-12-12 23:17:17 +010012811 kfree(new_triggers.nd_config);
Johannes Bergff1b6e62011-05-04 15:37:28 +020012812 return err;
12813}
Johannes Bergdfb89c52012-06-27 09:23:48 +020012814#endif
Johannes Bergff1b6e62011-05-04 15:37:28 +020012815
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012816static int nl80211_send_coalesce_rules(struct sk_buff *msg,
12817 struct cfg80211_registered_device *rdev)
12818{
12819 struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
12820 int i, j, pat_len;
12821 struct cfg80211_coalesce_rules *rule;
12822
12823 if (!rdev->coalesce->n_rules)
12824 return 0;
12825
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012826 nl_rules = nla_nest_start_noflag(msg, NL80211_ATTR_COALESCE_RULE);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012827 if (!nl_rules)
12828 return -ENOBUFS;
12829
12830 for (i = 0; i < rdev->coalesce->n_rules; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012831 nl_rule = nla_nest_start_noflag(msg, i + 1);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012832 if (!nl_rule)
12833 return -ENOBUFS;
12834
12835 rule = &rdev->coalesce->rules[i];
12836 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
12837 rule->delay))
12838 return -ENOBUFS;
12839
12840 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
12841 rule->condition))
12842 return -ENOBUFS;
12843
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012844 nl_pats = nla_nest_start_noflag(msg,
12845 NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012846 if (!nl_pats)
12847 return -ENOBUFS;
12848
12849 for (j = 0; j < rule->n_patterns; j++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020012850 nl_pat = nla_nest_start_noflag(msg, j + 1);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012851 if (!nl_pat)
12852 return -ENOBUFS;
12853 pat_len = rule->patterns[j].pattern_len;
12854 if (nla_put(msg, NL80211_PKTPAT_MASK,
12855 DIV_ROUND_UP(pat_len, 8),
12856 rule->patterns[j].mask) ||
12857 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
12858 rule->patterns[j].pattern) ||
12859 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
12860 rule->patterns[j].pkt_offset))
12861 return -ENOBUFS;
12862 nla_nest_end(msg, nl_pat);
12863 }
12864 nla_nest_end(msg, nl_pats);
12865 nla_nest_end(msg, nl_rule);
12866 }
12867 nla_nest_end(msg, nl_rules);
12868
12869 return 0;
12870}
12871
12872static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
12873{
12874 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12875 struct sk_buff *msg;
12876 void *hdr;
12877
12878 if (!rdev->wiphy.coalesce)
12879 return -EOPNOTSUPP;
12880
12881 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12882 if (!msg)
12883 return -ENOMEM;
12884
12885 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
12886 NL80211_CMD_GET_COALESCE);
12887 if (!hdr)
12888 goto nla_put_failure;
12889
12890 if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
12891 goto nla_put_failure;
12892
12893 genlmsg_end(msg, hdr);
12894 return genlmsg_reply(msg, info);
12895
12896nla_put_failure:
12897 nlmsg_free(msg);
12898 return -ENOBUFS;
12899}
12900
12901void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
12902{
12903 struct cfg80211_coalesce *coalesce = rdev->coalesce;
12904 int i, j;
12905 struct cfg80211_coalesce_rules *rule;
12906
12907 if (!coalesce)
12908 return;
12909
12910 for (i = 0; i < coalesce->n_rules; i++) {
12911 rule = &coalesce->rules[i];
12912 for (j = 0; j < rule->n_patterns; j++)
12913 kfree(rule->patterns[j].mask);
12914 kfree(rule->patterns);
12915 }
12916 kfree(coalesce->rules);
12917 kfree(coalesce);
12918 rdev->coalesce = NULL;
12919}
12920
12921static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
12922 struct nlattr *rule,
12923 struct cfg80211_coalesce_rules *new_rule)
12924{
12925 int err, i;
12926 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
12927 struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
12928 int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
12929 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
12930
Johannes Berg8cb08172019-04-26 14:07:28 +020012931 err = nla_parse_nested_deprecated(tb, NL80211_ATTR_COALESCE_RULE_MAX,
12932 rule, nl80211_coalesce_policy, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012933 if (err)
12934 return err;
12935
12936 if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
12937 new_rule->delay =
12938 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
12939 if (new_rule->delay > coalesce->max_delay)
12940 return -EINVAL;
12941
12942 if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
12943 new_rule->condition =
12944 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012945
12946 if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
12947 return -EINVAL;
12948
12949 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
12950 rem)
12951 n_patterns++;
12952 if (n_patterns > coalesce->n_patterns)
12953 return -EINVAL;
12954
12955 new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
12956 GFP_KERNEL);
12957 if (!new_rule->patterns)
12958 return -ENOMEM;
12959
12960 new_rule->n_patterns = n_patterns;
12961 i = 0;
12962
12963 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
12964 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020012965 u8 *mask_pat;
12966
Johannes Berg8cb08172019-04-26 14:07:28 +020012967 err = nla_parse_nested_deprecated(pat_tb, MAX_NL80211_PKTPAT,
12968 pat,
12969 nl80211_packet_pattern_policy,
12970 NULL);
Johannes Berg95bca622018-06-29 09:33:39 +020012971 if (err)
12972 return err;
12973
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012974 if (!pat_tb[NL80211_PKTPAT_MASK] ||
12975 !pat_tb[NL80211_PKTPAT_PATTERN])
12976 return -EINVAL;
12977 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
12978 mask_len = DIV_ROUND_UP(pat_len, 8);
12979 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
12980 return -EINVAL;
12981 if (pat_len > coalesce->pattern_max_len ||
12982 pat_len < coalesce->pattern_min_len)
12983 return -EINVAL;
12984
12985 if (!pat_tb[NL80211_PKTPAT_OFFSET])
12986 pkt_offset = 0;
12987 else
12988 pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
12989 if (pkt_offset > coalesce->max_pkt_offset)
12990 return -EINVAL;
12991 new_rule->patterns[i].pkt_offset = pkt_offset;
12992
Johannes Berg922bd802014-05-19 17:59:50 +020012993 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
12994 if (!mask_pat)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070012995 return -ENOMEM;
Johannes Berg922bd802014-05-19 17:59:50 +020012996
12997 new_rule->patterns[i].mask = mask_pat;
12998 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
12999 mask_len);
13000
13001 mask_pat += mask_len;
13002 new_rule->patterns[i].pattern = mask_pat;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070013003 new_rule->patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020013004 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
13005 pat_len);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070013006 i++;
13007 }
13008
13009 return 0;
13010}
13011
13012static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
13013{
13014 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13015 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
13016 struct cfg80211_coalesce new_coalesce = {};
13017 struct cfg80211_coalesce *n_coalesce;
13018 int err, rem_rule, n_rules = 0, i, j;
13019 struct nlattr *rule;
13020 struct cfg80211_coalesce_rules *tmp_rule;
13021
13022 if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
13023 return -EOPNOTSUPP;
13024
13025 if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
13026 cfg80211_rdev_free_coalesce(rdev);
Ilan Peera1056b1b2015-10-22 22:27:46 +030013027 rdev_set_coalesce(rdev, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070013028 return 0;
13029 }
13030
13031 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
13032 rem_rule)
13033 n_rules++;
13034 if (n_rules > coalesce->n_rules)
13035 return -EINVAL;
13036
13037 new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
13038 GFP_KERNEL);
13039 if (!new_coalesce.rules)
13040 return -ENOMEM;
13041
13042 new_coalesce.n_rules = n_rules;
13043 i = 0;
13044
13045 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
13046 rem_rule) {
13047 err = nl80211_parse_coalesce_rule(rdev, rule,
13048 &new_coalesce.rules[i]);
13049 if (err)
13050 goto error;
13051
13052 i++;
13053 }
13054
Ilan Peera1056b1b2015-10-22 22:27:46 +030013055 err = rdev_set_coalesce(rdev, &new_coalesce);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070013056 if (err)
13057 goto error;
13058
13059 n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
13060 if (!n_coalesce) {
13061 err = -ENOMEM;
13062 goto error;
13063 }
13064 cfg80211_rdev_free_coalesce(rdev);
13065 rdev->coalesce = n_coalesce;
13066
13067 return 0;
13068error:
13069 for (i = 0; i < new_coalesce.n_rules; i++) {
13070 tmp_rule = &new_coalesce.rules[i];
13071 for (j = 0; j < tmp_rule->n_patterns; j++)
13072 kfree(tmp_rule->patterns[j].mask);
13073 kfree(tmp_rule->patterns);
13074 }
13075 kfree(new_coalesce.rules);
13076
13077 return err;
13078}
13079
Johannes Berge5497d72011-07-05 16:35:40 +020013080static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
13081{
13082 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13083 struct net_device *dev = info->user_ptr[1];
13084 struct wireless_dev *wdev = dev->ieee80211_ptr;
13085 struct nlattr *tb[NUM_NL80211_REKEY_DATA];
Sara Sharonf495acd2020-11-29 17:30:44 +020013086 struct cfg80211_gtk_rekey_data rekey_data = {};
Johannes Berge5497d72011-07-05 16:35:40 +020013087 int err;
13088
13089 if (!info->attrs[NL80211_ATTR_REKEY_DATA])
13090 return -EINVAL;
13091
Johannes Berg8cb08172019-04-26 14:07:28 +020013092 err = nla_parse_nested_deprecated(tb, MAX_NL80211_REKEY_DATA,
13093 info->attrs[NL80211_ATTR_REKEY_DATA],
13094 nl80211_rekey_policy, info->extack);
Johannes Berge5497d72011-07-05 16:35:40 +020013095 if (err)
13096 return err;
13097
Vladis Dronove785fa02017-09-13 00:21:21 +020013098 if (!tb[NL80211_REKEY_DATA_REPLAY_CTR] || !tb[NL80211_REKEY_DATA_KEK] ||
13099 !tb[NL80211_REKEY_DATA_KCK])
13100 return -EINVAL;
Nathan Errera093a48d2020-05-28 21:22:38 +020013101 if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN &&
13102 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK &&
13103 nla_len(tb[NL80211_REKEY_DATA_KEK]) == NL80211_KEK_EXT_LEN))
Johannes Berge5497d72011-07-05 16:35:40 +020013104 return -ERANGE;
Nathan Errera093a48d2020-05-28 21:22:38 +020013105 if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN &&
13106 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK &&
13107 nla_len(tb[NL80211_REKEY_DATA_KEK]) == NL80211_KCK_EXT_LEN))
Johannes Berge5497d72011-07-05 16:35:40 +020013108 return -ERANGE;
13109
Johannes Berg78f686c2014-09-10 22:28:06 +030013110 rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
13111 rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
13112 rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
Nathan Errera093a48d2020-05-28 21:22:38 +020013113 rekey_data.kek_len = nla_len(tb[NL80211_REKEY_DATA_KEK]);
13114 rekey_data.kck_len = nla_len(tb[NL80211_REKEY_DATA_KCK]);
13115 if (tb[NL80211_REKEY_DATA_AKM])
13116 rekey_data.akm = nla_get_u32(tb[NL80211_REKEY_DATA_AKM]);
Johannes Berge5497d72011-07-05 16:35:40 +020013117
13118 wdev_lock(wdev);
13119 if (!wdev->current_bss) {
13120 err = -ENOTCONN;
13121 goto out;
13122 }
13123
13124 if (!rdev->ops->set_rekey_data) {
13125 err = -EOPNOTSUPP;
13126 goto out;
13127 }
13128
Hila Gonene35e4d22012-06-27 17:19:42 +030013129 err = rdev_set_rekey_data(rdev, dev, &rekey_data);
Johannes Berge5497d72011-07-05 16:35:40 +020013130 out:
13131 wdev_unlock(wdev);
13132 return err;
13133}
13134
Johannes Berg28946da2011-11-04 11:18:12 +010013135static int nl80211_register_unexpected_frame(struct sk_buff *skb,
13136 struct genl_info *info)
13137{
13138 struct net_device *dev = info->user_ptr[1];
13139 struct wireless_dev *wdev = dev->ieee80211_ptr;
13140
13141 if (wdev->iftype != NL80211_IFTYPE_AP &&
13142 wdev->iftype != NL80211_IFTYPE_P2P_GO)
13143 return -EINVAL;
13144
Eric W. Biederman15e47302012-09-07 20:12:54 +000013145 if (wdev->ap_unexpected_nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010013146 return -EBUSY;
13147
Eric W. Biederman15e47302012-09-07 20:12:54 +000013148 wdev->ap_unexpected_nlportid = info->snd_portid;
Johannes Berg28946da2011-11-04 11:18:12 +010013149 return 0;
13150}
13151
Johannes Berg7f6cf312011-11-04 11:18:15 +010013152static int nl80211_probe_client(struct sk_buff *skb,
13153 struct genl_info *info)
13154{
13155 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13156 struct net_device *dev = info->user_ptr[1];
13157 struct wireless_dev *wdev = dev->ieee80211_ptr;
13158 struct sk_buff *msg;
13159 void *hdr;
13160 const u8 *addr;
13161 u64 cookie;
13162 int err;
13163
13164 if (wdev->iftype != NL80211_IFTYPE_AP &&
13165 wdev->iftype != NL80211_IFTYPE_P2P_GO)
13166 return -EOPNOTSUPP;
13167
13168 if (!info->attrs[NL80211_ATTR_MAC])
13169 return -EINVAL;
13170
13171 if (!rdev->ops->probe_client)
13172 return -EOPNOTSUPP;
13173
13174 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13175 if (!msg)
13176 return -ENOMEM;
13177
Eric W. Biederman15e47302012-09-07 20:12:54 +000013178 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg7f6cf312011-11-04 11:18:15 +010013179 NL80211_CMD_PROBE_CLIENT);
Dan Carpentercb35fba2013-08-14 14:50:01 +030013180 if (!hdr) {
13181 err = -ENOBUFS;
Johannes Berg7f6cf312011-11-04 11:18:15 +010013182 goto free_msg;
13183 }
13184
13185 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
13186
Hila Gonene35e4d22012-06-27 17:19:42 +030013187 err = rdev_probe_client(rdev, dev, addr, &cookie);
Johannes Berg7f6cf312011-11-04 11:18:15 +010013188 if (err)
13189 goto free_msg;
13190
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013191 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
13192 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013193 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010013194
13195 genlmsg_end(msg, hdr);
13196
13197 return genlmsg_reply(msg, info);
13198
13199 nla_put_failure:
13200 err = -ENOBUFS;
13201 free_msg:
13202 nlmsg_free(msg);
13203 return err;
13204}
13205
Johannes Berg5e760232011-11-04 11:18:17 +010013206static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
13207{
13208 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Ben Greear37c73b52012-10-26 14:49:25 -070013209 struct cfg80211_beacon_registration *reg, *nreg;
13210 int rv;
Johannes Berg5e760232011-11-04 11:18:17 +010013211
13212 if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
13213 return -EOPNOTSUPP;
13214
Ben Greear37c73b52012-10-26 14:49:25 -070013215 nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
13216 if (!nreg)
13217 return -ENOMEM;
Johannes Berg5e760232011-11-04 11:18:17 +010013218
Ben Greear37c73b52012-10-26 14:49:25 -070013219 /* First, check if already registered. */
13220 spin_lock_bh(&rdev->beacon_registrations_lock);
13221 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
13222 if (reg->nlportid == info->snd_portid) {
13223 rv = -EALREADY;
13224 goto out_err;
13225 }
13226 }
13227 /* Add it to the list */
13228 nreg->nlportid = info->snd_portid;
13229 list_add(&nreg->list, &rdev->beacon_registrations);
13230
13231 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010013232
13233 return 0;
Ben Greear37c73b52012-10-26 14:49:25 -070013234out_err:
13235 spin_unlock_bh(&rdev->beacon_registrations_lock);
13236 kfree(nreg);
13237 return rv;
Johannes Berg5e760232011-11-04 11:18:17 +010013238}
13239
Johannes Berg98104fde2012-06-16 00:19:54 +020013240static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
13241{
13242 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13243 struct wireless_dev *wdev = info->user_ptr[1];
13244 int err;
13245
13246 if (!rdev->ops->start_p2p_device)
13247 return -EOPNOTSUPP;
13248
13249 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
13250 return -EOPNOTSUPP;
13251
Arend Van Spriel73c7da32016-10-20 20:08:22 +010013252 if (wdev_running(wdev))
Johannes Berg98104fde2012-06-16 00:19:54 +020013253 return 0;
13254
Emmanuel Grumbach358ae882021-06-16 23:28:26 +030013255 if (rfkill_blocked(rdev->wiphy.rfkill))
Luciano Coelhob6a55012014-02-27 11:07:21 +020013256 return -ERFKILL;
Johannes Berg98104fde2012-06-16 00:19:54 +020013257
Johannes Bergeeb126e2012-10-23 15:16:50 +020013258 err = rdev_start_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020013259 if (err)
13260 return err;
13261
Arend Van Spriel73c7da32016-10-20 20:08:22 +010013262 wdev->is_running = true;
Johannes Berg98104fde2012-06-16 00:19:54 +020013263 rdev->opencount++;
Johannes Berg98104fde2012-06-16 00:19:54 +020013264
13265 return 0;
13266}
13267
13268static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
13269{
13270 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13271 struct wireless_dev *wdev = info->user_ptr[1];
13272
13273 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
13274 return -EOPNOTSUPP;
13275
13276 if (!rdev->ops->stop_p2p_device)
13277 return -EOPNOTSUPP;
13278
Johannes Bergf9f47522013-03-19 15:04:07 +010013279 cfg80211_stop_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020013280
13281 return 0;
13282}
13283
Ayala Bekercb3b7d82016-09-20 17:31:13 +030013284static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
13285{
13286 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13287 struct wireless_dev *wdev = info->user_ptr[1];
13288 struct cfg80211_nan_conf conf = {};
13289 int err;
13290
13291 if (wdev->iftype != NL80211_IFTYPE_NAN)
13292 return -EOPNOTSUPP;
13293
Johannes Bergeeb04a92016-11-21 13:55:48 +010013294 if (wdev_running(wdev))
Ayala Bekercb3b7d82016-09-20 17:31:13 +030013295 return -EEXIST;
13296
Emmanuel Grumbach358ae882021-06-16 23:28:26 +030013297 if (rfkill_blocked(rdev->wiphy.rfkill))
Ayala Bekercb3b7d82016-09-20 17:31:13 +030013298 return -ERFKILL;
13299
13300 if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
13301 return -EINVAL;
13302
Ayala Bekercb3b7d82016-09-20 17:31:13 +030013303 conf.master_pref =
13304 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
Ayala Bekercb3b7d82016-09-20 17:31:13 +030013305
Luca Coelho85859892017-02-08 15:00:34 +020013306 if (info->attrs[NL80211_ATTR_BANDS]) {
13307 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
13308
13309 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
13310 return -EOPNOTSUPP;
13311
13312 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
13313 return -EINVAL;
13314
13315 conf.bands = bands;
13316 }
Ayala Bekercb3b7d82016-09-20 17:31:13 +030013317
13318 err = rdev_start_nan(rdev, wdev, &conf);
13319 if (err)
13320 return err;
13321
Arend Van Spriel73c7da32016-10-20 20:08:22 +010013322 wdev->is_running = true;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030013323 rdev->opencount++;
13324
13325 return 0;
13326}
13327
13328static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
13329{
13330 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13331 struct wireless_dev *wdev = info->user_ptr[1];
13332
13333 if (wdev->iftype != NL80211_IFTYPE_NAN)
13334 return -EOPNOTSUPP;
13335
13336 cfg80211_stop_nan(rdev, wdev);
13337
13338 return 0;
13339}
13340
Ayala Bekera442b762016-09-20 17:31:15 +030013341static int validate_nan_filter(struct nlattr *filter_attr)
13342{
13343 struct nlattr *attr;
13344 int len = 0, n_entries = 0, rem;
13345
13346 nla_for_each_nested(attr, filter_attr, rem) {
13347 len += nla_len(attr);
13348 n_entries++;
13349 }
13350
13351 if (len >= U8_MAX)
13352 return -EINVAL;
13353
13354 return n_entries;
13355}
13356
13357static int handle_nan_filter(struct nlattr *attr_filter,
13358 struct cfg80211_nan_func *func,
13359 bool tx)
13360{
13361 struct nlattr *attr;
13362 int n_entries, rem, i;
13363 struct cfg80211_nan_func_filter *filter;
13364
13365 n_entries = validate_nan_filter(attr_filter);
13366 if (n_entries < 0)
13367 return n_entries;
13368
13369 BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters));
13370
13371 filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL);
13372 if (!filter)
13373 return -ENOMEM;
13374
13375 i = 0;
13376 nla_for_each_nested(attr, attr_filter, rem) {
Thomas Grafb15ca182016-10-26 10:53:16 +020013377 filter[i].filter = nla_memdup(attr, GFP_KERNEL);
Ayala Bekera442b762016-09-20 17:31:15 +030013378 filter[i].len = nla_len(attr);
13379 i++;
13380 }
13381 if (tx) {
13382 func->num_tx_filters = n_entries;
13383 func->tx_filters = filter;
13384 } else {
13385 func->num_rx_filters = n_entries;
13386 func->rx_filters = filter;
13387 }
13388
13389 return 0;
13390}
13391
13392static int nl80211_nan_add_func(struct sk_buff *skb,
13393 struct genl_info *info)
13394{
13395 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13396 struct wireless_dev *wdev = info->user_ptr[1];
13397 struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR], *func_attr;
13398 struct cfg80211_nan_func *func;
13399 struct sk_buff *msg = NULL;
13400 void *hdr = NULL;
13401 int err = 0;
13402
13403 if (wdev->iftype != NL80211_IFTYPE_NAN)
13404 return -EOPNOTSUPP;
13405
Arend Van Spriel73c7da32016-10-20 20:08:22 +010013406 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030013407 return -ENOTCONN;
13408
13409 if (!info->attrs[NL80211_ATTR_NAN_FUNC])
13410 return -EINVAL;
13411
Johannes Berg8cb08172019-04-26 14:07:28 +020013412 err = nla_parse_nested_deprecated(tb, NL80211_NAN_FUNC_ATTR_MAX,
13413 info->attrs[NL80211_ATTR_NAN_FUNC],
13414 nl80211_nan_func_policy,
13415 info->extack);
Ayala Bekera442b762016-09-20 17:31:15 +030013416 if (err)
13417 return err;
13418
13419 func = kzalloc(sizeof(*func), GFP_KERNEL);
13420 if (!func)
13421 return -ENOMEM;
13422
Johannes Bergb60ad342018-10-01 11:52:07 +020013423 func->cookie = cfg80211_assign_cookie(rdev);
Ayala Bekera442b762016-09-20 17:31:15 +030013424
Johannes Bergcb9abd42020-08-05 15:47:16 +020013425 if (!tb[NL80211_NAN_FUNC_TYPE]) {
Ayala Bekera442b762016-09-20 17:31:15 +030013426 err = -EINVAL;
13427 goto out;
13428 }
13429
13430
13431 func->type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]);
13432
13433 if (!tb[NL80211_NAN_FUNC_SERVICE_ID]) {
13434 err = -EINVAL;
13435 goto out;
13436 }
13437
13438 memcpy(func->service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]),
13439 sizeof(func->service_id));
13440
13441 func->close_range =
13442 nla_get_flag(tb[NL80211_NAN_FUNC_CLOSE_RANGE]);
13443
13444 if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) {
13445 func->serv_spec_info_len =
13446 nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
13447 func->serv_spec_info =
13448 kmemdup(nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]),
13449 func->serv_spec_info_len,
13450 GFP_KERNEL);
13451 if (!func->serv_spec_info) {
13452 err = -ENOMEM;
13453 goto out;
13454 }
13455 }
13456
13457 if (tb[NL80211_NAN_FUNC_TTL])
13458 func->ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]);
13459
13460 switch (func->type) {
13461 case NL80211_NAN_FUNC_PUBLISH:
13462 if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE]) {
13463 err = -EINVAL;
13464 goto out;
13465 }
13466
13467 func->publish_type =
13468 nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]);
13469 func->publish_bcast =
13470 nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]);
13471
13472 if ((!(func->publish_type & NL80211_NAN_SOLICITED_PUBLISH)) &&
13473 func->publish_bcast) {
13474 err = -EINVAL;
13475 goto out;
13476 }
13477 break;
13478 case NL80211_NAN_FUNC_SUBSCRIBE:
13479 func->subscribe_active =
13480 nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]);
13481 break;
13482 case NL80211_NAN_FUNC_FOLLOW_UP:
13483 if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] ||
Hao Chen3ea15452018-01-03 11:00:31 +080013484 !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] ||
13485 !tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]) {
Ayala Bekera442b762016-09-20 17:31:15 +030013486 err = -EINVAL;
13487 goto out;
13488 }
13489
13490 func->followup_id =
13491 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]);
13492 func->followup_reqid =
13493 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]);
13494 memcpy(func->followup_dest.addr,
13495 nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]),
13496 sizeof(func->followup_dest.addr));
13497 if (func->ttl) {
13498 err = -EINVAL;
13499 goto out;
13500 }
13501 break;
13502 default:
13503 err = -EINVAL;
13504 goto out;
13505 }
13506
13507 if (tb[NL80211_NAN_FUNC_SRF]) {
13508 struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
13509
Johannes Berg8cb08172019-04-26 14:07:28 +020013510 err = nla_parse_nested_deprecated(srf_tb,
13511 NL80211_NAN_SRF_ATTR_MAX,
13512 tb[NL80211_NAN_FUNC_SRF],
13513 nl80211_nan_srf_policy,
13514 info->extack);
Ayala Bekera442b762016-09-20 17:31:15 +030013515 if (err)
13516 goto out;
13517
13518 func->srf_include =
13519 nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]);
13520
13521 if (srf_tb[NL80211_NAN_SRF_BF]) {
13522 if (srf_tb[NL80211_NAN_SRF_MAC_ADDRS] ||
13523 !srf_tb[NL80211_NAN_SRF_BF_IDX]) {
13524 err = -EINVAL;
13525 goto out;
13526 }
13527
13528 func->srf_bf_len =
13529 nla_len(srf_tb[NL80211_NAN_SRF_BF]);
13530 func->srf_bf =
13531 kmemdup(nla_data(srf_tb[NL80211_NAN_SRF_BF]),
13532 func->srf_bf_len, GFP_KERNEL);
13533 if (!func->srf_bf) {
13534 err = -ENOMEM;
13535 goto out;
13536 }
13537
13538 func->srf_bf_idx =
13539 nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]);
13540 } else {
13541 struct nlattr *attr, *mac_attr =
13542 srf_tb[NL80211_NAN_SRF_MAC_ADDRS];
13543 int n_entries, rem, i = 0;
13544
13545 if (!mac_attr) {
13546 err = -EINVAL;
13547 goto out;
13548 }
13549
13550 n_entries = validate_acl_mac_addrs(mac_attr);
13551 if (n_entries <= 0) {
13552 err = -EINVAL;
13553 goto out;
13554 }
13555
13556 func->srf_num_macs = n_entries;
13557 func->srf_macs =
Kees Cook6396bb22018-06-12 14:03:40 -070013558 kcalloc(n_entries, sizeof(*func->srf_macs),
Ayala Bekera442b762016-09-20 17:31:15 +030013559 GFP_KERNEL);
13560 if (!func->srf_macs) {
13561 err = -ENOMEM;
13562 goto out;
13563 }
13564
13565 nla_for_each_nested(attr, mac_attr, rem)
13566 memcpy(func->srf_macs[i++].addr, nla_data(attr),
13567 sizeof(*func->srf_macs));
13568 }
13569 }
13570
13571 if (tb[NL80211_NAN_FUNC_TX_MATCH_FILTER]) {
13572 err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER],
13573 func, true);
13574 if (err)
13575 goto out;
13576 }
13577
13578 if (tb[NL80211_NAN_FUNC_RX_MATCH_FILTER]) {
13579 err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER],
13580 func, false);
13581 if (err)
13582 goto out;
13583 }
13584
13585 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13586 if (!msg) {
13587 err = -ENOMEM;
13588 goto out;
13589 }
13590
13591 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
13592 NL80211_CMD_ADD_NAN_FUNCTION);
13593 /* This can't really happen - we just allocated 4KB */
13594 if (WARN_ON(!hdr)) {
13595 err = -ENOMEM;
13596 goto out;
13597 }
13598
13599 err = rdev_add_nan_func(rdev, wdev, func);
13600out:
13601 if (err < 0) {
13602 cfg80211_free_nan_func(func);
13603 nlmsg_free(msg);
13604 return err;
13605 }
13606
13607 /* propagate the instance id and cookie to userspace */
13608 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, func->cookie,
13609 NL80211_ATTR_PAD))
13610 goto nla_put_failure;
13611
Michal Kubecekae0be8d2019-04-26 11:13:06 +020013612 func_attr = nla_nest_start_noflag(msg, NL80211_ATTR_NAN_FUNC);
Ayala Bekera442b762016-09-20 17:31:15 +030013613 if (!func_attr)
13614 goto nla_put_failure;
13615
13616 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID,
13617 func->instance_id))
13618 goto nla_put_failure;
13619
13620 nla_nest_end(msg, func_attr);
13621
13622 genlmsg_end(msg, hdr);
13623 return genlmsg_reply(msg, info);
13624
13625nla_put_failure:
13626 nlmsg_free(msg);
13627 return -ENOBUFS;
13628}
13629
13630static int nl80211_nan_del_func(struct sk_buff *skb,
13631 struct genl_info *info)
13632{
13633 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13634 struct wireless_dev *wdev = info->user_ptr[1];
13635 u64 cookie;
13636
13637 if (wdev->iftype != NL80211_IFTYPE_NAN)
13638 return -EOPNOTSUPP;
13639
Arend Van Spriel73c7da32016-10-20 20:08:22 +010013640 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030013641 return -ENOTCONN;
13642
13643 if (!info->attrs[NL80211_ATTR_COOKIE])
13644 return -EINVAL;
13645
Ayala Bekera442b762016-09-20 17:31:15 +030013646 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
13647
13648 rdev_del_nan_func(rdev, wdev, cookie);
13649
13650 return 0;
13651}
13652
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030013653static int nl80211_nan_change_config(struct sk_buff *skb,
13654 struct genl_info *info)
13655{
13656 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13657 struct wireless_dev *wdev = info->user_ptr[1];
13658 struct cfg80211_nan_conf conf = {};
13659 u32 changed = 0;
13660
13661 if (wdev->iftype != NL80211_IFTYPE_NAN)
13662 return -EOPNOTSUPP;
13663
Arend Van Spriel73c7da32016-10-20 20:08:22 +010013664 if (!wdev_running(wdev))
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030013665 return -ENOTCONN;
13666
13667 if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
13668 conf.master_pref =
13669 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
13670 if (conf.master_pref <= 1 || conf.master_pref == 255)
13671 return -EINVAL;
13672
13673 changed |= CFG80211_NAN_CONF_CHANGED_PREF;
13674 }
13675
Luca Coelho85859892017-02-08 15:00:34 +020013676 if (info->attrs[NL80211_ATTR_BANDS]) {
13677 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
13678
13679 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
13680 return -EOPNOTSUPP;
13681
13682 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
13683 return -EINVAL;
13684
13685 conf.bands = bands;
13686 changed |= CFG80211_NAN_CONF_CHANGED_BANDS;
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030013687 }
13688
13689 if (!changed)
13690 return -EINVAL;
13691
13692 return rdev_nan_change_conf(rdev, wdev, &conf, changed);
13693}
13694
Ayala Beker50bcd312016-09-20 17:31:17 +030013695void cfg80211_nan_match(struct wireless_dev *wdev,
13696 struct cfg80211_nan_match_params *match, gfp_t gfp)
13697{
13698 struct wiphy *wiphy = wdev->wiphy;
13699 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
13700 struct nlattr *match_attr, *local_func_attr, *peer_func_attr;
13701 struct sk_buff *msg;
13702 void *hdr;
13703
13704 if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr))
13705 return;
13706
13707 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
13708 if (!msg)
13709 return;
13710
13711 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH);
13712 if (!hdr) {
13713 nlmsg_free(msg);
13714 return;
13715 }
13716
13717 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13718 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13719 wdev->netdev->ifindex)) ||
13720 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13721 NL80211_ATTR_PAD))
13722 goto nla_put_failure;
13723
13724 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie,
13725 NL80211_ATTR_PAD) ||
13726 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr))
13727 goto nla_put_failure;
13728
Michal Kubecekae0be8d2019-04-26 11:13:06 +020013729 match_attr = nla_nest_start_noflag(msg, NL80211_ATTR_NAN_MATCH);
Ayala Beker50bcd312016-09-20 17:31:17 +030013730 if (!match_attr)
13731 goto nla_put_failure;
13732
Michal Kubecekae0be8d2019-04-26 11:13:06 +020013733 local_func_attr = nla_nest_start_noflag(msg,
13734 NL80211_NAN_MATCH_FUNC_LOCAL);
Ayala Beker50bcd312016-09-20 17:31:17 +030013735 if (!local_func_attr)
13736 goto nla_put_failure;
13737
13738 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id))
13739 goto nla_put_failure;
13740
13741 nla_nest_end(msg, local_func_attr);
13742
Michal Kubecekae0be8d2019-04-26 11:13:06 +020013743 peer_func_attr = nla_nest_start_noflag(msg,
13744 NL80211_NAN_MATCH_FUNC_PEER);
Ayala Beker50bcd312016-09-20 17:31:17 +030013745 if (!peer_func_attr)
13746 goto nla_put_failure;
13747
13748 if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) ||
13749 nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id))
13750 goto nla_put_failure;
13751
13752 if (match->info && match->info_len &&
13753 nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len,
13754 match->info))
13755 goto nla_put_failure;
13756
13757 nla_nest_end(msg, peer_func_attr);
13758 nla_nest_end(msg, match_attr);
13759 genlmsg_end(msg, hdr);
13760
13761 if (!wdev->owner_nlportid)
13762 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
13763 msg, 0, NL80211_MCGRP_NAN, gfp);
13764 else
13765 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
13766 wdev->owner_nlportid);
13767
13768 return;
13769
13770nla_put_failure:
13771 nlmsg_free(msg);
13772}
13773EXPORT_SYMBOL(cfg80211_nan_match);
13774
Ayala Beker368e5a72016-09-20 17:31:18 +030013775void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
13776 u8 inst_id,
13777 enum nl80211_nan_func_term_reason reason,
13778 u64 cookie, gfp_t gfp)
13779{
13780 struct wiphy *wiphy = wdev->wiphy;
13781 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
13782 struct sk_buff *msg;
13783 struct nlattr *func_attr;
13784 void *hdr;
13785
13786 if (WARN_ON(!inst_id))
13787 return;
13788
13789 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
13790 if (!msg)
13791 return;
13792
13793 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_NAN_FUNCTION);
13794 if (!hdr) {
13795 nlmsg_free(msg);
13796 return;
13797 }
13798
13799 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13800 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13801 wdev->netdev->ifindex)) ||
13802 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13803 NL80211_ATTR_PAD))
13804 goto nla_put_failure;
13805
13806 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
13807 NL80211_ATTR_PAD))
13808 goto nla_put_failure;
13809
Michal Kubecekae0be8d2019-04-26 11:13:06 +020013810 func_attr = nla_nest_start_noflag(msg, NL80211_ATTR_NAN_FUNC);
Ayala Beker368e5a72016-09-20 17:31:18 +030013811 if (!func_attr)
13812 goto nla_put_failure;
13813
13814 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, inst_id) ||
13815 nla_put_u8(msg, NL80211_NAN_FUNC_TERM_REASON, reason))
13816 goto nla_put_failure;
13817
13818 nla_nest_end(msg, func_attr);
13819 genlmsg_end(msg, hdr);
13820
13821 if (!wdev->owner_nlportid)
13822 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
13823 msg, 0, NL80211_MCGRP_NAN, gfp);
13824 else
13825 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
13826 wdev->owner_nlportid);
13827
13828 return;
13829
13830nla_put_failure:
13831 nlmsg_free(msg);
13832}
13833EXPORT_SYMBOL(cfg80211_nan_func_terminated);
13834
Johannes Berg3713b4e2013-02-14 16:19:38 +010013835static int nl80211_get_protocol_features(struct sk_buff *skb,
13836 struct genl_info *info)
13837{
13838 void *hdr;
13839 struct sk_buff *msg;
13840
13841 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13842 if (!msg)
13843 return -ENOMEM;
13844
13845 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
13846 NL80211_CMD_GET_PROTOCOL_FEATURES);
13847 if (!hdr)
13848 goto nla_put_failure;
13849
13850 if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
13851 NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
13852 goto nla_put_failure;
13853
13854 genlmsg_end(msg, hdr);
13855 return genlmsg_reply(msg, info);
13856
13857 nla_put_failure:
13858 kfree_skb(msg);
13859 return -ENOBUFS;
13860}
13861
Jouni Malinen355199e2013-02-27 17:14:27 +020013862static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
13863{
13864 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13865 struct cfg80211_update_ft_ies_params ft_params;
13866 struct net_device *dev = info->user_ptr[1];
13867
13868 if (!rdev->ops->update_ft_ies)
13869 return -EOPNOTSUPP;
13870
13871 if (!info->attrs[NL80211_ATTR_MDID] ||
Johannes Berg3d7af872018-10-02 10:00:08 +020013872 !info->attrs[NL80211_ATTR_IE])
Jouni Malinen355199e2013-02-27 17:14:27 +020013873 return -EINVAL;
13874
13875 memset(&ft_params, 0, sizeof(ft_params));
13876 ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
13877 ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
13878 ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
13879
13880 return rdev_update_ft_ies(rdev, dev, &ft_params);
13881}
13882
Arend van Spriel5de17982013-04-18 15:49:00 +020013883static int nl80211_crit_protocol_start(struct sk_buff *skb,
13884 struct genl_info *info)
13885{
13886 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13887 struct wireless_dev *wdev = info->user_ptr[1];
13888 enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
13889 u16 duration;
13890 int ret;
13891
13892 if (!rdev->ops->crit_proto_start)
13893 return -EOPNOTSUPP;
13894
13895 if (WARN_ON(!rdev->ops->crit_proto_stop))
13896 return -EINVAL;
13897
13898 if (rdev->crit_proto_nlportid)
13899 return -EBUSY;
13900
13901 /* determine protocol if provided */
13902 if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
13903 proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
13904
13905 if (proto >= NUM_NL80211_CRIT_PROTO)
13906 return -EINVAL;
13907
13908 /* timeout must be provided */
13909 if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
13910 return -EINVAL;
13911
13912 duration =
13913 nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
13914
Arend van Spriel5de17982013-04-18 15:49:00 +020013915 ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
13916 if (!ret)
13917 rdev->crit_proto_nlportid = info->snd_portid;
13918
13919 return ret;
13920}
13921
13922static int nl80211_crit_protocol_stop(struct sk_buff *skb,
13923 struct genl_info *info)
13924{
13925 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13926 struct wireless_dev *wdev = info->user_ptr[1];
13927
13928 if (!rdev->ops->crit_proto_stop)
13929 return -EOPNOTSUPP;
13930
13931 if (rdev->crit_proto_nlportid) {
13932 rdev->crit_proto_nlportid = 0;
13933 rdev_crit_proto_stop(rdev, wdev);
13934 }
13935 return 0;
13936}
13937
Johannes Berg901bb982019-05-28 10:56:03 +020013938static int nl80211_vendor_check_policy(const struct wiphy_vendor_command *vcmd,
13939 struct nlattr *attr,
13940 struct netlink_ext_ack *extack)
13941{
13942 if (vcmd->policy == VENDOR_CMD_RAW_DATA) {
13943 if (attr->nla_type & NLA_F_NESTED) {
13944 NL_SET_ERR_MSG_ATTR(extack, attr,
13945 "unexpected nested data");
13946 return -EINVAL;
13947 }
13948
13949 return 0;
13950 }
13951
13952 if (!(attr->nla_type & NLA_F_NESTED)) {
13953 NL_SET_ERR_MSG_ATTR(extack, attr, "expected nested data");
13954 return -EINVAL;
13955 }
13956
Michal Kubecek32d51092019-12-11 10:58:19 +010013957 return nla_validate_nested(attr, vcmd->maxattr, vcmd->policy, extack);
Johannes Berg901bb982019-05-28 10:56:03 +020013958}
13959
Johannes Bergad7e7182013-11-13 13:37:47 +010013960static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
13961{
13962 struct cfg80211_registered_device *rdev = info->user_ptr[0];
13963 struct wireless_dev *wdev =
Johannes Berga05829a2021-01-22 16:19:43 +010013964 __cfg80211_wdev_from_attrs(rdev, genl_info_net(info),
13965 info->attrs);
Johannes Bergad7e7182013-11-13 13:37:47 +010013966 int i, err;
13967 u32 vid, subcmd;
13968
13969 if (!rdev->wiphy.vendor_commands)
13970 return -EOPNOTSUPP;
13971
13972 if (IS_ERR(wdev)) {
13973 err = PTR_ERR(wdev);
13974 if (err != -EINVAL)
13975 return err;
13976 wdev = NULL;
13977 } else if (wdev->wiphy != &rdev->wiphy) {
13978 return -EINVAL;
13979 }
13980
13981 if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
13982 !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
13983 return -EINVAL;
13984
13985 vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
13986 subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
13987 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
13988 const struct wiphy_vendor_command *vcmd;
13989 void *data = NULL;
13990 int len = 0;
13991
13992 vcmd = &rdev->wiphy.vendor_commands[i];
13993
13994 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
13995 continue;
13996
13997 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
13998 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
13999 if (!wdev)
14000 return -EINVAL;
14001 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
14002 !wdev->netdev)
14003 return -EINVAL;
14004
14005 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Arend Van Spriel73c7da32016-10-20 20:08:22 +010014006 if (!wdev_running(wdev))
Johannes Bergad7e7182013-11-13 13:37:47 +010014007 return -ENETDOWN;
14008 }
14009 } else {
14010 wdev = NULL;
14011 }
14012
Julian Squires4052d3d2020-07-06 17:13:53 -040014013 if (!vcmd->doit)
14014 return -EOPNOTSUPP;
14015
Johannes Bergad7e7182013-11-13 13:37:47 +010014016 if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
14017 data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
14018 len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
Johannes Berg901bb982019-05-28 10:56:03 +020014019
14020 err = nl80211_vendor_check_policy(vcmd,
14021 info->attrs[NL80211_ATTR_VENDOR_DATA],
14022 info->extack);
14023 if (err)
14024 return err;
Johannes Bergad7e7182013-11-13 13:37:47 +010014025 }
14026
14027 rdev->cur_cmd_info = info;
Johannes Berg901bb982019-05-28 10:56:03 +020014028 err = vcmd->doit(&rdev->wiphy, wdev, data, len);
Johannes Bergad7e7182013-11-13 13:37:47 +010014029 rdev->cur_cmd_info = NULL;
14030 return err;
14031 }
14032
14033 return -EOPNOTSUPP;
14034}
14035
Johannes Berg7bdbe402015-08-15 22:39:49 +030014036static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
14037 struct netlink_callback *cb,
14038 struct cfg80211_registered_device **rdev,
14039 struct wireless_dev **wdev)
14040{
Johannes Berg50508d92019-07-29 16:31:09 +020014041 struct nlattr **attrbuf;
Johannes Berg7bdbe402015-08-15 22:39:49 +030014042 u32 vid, subcmd;
14043 unsigned int i;
14044 int vcmd_idx = -1;
14045 int err;
14046 void *data = NULL;
14047 unsigned int data_len = 0;
14048
Johannes Berg7bdbe402015-08-15 22:39:49 +030014049 if (cb->args[0]) {
14050 /* subtract the 1 again here */
14051 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
14052 struct wireless_dev *tmp;
14053
Johannes Bergea90e0d2017-03-15 14:26:04 +010014054 if (!wiphy)
14055 return -ENODEV;
Johannes Berg7bdbe402015-08-15 22:39:49 +030014056 *rdev = wiphy_to_rdev(wiphy);
14057 *wdev = NULL;
14058
14059 if (cb->args[1]) {
Johannes Berg53873f12016-05-03 16:52:04 +030014060 list_for_each_entry(tmp, &wiphy->wdev_list, list) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030014061 if (tmp->identifier == cb->args[1] - 1) {
14062 *wdev = tmp;
14063 break;
14064 }
14065 }
14066 }
14067
14068 /* keep rtnl locked in successful case */
14069 return 0;
14070 }
14071
Johannes Berg50508d92019-07-29 16:31:09 +020014072 attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
14073 if (!attrbuf)
14074 return -ENOMEM;
14075
Johannes Berg8cb08172019-04-26 14:07:28 +020014076 err = nlmsg_parse_deprecated(cb->nlh,
14077 GENL_HDRLEN + nl80211_fam.hdrsize,
14078 attrbuf, nl80211_fam.maxattr,
14079 nl80211_policy, NULL);
Johannes Berg7bdbe402015-08-15 22:39:49 +030014080 if (err)
Johannes Berg50508d92019-07-29 16:31:09 +020014081 goto out;
Johannes Berg7bdbe402015-08-15 22:39:49 +030014082
Johannes Bergc90c39d2016-10-24 14:40:01 +020014083 if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
Johannes Berg50508d92019-07-29 16:31:09 +020014084 !attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
14085 err = -EINVAL;
14086 goto out;
14087 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030014088
Johannes Berga05829a2021-01-22 16:19:43 +010014089 *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(skb->sk), attrbuf);
Johannes Berg7bdbe402015-08-15 22:39:49 +030014090 if (IS_ERR(*wdev))
14091 *wdev = NULL;
14092
Johannes Bergc90c39d2016-10-24 14:40:01 +020014093 *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg50508d92019-07-29 16:31:09 +020014094 if (IS_ERR(*rdev)) {
14095 err = PTR_ERR(*rdev);
14096 goto out;
14097 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030014098
Johannes Bergc90c39d2016-10-24 14:40:01 +020014099 vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
14100 subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030014101
14102 for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
14103 const struct wiphy_vendor_command *vcmd;
14104
14105 vcmd = &(*rdev)->wiphy.vendor_commands[i];
14106
14107 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
14108 continue;
14109
Johannes Berg50508d92019-07-29 16:31:09 +020014110 if (!vcmd->dumpit) {
14111 err = -EOPNOTSUPP;
14112 goto out;
14113 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030014114
14115 vcmd_idx = i;
14116 break;
14117 }
14118
Johannes Berg50508d92019-07-29 16:31:09 +020014119 if (vcmd_idx < 0) {
14120 err = -EOPNOTSUPP;
14121 goto out;
14122 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030014123
Johannes Bergc90c39d2016-10-24 14:40:01 +020014124 if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
14125 data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
14126 data_len = nla_len(attrbuf[NL80211_ATTR_VENDOR_DATA]);
Johannes Berg901bb982019-05-28 10:56:03 +020014127
14128 err = nl80211_vendor_check_policy(
14129 &(*rdev)->wiphy.vendor_commands[vcmd_idx],
14130 attrbuf[NL80211_ATTR_VENDOR_DATA],
14131 cb->extack);
14132 if (err)
Johannes Berg50508d92019-07-29 16:31:09 +020014133 goto out;
Johannes Berg7bdbe402015-08-15 22:39:49 +030014134 }
14135
14136 /* 0 is the first index - add 1 to parse only once */
14137 cb->args[0] = (*rdev)->wiphy_idx + 1;
14138 /* add 1 to know if it was NULL */
14139 cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
14140 cb->args[2] = vcmd_idx;
14141 cb->args[3] = (unsigned long)data;
14142 cb->args[4] = data_len;
14143
14144 /* keep rtnl locked in successful case */
Johannes Berg50508d92019-07-29 16:31:09 +020014145 err = 0;
14146out:
14147 kfree(attrbuf);
14148 return err;
Johannes Berg7bdbe402015-08-15 22:39:49 +030014149}
14150
14151static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
14152 struct netlink_callback *cb)
14153{
14154 struct cfg80211_registered_device *rdev;
14155 struct wireless_dev *wdev;
14156 unsigned int vcmd_idx;
14157 const struct wiphy_vendor_command *vcmd;
14158 void *data;
14159 int data_len;
14160 int err;
14161 struct nlattr *vendor_data;
14162
Johannes Bergea90e0d2017-03-15 14:26:04 +010014163 rtnl_lock();
Johannes Berg7bdbe402015-08-15 22:39:49 +030014164 err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
14165 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +010014166 goto out;
Johannes Berg7bdbe402015-08-15 22:39:49 +030014167
14168 vcmd_idx = cb->args[2];
14169 data = (void *)cb->args[3];
14170 data_len = cb->args[4];
14171 vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
14172
14173 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
14174 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
Johannes Bergea90e0d2017-03-15 14:26:04 +010014175 if (!wdev) {
14176 err = -EINVAL;
14177 goto out;
14178 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030014179 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
Johannes Bergea90e0d2017-03-15 14:26:04 +010014180 !wdev->netdev) {
14181 err = -EINVAL;
14182 goto out;
14183 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030014184
14185 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Johannes Bergea90e0d2017-03-15 14:26:04 +010014186 if (!wdev_running(wdev)) {
14187 err = -ENETDOWN;
14188 goto out;
14189 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030014190 }
14191 }
14192
14193 while (1) {
14194 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
14195 cb->nlh->nlmsg_seq, NLM_F_MULTI,
14196 NL80211_CMD_VENDOR);
14197 if (!hdr)
14198 break;
14199
14200 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014201 (wdev && nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
14202 wdev_id(wdev),
14203 NL80211_ATTR_PAD))) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030014204 genlmsg_cancel(skb, hdr);
14205 break;
14206 }
14207
Michal Kubecekae0be8d2019-04-26 11:13:06 +020014208 vendor_data = nla_nest_start_noflag(skb,
14209 NL80211_ATTR_VENDOR_DATA);
Johannes Berg7bdbe402015-08-15 22:39:49 +030014210 if (!vendor_data) {
14211 genlmsg_cancel(skb, hdr);
14212 break;
14213 }
14214
14215 err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
14216 (unsigned long *)&cb->args[5]);
14217 nla_nest_end(skb, vendor_data);
14218
14219 if (err == -ENOBUFS || err == -ENOENT) {
14220 genlmsg_cancel(skb, hdr);
14221 break;
Julian Squires9c167b22020-07-20 12:20:35 -023014222 } else if (err <= 0) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030014223 genlmsg_cancel(skb, hdr);
14224 goto out;
14225 }
14226
14227 genlmsg_end(skb, hdr);
14228 }
14229
14230 err = skb->len;
14231 out:
14232 rtnl_unlock();
14233 return err;
14234}
14235
Johannes Bergad7e7182013-11-13 13:37:47 +010014236struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
14237 enum nl80211_commands cmd,
14238 enum nl80211_attrs attr,
14239 int approxlen)
14240{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014241 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Bergad7e7182013-11-13 13:37:47 +010014242
14243 if (WARN_ON(!rdev->cur_cmd_info))
14244 return NULL;
14245
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020014246 return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
Johannes Bergad7e7182013-11-13 13:37:47 +010014247 rdev->cur_cmd_info->snd_portid,
14248 rdev->cur_cmd_info->snd_seq,
Johannes Berg567ffc32013-12-18 14:43:31 +010014249 cmd, attr, NULL, GFP_KERNEL);
Johannes Bergad7e7182013-11-13 13:37:47 +010014250}
14251EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
14252
14253int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
14254{
14255 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
14256 void *hdr = ((void **)skb->cb)[1];
14257 struct nlattr *data = ((void **)skb->cb)[2];
14258
Johannes Bergbd8c78e2014-07-30 14:55:26 +020014259 /* clear CB data for netlink core to own from now on */
14260 memset(skb->cb, 0, sizeof(skb->cb));
14261
Johannes Bergad7e7182013-11-13 13:37:47 +010014262 if (WARN_ON(!rdev->cur_cmd_info)) {
14263 kfree_skb(skb);
14264 return -EINVAL;
14265 }
14266
14267 nla_nest_end(skb, data);
14268 genlmsg_end(skb, hdr);
14269 return genlmsg_reply(skb, rdev->cur_cmd_info);
14270}
14271EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
14272
Johannes Berg55c1fdf2019-02-06 13:17:19 +020014273unsigned int cfg80211_vendor_cmd_get_sender(struct wiphy *wiphy)
14274{
14275 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
14276
14277 if (WARN_ON(!rdev->cur_cmd_info))
14278 return 0;
14279
14280 return rdev->cur_cmd_info->snd_portid;
14281}
14282EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_get_sender);
14283
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080014284static int nl80211_set_qos_map(struct sk_buff *skb,
14285 struct genl_info *info)
14286{
14287 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14288 struct cfg80211_qos_map *qos_map = NULL;
14289 struct net_device *dev = info->user_ptr[1];
14290 u8 *pos, len, num_des, des_len, des;
14291 int ret;
14292
14293 if (!rdev->ops->set_qos_map)
14294 return -EOPNOTSUPP;
14295
14296 if (info->attrs[NL80211_ATTR_QOS_MAP]) {
14297 pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
14298 len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
14299
Johannes Bergc8b82802020-08-19 08:56:43 +020014300 if (len % 2)
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080014301 return -EINVAL;
14302
14303 qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
14304 if (!qos_map)
14305 return -ENOMEM;
14306
14307 num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
14308 if (num_des) {
14309 des_len = num_des *
14310 sizeof(struct cfg80211_dscp_exception);
14311 memcpy(qos_map->dscp_exception, pos, des_len);
14312 qos_map->num_des = num_des;
14313 for (des = 0; des < num_des; des++) {
14314 if (qos_map->dscp_exception[des].up > 7) {
14315 kfree(qos_map);
14316 return -EINVAL;
14317 }
14318 }
14319 pos += des_len;
14320 }
14321 memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
14322 }
14323
14324 wdev_lock(dev->ieee80211_ptr);
14325 ret = nl80211_key_allowed(dev->ieee80211_ptr);
14326 if (!ret)
14327 ret = rdev_set_qos_map(rdev, dev, qos_map);
14328 wdev_unlock(dev->ieee80211_ptr);
14329
14330 kfree(qos_map);
14331 return ret;
14332}
14333
Johannes Berg960d01a2014-09-09 22:55:35 +030014334static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
14335{
14336 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14337 struct net_device *dev = info->user_ptr[1];
14338 struct wireless_dev *wdev = dev->ieee80211_ptr;
14339 const u8 *peer;
14340 u8 tsid, up;
14341 u16 admitted_time = 0;
14342 int err;
14343
Johannes Berg723e73a2014-10-22 09:25:06 +020014344 if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
Johannes Berg960d01a2014-09-09 22:55:35 +030014345 return -EOPNOTSUPP;
14346
14347 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
14348 !info->attrs[NL80211_ATTR_USER_PRIO])
14349 return -EINVAL;
14350
14351 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
Johannes Berg960d01a2014-09-09 22:55:35 +030014352 up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
Johannes Berg960d01a2014-09-09 22:55:35 +030014353
14354 /* WMM uses TIDs 0-7 even for TSPEC */
Johannes Berg723e73a2014-10-22 09:25:06 +020014355 if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
Johannes Berg960d01a2014-09-09 22:55:35 +030014356 /* TODO: handle 802.11 TSPEC/admission control
Johannes Berg723e73a2014-10-22 09:25:06 +020014357 * need more attributes for that (e.g. BA session requirement);
14358 * change the WMM adminssion test above to allow both then
Johannes Berg960d01a2014-09-09 22:55:35 +030014359 */
14360 return -EINVAL;
14361 }
14362
14363 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
14364
14365 if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
14366 admitted_time =
14367 nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
14368 if (!admitted_time)
14369 return -EINVAL;
14370 }
14371
14372 wdev_lock(wdev);
14373 switch (wdev->iftype) {
14374 case NL80211_IFTYPE_STATION:
14375 case NL80211_IFTYPE_P2P_CLIENT:
14376 if (wdev->current_bss)
14377 break;
14378 err = -ENOTCONN;
14379 goto out;
14380 default:
14381 err = -EOPNOTSUPP;
14382 goto out;
14383 }
14384
14385 err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
14386
14387 out:
14388 wdev_unlock(wdev);
14389 return err;
14390}
14391
14392static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
14393{
14394 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14395 struct net_device *dev = info->user_ptr[1];
14396 struct wireless_dev *wdev = dev->ieee80211_ptr;
14397 const u8 *peer;
14398 u8 tsid;
14399 int err;
14400
14401 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
14402 return -EINVAL;
14403
14404 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
14405 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
14406
14407 wdev_lock(wdev);
14408 err = rdev_del_tx_ts(rdev, dev, tsid, peer);
14409 wdev_unlock(wdev);
14410
14411 return err;
14412}
14413
Arik Nemtsov1057d352014-11-19 12:54:26 +020014414static int nl80211_tdls_channel_switch(struct sk_buff *skb,
14415 struct genl_info *info)
14416{
14417 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14418 struct net_device *dev = info->user_ptr[1];
14419 struct wireless_dev *wdev = dev->ieee80211_ptr;
14420 struct cfg80211_chan_def chandef = {};
14421 const u8 *addr;
14422 u8 oper_class;
14423 int err;
14424
14425 if (!rdev->ops->tdls_channel_switch ||
14426 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
14427 return -EOPNOTSUPP;
14428
14429 switch (dev->ieee80211_ptr->iftype) {
14430 case NL80211_IFTYPE_STATION:
14431 case NL80211_IFTYPE_P2P_CLIENT:
14432 break;
14433 default:
14434 return -EOPNOTSUPP;
14435 }
14436
14437 if (!info->attrs[NL80211_ATTR_MAC] ||
14438 !info->attrs[NL80211_ATTR_OPER_CLASS])
14439 return -EINVAL;
14440
14441 err = nl80211_parse_chandef(rdev, info, &chandef);
14442 if (err)
14443 return err;
14444
14445 /*
14446 * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012
14447 * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the
14448 * specification is not defined for them.
14449 */
Johannes Berg57fbcce2016-04-12 15:56:15 +020014450 if (chandef.chan->band == NL80211_BAND_2GHZ &&
Arik Nemtsov1057d352014-11-19 12:54:26 +020014451 chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
14452 chandef.width != NL80211_CHAN_WIDTH_20)
14453 return -EINVAL;
14454
14455 /* we will be active on the TDLS link */
Arik Nemtsov923b3522015-07-08 15:41:44 +030014456 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
14457 wdev->iftype))
Arik Nemtsov1057d352014-11-19 12:54:26 +020014458 return -EINVAL;
14459
14460 /* don't allow switching to DFS channels */
14461 if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype))
14462 return -EINVAL;
14463
14464 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
14465 oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]);
14466
14467 wdev_lock(wdev);
14468 err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef);
14469 wdev_unlock(wdev);
14470
14471 return err;
14472}
14473
14474static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
14475 struct genl_info *info)
14476{
14477 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14478 struct net_device *dev = info->user_ptr[1];
14479 struct wireless_dev *wdev = dev->ieee80211_ptr;
14480 const u8 *addr;
14481
14482 if (!rdev->ops->tdls_channel_switch ||
14483 !rdev->ops->tdls_cancel_channel_switch ||
14484 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
14485 return -EOPNOTSUPP;
14486
14487 switch (dev->ieee80211_ptr->iftype) {
14488 case NL80211_IFTYPE_STATION:
14489 case NL80211_IFTYPE_P2P_CLIENT:
14490 break;
14491 default:
14492 return -EOPNOTSUPP;
14493 }
14494
14495 if (!info->attrs[NL80211_ATTR_MAC])
14496 return -EINVAL;
14497
14498 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
14499
14500 wdev_lock(wdev);
14501 rdev_tdls_cancel_channel_switch(rdev, dev, addr);
14502 wdev_unlock(wdev);
14503
14504 return 0;
14505}
14506
Michael Braunce0ce132016-10-10 19:12:22 +020014507static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
14508 struct genl_info *info)
14509{
14510 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14511 struct net_device *dev = info->user_ptr[1];
14512 struct wireless_dev *wdev = dev->ieee80211_ptr;
14513 const struct nlattr *nla;
14514 bool enabled;
14515
Michael Braunce0ce132016-10-10 19:12:22 +020014516 if (!rdev->ops->set_multicast_to_unicast)
14517 return -EOPNOTSUPP;
14518
14519 if (wdev->iftype != NL80211_IFTYPE_AP &&
14520 wdev->iftype != NL80211_IFTYPE_P2P_GO)
14521 return -EOPNOTSUPP;
14522
14523 nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
14524 enabled = nla_get_flag(nla);
14525
14526 return rdev_set_multicast_to_unicast(rdev, dev, enabled);
14527}
14528
Avraham Stern3a00df52017-06-09 13:08:43 +010014529static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
14530{
14531 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14532 struct net_device *dev = info->user_ptr[1];
14533 struct wireless_dev *wdev = dev->ieee80211_ptr;
14534 struct cfg80211_pmk_conf pmk_conf = {};
14535 int ret;
14536
14537 if (wdev->iftype != NL80211_IFTYPE_STATION &&
14538 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
14539 return -EOPNOTSUPP;
14540
14541 if (!wiphy_ext_feature_isset(&rdev->wiphy,
14542 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
14543 return -EOPNOTSUPP;
14544
14545 if (!info->attrs[NL80211_ATTR_MAC] || !info->attrs[NL80211_ATTR_PMK])
14546 return -EINVAL;
14547
14548 wdev_lock(wdev);
14549 if (!wdev->current_bss) {
14550 ret = -ENOTCONN;
14551 goto out;
14552 }
14553
14554 pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
14555 if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) {
14556 ret = -EINVAL;
14557 goto out;
14558 }
14559
14560 pmk_conf.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
14561 pmk_conf.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
14562 if (pmk_conf.pmk_len != WLAN_PMK_LEN &&
14563 pmk_conf.pmk_len != WLAN_PMK_LEN_SUITE_B_192) {
14564 ret = -EINVAL;
14565 goto out;
14566 }
14567
Johannes Bergcb9abd42020-08-05 15:47:16 +020014568 if (info->attrs[NL80211_ATTR_PMKR0_NAME])
Avraham Stern3a00df52017-06-09 13:08:43 +010014569 pmk_conf.pmk_r0_name =
14570 nla_data(info->attrs[NL80211_ATTR_PMKR0_NAME]);
Avraham Stern3a00df52017-06-09 13:08:43 +010014571
14572 ret = rdev_set_pmk(rdev, dev, &pmk_conf);
14573out:
14574 wdev_unlock(wdev);
14575 return ret;
14576}
14577
14578static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
14579{
14580 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14581 struct net_device *dev = info->user_ptr[1];
14582 struct wireless_dev *wdev = dev->ieee80211_ptr;
14583 const u8 *aa;
14584 int ret;
14585
14586 if (wdev->iftype != NL80211_IFTYPE_STATION &&
14587 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
14588 return -EOPNOTSUPP;
14589
14590 if (!wiphy_ext_feature_isset(&rdev->wiphy,
14591 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
14592 return -EOPNOTSUPP;
14593
14594 if (!info->attrs[NL80211_ATTR_MAC])
14595 return -EINVAL;
14596
14597 wdev_lock(wdev);
14598 aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
14599 ret = rdev_del_pmk(rdev, dev, aa);
14600 wdev_unlock(wdev);
14601
14602 return ret;
14603}
14604
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020014605static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info)
14606{
14607 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14608 struct net_device *dev = info->user_ptr[1];
14609 struct cfg80211_external_auth_params params;
14610
Srinivas Dasaridb8d93a2018-02-02 11:15:27 +020014611 if (!rdev->ops->external_auth)
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020014612 return -EOPNOTSUPP;
14613
Srinivas Dasarife494372019-01-23 18:06:56 +053014614 if (!info->attrs[NL80211_ATTR_SSID] &&
14615 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
14616 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020014617 return -EINVAL;
14618
14619 if (!info->attrs[NL80211_ATTR_BSSID])
14620 return -EINVAL;
14621
14622 if (!info->attrs[NL80211_ATTR_STATUS_CODE])
14623 return -EINVAL;
14624
14625 memset(&params, 0, sizeof(params));
14626
Srinivas Dasarife494372019-01-23 18:06:56 +053014627 if (info->attrs[NL80211_ATTR_SSID]) {
14628 params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
Johannes Bergcb9abd42020-08-05 15:47:16 +020014629 if (params.ssid.ssid_len == 0)
Srinivas Dasarife494372019-01-23 18:06:56 +053014630 return -EINVAL;
14631 memcpy(params.ssid.ssid,
14632 nla_data(info->attrs[NL80211_ATTR_SSID]),
14633 params.ssid.ssid_len);
14634 }
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020014635
14636 memcpy(params.bssid, nla_data(info->attrs[NL80211_ATTR_BSSID]),
14637 ETH_ALEN);
14638
14639 params.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
14640
Srinivas Dasarife494372019-01-23 18:06:56 +053014641 if (info->attrs[NL80211_ATTR_PMKID])
14642 params.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
14643
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020014644 return rdev_external_auth(rdev, dev, &params);
14645}
14646
Denis Kenzior2576a9a2018-03-26 12:52:42 -050014647static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
14648{
Markus Theildca9ca22020-05-08 16:42:00 +020014649 bool dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
Denis Kenzior2576a9a2018-03-26 12:52:42 -050014650 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14651 struct net_device *dev = info->user_ptr[1];
14652 struct wireless_dev *wdev = dev->ieee80211_ptr;
14653 const u8 *buf;
14654 size_t len;
14655 u8 *dest;
14656 u16 proto;
14657 bool noencrypt;
Markus Theildca9ca22020-05-08 16:42:00 +020014658 u64 cookie = 0;
Denis Kenzior2576a9a2018-03-26 12:52:42 -050014659 int err;
14660
14661 if (!wiphy_ext_feature_isset(&rdev->wiphy,
14662 NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
14663 return -EOPNOTSUPP;
14664
14665 if (!rdev->ops->tx_control_port)
14666 return -EOPNOTSUPP;
14667
14668 if (!info->attrs[NL80211_ATTR_FRAME] ||
14669 !info->attrs[NL80211_ATTR_MAC] ||
14670 !info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
14671 GENL_SET_ERR_MSG(info, "Frame, MAC or ethertype missing");
14672 return -EINVAL;
14673 }
14674
14675 wdev_lock(wdev);
14676
14677 switch (wdev->iftype) {
14678 case NL80211_IFTYPE_AP:
14679 case NL80211_IFTYPE_P2P_GO:
14680 case NL80211_IFTYPE_MESH_POINT:
14681 break;
14682 case NL80211_IFTYPE_ADHOC:
14683 case NL80211_IFTYPE_STATION:
14684 case NL80211_IFTYPE_P2P_CLIENT:
14685 if (wdev->current_bss)
14686 break;
14687 err = -ENOTCONN;
14688 goto out;
14689 default:
14690 err = -EOPNOTSUPP;
14691 goto out;
14692 }
14693
14694 wdev_unlock(wdev);
14695
14696 buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
14697 len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
14698 dest = nla_data(info->attrs[NL80211_ATTR_MAC]);
14699 proto = nla_get_u16(info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
14700 noencrypt =
14701 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);
14702
Markus Theildca9ca22020-05-08 16:42:00 +020014703 err = rdev_tx_control_port(rdev, dev, buf, len,
14704 dest, cpu_to_be16(proto), noencrypt,
14705 dont_wait_for_ack ? NULL : &cookie);
14706 if (!err && !dont_wait_for_ack)
14707 nl_set_extack_cookie_u64(info->extack, cookie);
14708 return err;
Denis Kenzior2576a9a2018-03-26 12:52:42 -050014709 out:
14710 wdev_unlock(wdev);
14711 return err;
14712}
14713
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070014714static int nl80211_get_ftm_responder_stats(struct sk_buff *skb,
14715 struct genl_info *info)
14716{
14717 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14718 struct net_device *dev = info->user_ptr[1];
14719 struct wireless_dev *wdev = dev->ieee80211_ptr;
14720 struct cfg80211_ftm_responder_stats ftm_stats = {};
14721 struct sk_buff *msg;
14722 void *hdr;
14723 struct nlattr *ftm_stats_attr;
14724 int err;
14725
14726 if (wdev->iftype != NL80211_IFTYPE_AP || !wdev->beacon_interval)
14727 return -EOPNOTSUPP;
14728
14729 err = rdev_get_ftm_responder_stats(rdev, dev, &ftm_stats);
14730 if (err)
14731 return err;
14732
14733 if (!ftm_stats.filled)
14734 return -ENODATA;
14735
14736 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
14737 if (!msg)
14738 return -ENOMEM;
14739
14740 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
14741 NL80211_CMD_GET_FTM_RESPONDER_STATS);
14742 if (!hdr)
Navid Emamdoost1399c592019-10-04 14:42:19 -050014743 goto nla_put_failure;
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070014744
14745 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
14746 goto nla_put_failure;
14747
Michal Kubecekae0be8d2019-04-26 11:13:06 +020014748 ftm_stats_attr = nla_nest_start_noflag(msg,
14749 NL80211_ATTR_FTM_RESPONDER_STATS);
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070014750 if (!ftm_stats_attr)
14751 goto nla_put_failure;
14752
14753#define SET_FTM(field, name, type) \
14754 do { if ((ftm_stats.filled & BIT(NL80211_FTM_STATS_ ## name)) && \
14755 nla_put_ ## type(msg, NL80211_FTM_STATS_ ## name, \
14756 ftm_stats.field)) \
14757 goto nla_put_failure; } while (0)
14758#define SET_FTM_U64(field, name) \
14759 do { if ((ftm_stats.filled & BIT(NL80211_FTM_STATS_ ## name)) && \
14760 nla_put_u64_64bit(msg, NL80211_FTM_STATS_ ## name, \
14761 ftm_stats.field, NL80211_FTM_STATS_PAD)) \
14762 goto nla_put_failure; } while (0)
14763
14764 SET_FTM(success_num, SUCCESS_NUM, u32);
14765 SET_FTM(partial_num, PARTIAL_NUM, u32);
14766 SET_FTM(failed_num, FAILED_NUM, u32);
14767 SET_FTM(asap_num, ASAP_NUM, u32);
14768 SET_FTM(non_asap_num, NON_ASAP_NUM, u32);
14769 SET_FTM_U64(total_duration_ms, TOTAL_DURATION_MSEC);
14770 SET_FTM(unknown_triggers_num, UNKNOWN_TRIGGERS_NUM, u32);
14771 SET_FTM(reschedule_requests_num, RESCHEDULE_REQUESTS_NUM, u32);
14772 SET_FTM(out_of_window_triggers_num, OUT_OF_WINDOW_TRIGGERS_NUM, u32);
14773#undef SET_FTM
14774
14775 nla_nest_end(msg, ftm_stats_attr);
14776
14777 genlmsg_end(msg, hdr);
14778 return genlmsg_reply(msg, info);
14779
14780nla_put_failure:
14781 nlmsg_free(msg);
14782 return -ENOBUFS;
14783}
14784
Sunil Duttcb74e972019-02-20 16:18:07 +053014785static int nl80211_update_owe_info(struct sk_buff *skb, struct genl_info *info)
14786{
14787 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14788 struct cfg80211_update_owe_info owe_info;
14789 struct net_device *dev = info->user_ptr[1];
14790
14791 if (!rdev->ops->update_owe_info)
14792 return -EOPNOTSUPP;
14793
14794 if (!info->attrs[NL80211_ATTR_STATUS_CODE] ||
14795 !info->attrs[NL80211_ATTR_MAC])
14796 return -EINVAL;
14797
14798 memset(&owe_info, 0, sizeof(owe_info));
14799 owe_info.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
14800 nla_memcpy(owe_info.peer, info->attrs[NL80211_ATTR_MAC], ETH_ALEN);
14801
14802 if (info->attrs[NL80211_ATTR_IE]) {
14803 owe_info.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
14804 owe_info.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
14805 }
14806
14807 return rdev_update_owe_info(rdev, dev, &owe_info);
14808}
14809
Rajkumar Manoharan5ab92e72019-04-11 13:47:24 -070014810static int nl80211_probe_mesh_link(struct sk_buff *skb, struct genl_info *info)
14811{
14812 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14813 struct net_device *dev = info->user_ptr[1];
14814 struct wireless_dev *wdev = dev->ieee80211_ptr;
14815 struct station_info sinfo = {};
14816 const u8 *buf;
14817 size_t len;
14818 u8 *dest;
14819 int err;
14820
14821 if (!rdev->ops->probe_mesh_link || !rdev->ops->get_station)
14822 return -EOPNOTSUPP;
14823
14824 if (!info->attrs[NL80211_ATTR_MAC] ||
14825 !info->attrs[NL80211_ATTR_FRAME]) {
14826 GENL_SET_ERR_MSG(info, "Frame or MAC missing");
14827 return -EINVAL;
14828 }
14829
14830 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
14831 return -EOPNOTSUPP;
14832
14833 dest = nla_data(info->attrs[NL80211_ATTR_MAC]);
14834 buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
14835 len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
14836
14837 if (len < sizeof(struct ethhdr))
14838 return -EINVAL;
14839
14840 if (!ether_addr_equal(buf, dest) || is_multicast_ether_addr(buf) ||
14841 !ether_addr_equal(buf + ETH_ALEN, dev->dev_addr))
14842 return -EINVAL;
14843
14844 err = rdev_get_station(rdev, dev, dest, &sinfo);
14845 if (err)
14846 return err;
14847
Felix Fietkau2a279b342020-01-08 18:06:29 +010014848 cfg80211_sinfo_release_content(&sinfo);
14849
Rajkumar Manoharan5ab92e72019-04-11 13:47:24 -070014850 return rdev_probe_mesh_link(rdev, dev, dest, buf, len);
14851}
14852
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014853static int parse_tid_conf(struct cfg80211_registered_device *rdev,
14854 struct nlattr *attrs[], struct net_device *dev,
Johannes Berg3710a8a2020-02-24 11:34:25 +010014855 struct cfg80211_tid_cfg *tid_conf,
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014856 struct genl_info *info, const u8 *peer)
14857{
14858 struct netlink_ext_ack *extack = info->extack;
Johannes Berg3710a8a2020-02-24 11:34:25 +010014859 u64 mask;
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014860 int err;
14861
14862 if (!attrs[NL80211_TID_CONFIG_ATTR_TIDS])
14863 return -EINVAL;
14864
14865 tid_conf->config_override =
14866 nla_get_flag(attrs[NL80211_TID_CONFIG_ATTR_OVERRIDE]);
Johannes Berg3710a8a2020-02-24 11:34:25 +010014867 tid_conf->tids = nla_get_u16(attrs[NL80211_TID_CONFIG_ATTR_TIDS]);
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014868
14869 if (tid_conf->config_override) {
14870 if (rdev->ops->reset_tid_config) {
14871 err = rdev_reset_tid_config(rdev, dev, peer,
Johannes Berg3710a8a2020-02-24 11:34:25 +010014872 tid_conf->tids);
Sergey Matyukevichc0336952020-04-24 14:29:04 +030014873 if (err)
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014874 return err;
14875 } else {
14876 return -EINVAL;
14877 }
14878 }
14879
14880 if (attrs[NL80211_TID_CONFIG_ATTR_NOACK]) {
Johannes Berg3710a8a2020-02-24 11:34:25 +010014881 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_NOACK);
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014882 tid_conf->noack =
14883 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_NOACK]);
14884 }
14885
Tamizh chelvam6a21d162020-01-20 13:21:23 +053014886 if (attrs[NL80211_TID_CONFIG_ATTR_RETRY_SHORT]) {
14887 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_RETRY_SHORT);
14888 tid_conf->retry_short =
14889 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_RETRY_SHORT]);
14890
14891 if (tid_conf->retry_short > rdev->wiphy.max_data_retry_count)
14892 return -EINVAL;
14893 }
14894
14895 if (attrs[NL80211_TID_CONFIG_ATTR_RETRY_LONG]) {
14896 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG);
14897 tid_conf->retry_long =
14898 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_RETRY_LONG]);
14899
14900 if (tid_conf->retry_long > rdev->wiphy.max_data_retry_count)
14901 return -EINVAL;
14902 }
14903
Tamizh chelvamade274b2020-01-20 13:21:24 +053014904 if (attrs[NL80211_TID_CONFIG_ATTR_AMPDU_CTRL]) {
14905 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL);
14906 tid_conf->ampdu =
14907 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_AMPDU_CTRL]);
14908 }
14909
Tamizh chelvam04f7d142020-01-20 13:21:25 +053014910 if (attrs[NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL]) {
14911 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL);
14912 tid_conf->rtscts =
14913 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL]);
14914 }
14915
Sergey Matyukevich33462e62020-04-24 14:29:03 +030014916 if (attrs[NL80211_TID_CONFIG_ATTR_AMSDU_CTRL]) {
14917 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_AMSDU_CTRL);
14918 tid_conf->amsdu =
14919 nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_AMSDU_CTRL]);
14920 }
14921
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +053014922 if (attrs[NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE]) {
14923 u32 idx = NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE, attr;
14924
14925 tid_conf->txrate_type = nla_get_u8(attrs[idx]);
14926
14927 if (tid_conf->txrate_type != NL80211_TX_RATE_AUTOMATIC) {
14928 attr = NL80211_TID_CONFIG_ATTR_TX_RATE;
14929 err = nl80211_parse_tx_bitrate_mask(info, attrs, attr,
Rajkumar Manoharan857b34c2020-10-16 13:15:26 -070014930 &tid_conf->txrate_mask, dev,
14931 true);
Tamizh Chelvam9a5f6482020-05-13 13:41:44 +053014932 if (err)
14933 return err;
14934
14935 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_TX_RATE);
14936 }
14937 tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE);
14938 }
14939
Johannes Berg3710a8a2020-02-24 11:34:25 +010014940 if (peer)
14941 mask = rdev->wiphy.tid_config_support.peer;
14942 else
14943 mask = rdev->wiphy.tid_config_support.vif;
14944
14945 if (tid_conf->mask & ~mask) {
14946 NL_SET_ERR_MSG(extack, "unsupported TID configuration");
14947 return -ENOTSUPP;
14948 }
14949
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014950 return 0;
14951}
14952
14953static int nl80211_set_tid_config(struct sk_buff *skb,
14954 struct genl_info *info)
14955{
14956 struct cfg80211_registered_device *rdev = info->user_ptr[0];
14957 struct nlattr *attrs[NL80211_TID_CONFIG_ATTR_MAX + 1];
14958 struct net_device *dev = info->user_ptr[1];
Johannes Berg3710a8a2020-02-24 11:34:25 +010014959 struct cfg80211_tid_config *tid_config;
Tamizh chelvam77f576d2020-01-20 13:21:22 +053014960 struct nlattr *tid;
14961 int conf_idx = 0, rem_conf;
14962 int ret = -EINVAL;
14963 u32 num_conf = 0;
14964
14965 if (!info->attrs[NL80211_ATTR_TID_CONFIG])
14966 return -EINVAL;
14967
14968 if (!rdev->ops->set_tid_config)
14969 return -EOPNOTSUPP;
14970
14971 nla_for_each_nested(tid, info->attrs[NL80211_ATTR_TID_CONFIG],
14972 rem_conf)
14973 num_conf++;
14974
14975 tid_config = kzalloc(struct_size(tid_config, tid_conf, num_conf),
14976 GFP_KERNEL);
14977 if (!tid_config)
14978 return -ENOMEM;
14979
14980 tid_config->n_tid_conf = num_conf;
14981
14982 if (info->attrs[NL80211_ATTR_MAC])
14983 tid_config->peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
14984
14985 nla_for_each_nested(tid, info->attrs[NL80211_ATTR_TID_CONFIG],
14986 rem_conf) {
14987 ret = nla_parse_nested(attrs, NL80211_TID_CONFIG_ATTR_MAX,
14988 tid, NULL, NULL);
14989
14990 if (ret)
14991 goto bad_tid_conf;
14992
14993 ret = parse_tid_conf(rdev, attrs, dev,
14994 &tid_config->tid_conf[conf_idx],
14995 info, tid_config->peer);
14996 if (ret)
14997 goto bad_tid_conf;
14998
14999 conf_idx++;
15000 }
15001
15002 ret = rdev_set_tid_config(rdev, dev, tid_config);
15003
15004bad_tid_conf:
15005 kfree(tid_config);
15006 return ret;
15007}
15008
John Crispin0d2ab3ae2021-07-02 19:44:07 +020015009static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
15010{
15011 struct cfg80211_registered_device *rdev = info->user_ptr[0];
15012 struct cfg80211_color_change_settings params = {};
15013 struct net_device *dev = info->user_ptr[1];
15014 struct wireless_dev *wdev = dev->ieee80211_ptr;
15015 struct nlattr **tb;
15016 u16 offset;
15017 int err;
15018
15019 if (!rdev->ops->color_change)
15020 return -EOPNOTSUPP;
15021
15022 if (!wiphy_ext_feature_isset(&rdev->wiphy,
15023 NL80211_EXT_FEATURE_BSS_COLOR))
15024 return -EOPNOTSUPP;
15025
15026 if (wdev->iftype != NL80211_IFTYPE_AP)
15027 return -EOPNOTSUPP;
15028
15029 if (!info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT] ||
15030 !info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR] ||
15031 !info->attrs[NL80211_ATTR_COLOR_CHANGE_ELEMS])
15032 return -EINVAL;
15033
15034 params.count = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT]);
15035 params.color = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR]);
15036
15037 err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_next);
15038 if (err)
15039 return err;
15040
15041 tb = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*tb), GFP_KERNEL);
15042 if (!tb)
15043 return -ENOMEM;
15044
15045 err = nla_parse_nested(tb, NL80211_ATTR_MAX,
15046 info->attrs[NL80211_ATTR_COLOR_CHANGE_ELEMS],
15047 nl80211_policy, info->extack);
15048 if (err)
15049 goto out;
15050
15051 err = nl80211_parse_beacon(rdev, tb, &params.beacon_color_change);
15052 if (err)
15053 goto out;
15054
15055 if (!tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]) {
15056 err = -EINVAL;
15057 goto out;
15058 }
15059
15060 if (nla_len(tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]) != sizeof(u16)) {
15061 err = -EINVAL;
15062 goto out;
15063 }
15064
15065 offset = nla_get_u16(tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]);
15066 if (offset >= params.beacon_color_change.tail_len) {
15067 err = -EINVAL;
15068 goto out;
15069 }
15070
15071 if (params.beacon_color_change.tail[offset] != params.count) {
15072 err = -EINVAL;
15073 goto out;
15074 }
15075
15076 params.counter_offset_beacon = offset;
15077
15078 if (tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]) {
15079 if (nla_len(tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]) !=
15080 sizeof(u16)) {
15081 err = -EINVAL;
15082 goto out;
15083 }
15084
15085 offset = nla_get_u16(tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]);
15086 if (offset >= params.beacon_color_change.probe_resp_len) {
15087 err = -EINVAL;
15088 goto out;
15089 }
15090
15091 if (params.beacon_color_change.probe_resp[offset] !=
15092 params.count) {
15093 err = -EINVAL;
15094 goto out;
15095 }
15096
15097 params.counter_offset_presp = offset;
15098 }
15099
15100 wdev_lock(wdev);
15101 err = rdev_color_change(rdev, dev, &params);
15102 wdev_unlock(wdev);
15103
15104out:
John Crispindc1e3cb2021-09-15 19:54:34 -070015105 kfree(params.beacon_next.mbssid_ies);
15106 kfree(params.beacon_color_change.mbssid_ies);
John Crispin0d2ab3ae2021-07-02 19:44:07 +020015107 kfree(tb);
15108 return err;
15109}
15110
Subrat Mishrae3067842021-09-15 11:22:23 +053015111static int nl80211_set_fils_aad(struct sk_buff *skb,
15112 struct genl_info *info)
15113{
15114 struct cfg80211_registered_device *rdev = info->user_ptr[0];
15115 struct net_device *dev = info->user_ptr[1];
15116 struct cfg80211_fils_aad fils_aad = {};
15117 u8 *nonces;
15118
15119 if (!info->attrs[NL80211_ATTR_MAC] ||
15120 !info->attrs[NL80211_ATTR_FILS_KEK] ||
15121 !info->attrs[NL80211_ATTR_FILS_NONCES])
15122 return -EINVAL;
15123
15124 fils_aad.macaddr = nla_data(info->attrs[NL80211_ATTR_MAC]);
15125 fils_aad.kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
15126 fils_aad.kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
15127 nonces = nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
15128 fils_aad.snonce = nonces;
15129 fils_aad.anonce = nonces + FILS_NONCE_LEN;
15130
15131 return rdev_set_fils_aad(rdev, dev, &fils_aad);
15132}
15133
Johannes Berg4c476992010-10-04 21:36:35 +020015134#define NL80211_FLAG_NEED_WIPHY 0x01
15135#define NL80211_FLAG_NEED_NETDEV 0x02
15136#define NL80211_FLAG_NEED_RTNL 0x04
Johannes Berg41265712010-10-04 21:14:05 +020015137#define NL80211_FLAG_CHECK_NETDEV_UP 0x08
15138#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
15139 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg1bf614e2012-06-15 15:23:36 +020015140#define NL80211_FLAG_NEED_WDEV 0x10
Johannes Berg98104fde2012-06-16 00:19:54 +020015141/* If a netdev is associated, it must be UP, P2P must be started */
Johannes Berg1bf614e2012-06-15 15:23:36 +020015142#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
15143 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg5393b912014-09-10 15:00:16 +030015144#define NL80211_FLAG_CLEAR_SKB 0x20
Johannes Berg77cbf792021-03-10 21:58:40 +010015145#define NL80211_FLAG_NO_WIPHY_MTX 0x40
Johannes Berg4c476992010-10-04 21:36:35 +020015146
Johannes Bergf84f7712013-11-14 17:14:45 +010015147static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020015148 struct genl_info *info)
15149{
Johannes Berga05829a2021-01-22 16:19:43 +010015150 struct cfg80211_registered_device *rdev = NULL;
Johannes Berg89a54e42012-06-15 14:33:17 +020015151 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020015152 struct net_device *dev;
Johannes Berg4c476992010-10-04 21:36:35 +020015153
Johannes Berga05829a2021-01-22 16:19:43 +010015154 rtnl_lock();
Johannes Berg4c476992010-10-04 21:36:35 +020015155 if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
Johannes Berg4f7eff12012-06-15 14:14:22 +020015156 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
Johannes Berg4c476992010-10-04 21:36:35 +020015157 if (IS_ERR(rdev)) {
Johannes Berga05829a2021-01-22 16:19:43 +010015158 rtnl_unlock();
Johannes Berg4c476992010-10-04 21:36:35 +020015159 return PTR_ERR(rdev);
15160 }
15161 info->user_ptr[0] = rdev;
Johannes Berg1bf614e2012-06-15 15:23:36 +020015162 } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
15163 ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
Johannes Berga05829a2021-01-22 16:19:43 +010015164 wdev = __cfg80211_wdev_from_attrs(NULL, genl_info_net(info),
Johannes Berg89a54e42012-06-15 14:33:17 +020015165 info->attrs);
15166 if (IS_ERR(wdev)) {
Johannes Berga05829a2021-01-22 16:19:43 +010015167 rtnl_unlock();
Johannes Berg89a54e42012-06-15 14:33:17 +020015168 return PTR_ERR(wdev);
Johannes Berg4c476992010-10-04 21:36:35 +020015169 }
Johannes Berg89a54e42012-06-15 14:33:17 +020015170
Johannes Berg89a54e42012-06-15 14:33:17 +020015171 dev = wdev->netdev;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015172 rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg89a54e42012-06-15 14:33:17 +020015173
Johannes Berg1bf614e2012-06-15 15:23:36 +020015174 if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
15175 if (!dev) {
Johannes Berga05829a2021-01-22 16:19:43 +010015176 rtnl_unlock();
Johannes Berg1bf614e2012-06-15 15:23:36 +020015177 return -EINVAL;
15178 }
15179
15180 info->user_ptr[1] = dev;
15181 } else {
15182 info->user_ptr[1] = wdev;
Johannes Berg41265712010-10-04 21:14:05 +020015183 }
Johannes Berg89a54e42012-06-15 14:33:17 +020015184
Arend Van Spriel73c7da32016-10-20 20:08:22 +010015185 if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
15186 !wdev_running(wdev)) {
Johannes Berga05829a2021-01-22 16:19:43 +010015187 rtnl_unlock();
Arend Van Spriel73c7da32016-10-20 20:08:22 +010015188 return -ENETDOWN;
Johannes Berg1bf614e2012-06-15 15:23:36 +020015189 }
15190
Yajun Deng1160dfa2021-08-05 19:55:27 +080015191 dev_hold(dev);
Johannes Berg4c476992010-10-04 21:36:35 +020015192 info->user_ptr[0] = rdev;
Johannes Berg4c476992010-10-04 21:36:35 +020015193 }
15194
Johannes Berg77cbf792021-03-10 21:58:40 +010015195 if (rdev && !(ops->internal_flags & NL80211_FLAG_NO_WIPHY_MTX)) {
Johannes Berga05829a2021-01-22 16:19:43 +010015196 wiphy_lock(&rdev->wiphy);
15197 /* we keep the mutex locked until post_doit */
15198 __release(&rdev->wiphy.mtx);
15199 }
15200 if (!(ops->internal_flags & NL80211_FLAG_NEED_RTNL))
15201 rtnl_unlock();
15202
Johannes Berg4c476992010-10-04 21:36:35 +020015203 return 0;
15204}
15205
Johannes Bergf84f7712013-11-14 17:14:45 +010015206static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020015207 struct genl_info *info)
15208{
Johannes Berg1bf614e2012-06-15 15:23:36 +020015209 if (info->user_ptr[1]) {
15210 if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
15211 struct wireless_dev *wdev = info->user_ptr[1];
15212
Yajun Deng1160dfa2021-08-05 19:55:27 +080015213 dev_put(wdev->netdev);
Johannes Berg1bf614e2012-06-15 15:23:36 +020015214 } else {
15215 dev_put(info->user_ptr[1]);
15216 }
15217 }
Johannes Berg5393b912014-09-10 15:00:16 +030015218
Johannes Berg77cbf792021-03-10 21:58:40 +010015219 if (info->user_ptr[0] &&
15220 !(ops->internal_flags & NL80211_FLAG_NO_WIPHY_MTX)) {
Johannes Berga05829a2021-01-22 16:19:43 +010015221 struct cfg80211_registered_device *rdev = info->user_ptr[0];
15222
15223 /* we kept the mutex locked since pre_doit */
15224 __acquire(&rdev->wiphy.mtx);
15225 wiphy_unlock(&rdev->wiphy);
15226 }
15227
Johannes Berg4c476992010-10-04 21:36:35 +020015228 if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
15229 rtnl_unlock();
Johannes Berg5393b912014-09-10 15:00:16 +030015230
15231 /* If needed, clear the netlink message payload from the SKB
15232 * as it might contain key data that shouldn't stick around on
15233 * the heap after the SKB is freed. The netlink message header
15234 * is still needed for further processing, so leave it intact.
15235 */
15236 if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) {
15237 struct nlmsghdr *nlh = nlmsg_hdr(skb);
15238
15239 memset(nlmsg_data(nlh), 0, nlmsg_len(nlh));
15240 }
Johannes Berg4c476992010-10-04 21:36:35 +020015241}
15242
Carl Huang6bdb68c2020-12-03 05:37:26 -050015243static int nl80211_set_sar_sub_specs(struct cfg80211_registered_device *rdev,
15244 struct cfg80211_sar_specs *sar_specs,
15245 struct nlattr *spec[], int index)
15246{
15247 u32 range_index, i;
15248
15249 if (!sar_specs || !spec)
15250 return -EINVAL;
15251
15252 if (!spec[NL80211_SAR_ATTR_SPECS_POWER] ||
15253 !spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX])
15254 return -EINVAL;
15255
15256 range_index = nla_get_u32(spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX]);
15257
15258 /* check if range_index exceeds num_freq_ranges */
15259 if (range_index >= rdev->wiphy.sar_capa->num_freq_ranges)
15260 return -EINVAL;
15261
15262 /* check if range_index duplicates */
15263 for (i = 0; i < index; i++) {
15264 if (sar_specs->sub_specs[i].freq_range_index == range_index)
15265 return -EINVAL;
15266 }
15267
15268 sar_specs->sub_specs[index].power =
15269 nla_get_s32(spec[NL80211_SAR_ATTR_SPECS_POWER]);
15270
15271 sar_specs->sub_specs[index].freq_range_index = range_index;
15272
15273 return 0;
15274}
15275
15276static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info)
15277{
15278 struct cfg80211_registered_device *rdev = info->user_ptr[0];
15279 struct nlattr *spec[NL80211_SAR_ATTR_SPECS_MAX + 1];
15280 struct nlattr *tb[NL80211_SAR_ATTR_MAX + 1];
15281 struct cfg80211_sar_specs *sar_spec;
15282 enum nl80211_sar_type type;
15283 struct nlattr *spec_list;
15284 u32 specs;
15285 int rem, err;
15286
15287 if (!rdev->wiphy.sar_capa || !rdev->ops->set_sar_specs)
15288 return -EOPNOTSUPP;
15289
15290 if (!info->attrs[NL80211_ATTR_SAR_SPEC])
15291 return -EINVAL;
15292
15293 nla_parse_nested(tb, NL80211_SAR_ATTR_MAX,
15294 info->attrs[NL80211_ATTR_SAR_SPEC],
15295 NULL, NULL);
15296
15297 if (!tb[NL80211_SAR_ATTR_TYPE] || !tb[NL80211_SAR_ATTR_SPECS])
15298 return -EINVAL;
15299
15300 type = nla_get_u32(tb[NL80211_SAR_ATTR_TYPE]);
15301 if (type != rdev->wiphy.sar_capa->type)
15302 return -EINVAL;
15303
15304 specs = 0;
15305 nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem)
15306 specs++;
15307
15308 if (specs > rdev->wiphy.sar_capa->num_freq_ranges)
15309 return -EINVAL;
15310
Len Baker40f231e2021-09-19 13:40:40 +020015311 sar_spec = kzalloc(struct_size(sar_spec, sub_specs, specs), GFP_KERNEL);
Carl Huang6bdb68c2020-12-03 05:37:26 -050015312 if (!sar_spec)
15313 return -ENOMEM;
15314
15315 sar_spec->type = type;
15316 specs = 0;
15317 nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) {
15318 nla_parse_nested(spec, NL80211_SAR_ATTR_SPECS_MAX,
15319 spec_list, NULL, NULL);
15320
15321 switch (type) {
15322 case NL80211_SAR_TYPE_POWER:
15323 if (nl80211_set_sar_sub_specs(rdev, sar_spec,
15324 spec, specs)) {
15325 err = -EINVAL;
15326 goto error;
15327 }
15328 break;
15329 default:
15330 err = -EINVAL;
15331 goto error;
15332 }
15333 specs++;
15334 }
15335
15336 sar_spec->num_sub_specs = specs;
15337
15338 rdev->cur_cmd_info = info;
15339 err = rdev_set_sar_specs(rdev, sar_spec);
15340 rdev->cur_cmd_info = NULL;
15341error:
15342 kfree(sar_spec);
15343 return err;
15344}
15345
Johannes Berg4534de82013-11-14 17:14:46 +010015346static const struct genl_ops nl80211_ops[] = {
Johannes Berg55682962007-09-20 13:09:35 -040015347 {
15348 .cmd = NL80211_CMD_GET_WIPHY,
Johannes Bergef6243a2019-04-26 14:07:31 +020015349 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040015350 .doit = nl80211_get_wiphy,
15351 .dumpit = nl80211_dump_wiphy,
Johannes Berg86e8cf92013-06-19 10:57:22 +020015352 .done = nl80211_dump_wiphy_done,
Johannes Berg55682962007-09-20 13:09:35 -040015353 /* can be retrieved by unprivileged users */
Johannes Berga05829a2021-01-22 16:19:43 +010015354 .internal_flags = NL80211_FLAG_NEED_WIPHY,
Johannes Berg55682962007-09-20 13:09:35 -040015355 },
Jakub Kicinski66a9b922020-10-02 14:49:54 -070015356};
15357
15358static const struct genl_small_ops nl80211_small_ops[] = {
Johannes Berg55682962007-09-20 13:09:35 -040015359 {
15360 .cmd = NL80211_CMD_SET_WIPHY,
Johannes Bergef6243a2019-04-26 14:07:31 +020015361 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040015362 .doit = nl80211_set_wiphy,
Martin Willi5617c6c2016-05-09 18:33:58 +020015363 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg55682962007-09-20 13:09:35 -040015364 },
15365 {
15366 .cmd = NL80211_CMD_GET_INTERFACE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015367 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040015368 .doit = nl80211_get_interface,
15369 .dumpit = nl80211_dump_interface,
Johannes Berg55682962007-09-20 13:09:35 -040015370 /* can be retrieved by unprivileged users */
Johannes Berga05829a2021-01-22 16:19:43 +010015371 .internal_flags = NL80211_FLAG_NEED_WDEV,
Johannes Berg55682962007-09-20 13:09:35 -040015372 },
15373 {
15374 .cmd = NL80211_CMD_SET_INTERFACE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015375 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040015376 .doit = nl80211_set_interface,
Martin Willi5617c6c2016-05-09 18:33:58 +020015377 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020015378 .internal_flags = NL80211_FLAG_NEED_NETDEV |
15379 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040015380 },
15381 {
15382 .cmd = NL80211_CMD_NEW_INTERFACE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015383 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040015384 .doit = nl80211_new_interface,
Martin Willi5617c6c2016-05-09 18:33:58 +020015385 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020015386 .internal_flags = NL80211_FLAG_NEED_WIPHY |
Johannes Bergea6b2092021-04-27 11:49:52 +020015387 NL80211_FLAG_NEED_RTNL |
15388 /* we take the wiphy mutex later ourselves */
15389 NL80211_FLAG_NO_WIPHY_MTX,
Johannes Berg55682962007-09-20 13:09:35 -040015390 },
15391 {
15392 .cmd = NL80211_CMD_DEL_INTERFACE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015393 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg55682962007-09-20 13:09:35 -040015394 .doit = nl80211_del_interface,
Martin Willi5617c6c2016-05-09 18:33:58 +020015395 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg84efbb82012-06-16 00:00:26 +020015396 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020015397 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040015398 },
Johannes Berg41ade002007-12-19 02:03:29 +010015399 {
15400 .cmd = NL80211_CMD_GET_KEY,
Johannes Bergef6243a2019-04-26 14:07:31 +020015401 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg41ade002007-12-19 02:03:29 +010015402 .doit = nl80211_get_key,
Martin Willi5617c6c2016-05-09 18:33:58 +020015403 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015404 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg41ade002007-12-19 02:03:29 +010015405 },
15406 {
15407 .cmd = NL80211_CMD_SET_KEY,
Johannes Bergef6243a2019-04-26 14:07:31 +020015408 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg41ade002007-12-19 02:03:29 +010015409 .doit = nl80211_set_key,
Martin Willi5617c6c2016-05-09 18:33:58 +020015410 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020015411 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030015412 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010015413 },
15414 {
15415 .cmd = NL80211_CMD_NEW_KEY,
Johannes Bergef6243a2019-04-26 14:07:31 +020015416 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg41ade002007-12-19 02:03:29 +010015417 .doit = nl80211_new_key,
Martin Willi5617c6c2016-05-09 18:33:58 +020015418 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020015419 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030015420 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010015421 },
15422 {
15423 .cmd = NL80211_CMD_DEL_KEY,
Johannes Bergef6243a2019-04-26 14:07:31 +020015424 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg41ade002007-12-19 02:03:29 +010015425 .doit = nl80211_del_key,
Martin Willi5617c6c2016-05-09 18:33:58 +020015426 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015427 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg41ade002007-12-19 02:03:29 +010015428 },
Johannes Berged1b6cc2007-12-19 02:03:32 +010015429 {
15430 .cmd = NL80211_CMD_SET_BEACON,
Johannes Bergef6243a2019-04-26 14:07:31 +020015431 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Martin Willi5617c6c2016-05-09 18:33:58 +020015432 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010015433 .doit = nl80211_set_beacon,
Johannes Berga05829a2021-01-22 16:19:43 +010015434 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010015435 },
15436 {
Johannes Berg88600202012-02-13 15:17:18 +010015437 .cmd = NL80211_CMD_START_AP,
Johannes Bergef6243a2019-04-26 14:07:31 +020015438 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Martin Willi5617c6c2016-05-09 18:33:58 +020015439 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010015440 .doit = nl80211_start_ap,
Johannes Berga05829a2021-01-22 16:19:43 +010015441 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010015442 },
15443 {
Johannes Berg88600202012-02-13 15:17:18 +010015444 .cmd = NL80211_CMD_STOP_AP,
Johannes Bergef6243a2019-04-26 14:07:31 +020015445 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Martin Willi5617c6c2016-05-09 18:33:58 +020015446 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010015447 .doit = nl80211_stop_ap,
Johannes Berga05829a2021-01-22 16:19:43 +010015448 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010015449 },
Johannes Berg5727ef12007-12-19 02:03:34 +010015450 {
15451 .cmd = NL80211_CMD_GET_STATION,
Johannes Bergef6243a2019-04-26 14:07:31 +020015452 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg5727ef12007-12-19 02:03:34 +010015453 .doit = nl80211_get_station,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015454 .dumpit = nl80211_dump_station,
Johannes Berga05829a2021-01-22 16:19:43 +010015455 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Johannes Berg5727ef12007-12-19 02:03:34 +010015456 },
15457 {
15458 .cmd = NL80211_CMD_SET_STATION,
Johannes Bergef6243a2019-04-26 14:07:31 +020015459 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg5727ef12007-12-19 02:03:34 +010015460 .doit = nl80211_set_station,
Martin Willi5617c6c2016-05-09 18:33:58 +020015461 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015462 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg5727ef12007-12-19 02:03:34 +010015463 },
15464 {
15465 .cmd = NL80211_CMD_NEW_STATION,
Johannes Bergef6243a2019-04-26 14:07:31 +020015466 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg5727ef12007-12-19 02:03:34 +010015467 .doit = nl80211_new_station,
Martin Willi5617c6c2016-05-09 18:33:58 +020015468 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015469 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg5727ef12007-12-19 02:03:34 +010015470 },
15471 {
15472 .cmd = NL80211_CMD_DEL_STATION,
Johannes Bergef6243a2019-04-26 14:07:31 +020015473 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg5727ef12007-12-19 02:03:34 +010015474 .doit = nl80211_del_station,
Martin Willi5617c6c2016-05-09 18:33:58 +020015475 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015476 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg5727ef12007-12-19 02:03:34 +010015477 },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015478 {
15479 .cmd = NL80211_CMD_GET_MPATH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015480 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015481 .doit = nl80211_get_mpath,
15482 .dumpit = nl80211_dump_mpath,
Martin Willi5617c6c2016-05-09 18:33:58 +020015483 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015484 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015485 },
15486 {
Henning Rogge66be7d22014-09-12 08:58:49 +020015487 .cmd = NL80211_CMD_GET_MPP,
Johannes Bergef6243a2019-04-26 14:07:31 +020015488 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Henning Rogge66be7d22014-09-12 08:58:49 +020015489 .doit = nl80211_get_mpp,
15490 .dumpit = nl80211_dump_mpp,
Martin Willi5617c6c2016-05-09 18:33:58 +020015491 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015492 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Henning Rogge66be7d22014-09-12 08:58:49 +020015493 },
15494 {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015495 .cmd = NL80211_CMD_SET_MPATH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015496 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015497 .doit = nl80211_set_mpath,
Martin Willi5617c6c2016-05-09 18:33:58 +020015498 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015499 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015500 },
15501 {
15502 .cmd = NL80211_CMD_NEW_MPATH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015503 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015504 .doit = nl80211_new_mpath,
Martin Willi5617c6c2016-05-09 18:33:58 +020015505 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015506 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015507 },
15508 {
15509 .cmd = NL80211_CMD_DEL_MPATH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015510 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015511 .doit = nl80211_del_mpath,
Martin Willi5617c6c2016-05-09 18:33:58 +020015512 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015513 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010015514 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +030015515 {
15516 .cmd = NL80211_CMD_SET_BSS,
Johannes Bergef6243a2019-04-26 14:07:31 +020015517 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen9f1ba902008-08-07 20:07:01 +030015518 .doit = nl80211_set_bss,
Martin Willi5617c6c2016-05-09 18:33:58 +020015519 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015520 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Jouni Malinen9f1ba902008-08-07 20:07:01 +030015521 },
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070015522 {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080015523 .cmd = NL80211_CMD_GET_REG,
Johannes Bergef6243a2019-04-26 14:07:31 +020015524 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arik Nemtsovad30ca22014-12-15 19:25:59 +020015525 .doit = nl80211_get_reg_do,
15526 .dumpit = nl80211_get_reg_dump,
Johannes Berga05829a2021-01-22 16:19:43 +010015527 .internal_flags = 0,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080015528 /* can be retrieved by unprivileged users */
15529 },
Johannes Bergb6863032015-10-15 09:25:18 +020015530#ifdef CONFIG_CFG80211_CRDA_SUPPORT
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080015531 {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070015532 .cmd = NL80211_CMD_SET_REG,
Johannes Bergef6243a2019-04-26 14:07:31 +020015533 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070015534 .doit = nl80211_set_reg,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070015535 .flags = GENL_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015536 .internal_flags = 0,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070015537 },
Johannes Bergb6863032015-10-15 09:25:18 +020015538#endif
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070015539 {
15540 .cmd = NL80211_CMD_REQ_SET_REG,
Johannes Bergef6243a2019-04-26 14:07:31 +020015541 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070015542 .doit = nl80211_req_set_reg,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070015543 .flags = GENL_ADMIN_PERM,
15544 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070015545 {
Johannes Berg1ea4ff3e92017-09-13 16:07:22 +020015546 .cmd = NL80211_CMD_RELOAD_REGDB,
Johannes Bergef6243a2019-04-26 14:07:31 +020015547 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg1ea4ff3e92017-09-13 16:07:22 +020015548 .doit = nl80211_reload_regdb,
Johannes Berg1ea4ff3e92017-09-13 16:07:22 +020015549 .flags = GENL_ADMIN_PERM,
15550 },
15551 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080015552 .cmd = NL80211_CMD_GET_MESH_CONFIG,
Johannes Bergef6243a2019-04-26 14:07:31 +020015553 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Javier Cardona24bdd9f2010-12-16 17:37:48 -080015554 .doit = nl80211_get_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070015555 /* can be retrieved by unprivileged users */
Johannes Berga05829a2021-01-22 16:19:43 +010015556 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070015557 },
15558 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080015559 .cmd = NL80211_CMD_SET_MESH_CONFIG,
Johannes Bergef6243a2019-04-26 14:07:31 +020015560 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Javier Cardona24bdd9f2010-12-16 17:37:48 -080015561 .doit = nl80211_update_mesh_config,
Martin Willi5617c6c2016-05-09 18:33:58 +020015562 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015563 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070015564 },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +020015565 {
Johannes Berg2a519312009-02-10 21:25:55 +010015566 .cmd = NL80211_CMD_TRIGGER_SCAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020015567 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg2a519312009-02-10 21:25:55 +010015568 .doit = nl80211_trigger_scan,
Martin Willi5617c6c2016-05-09 18:33:58 +020015569 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015570 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Johannes Berg2a519312009-02-10 21:25:55 +010015571 },
15572 {
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053015573 .cmd = NL80211_CMD_ABORT_SCAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020015574 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053015575 .doit = nl80211_abort_scan,
Martin Willi5617c6c2016-05-09 18:33:58 +020015576 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015577 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053015578 },
15579 {
Johannes Berg2a519312009-02-10 21:25:55 +010015580 .cmd = NL80211_CMD_GET_SCAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020015581 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg2a519312009-02-10 21:25:55 +010015582 .dumpit = nl80211_dump_scan,
15583 },
Jouni Malinen636a5d32009-03-19 13:39:22 +020015584 {
Luciano Coelho807f8a82011-05-11 17:09:35 +030015585 .cmd = NL80211_CMD_START_SCHED_SCAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020015586 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luciano Coelho807f8a82011-05-11 17:09:35 +030015587 .doit = nl80211_start_sched_scan,
Martin Willi5617c6c2016-05-09 18:33:58 +020015588 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015589 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Luciano Coelho807f8a82011-05-11 17:09:35 +030015590 },
15591 {
15592 .cmd = NL80211_CMD_STOP_SCHED_SCAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020015593 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Luciano Coelho807f8a82011-05-11 17:09:35 +030015594 .doit = nl80211_stop_sched_scan,
Martin Willi5617c6c2016-05-09 18:33:58 +020015595 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015596 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Luciano Coelho807f8a82011-05-11 17:09:35 +030015597 },
15598 {
Jouni Malinen636a5d32009-03-19 13:39:22 +020015599 .cmd = NL80211_CMD_AUTHENTICATE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015600 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen636a5d32009-03-19 13:39:22 +020015601 .doit = nl80211_authenticate,
Martin Willi5617c6c2016-05-09 18:33:58 +020015602 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020015603 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berga05829a2021-01-22 16:19:43 +010015604 0 |
Johannes Berg5393b912014-09-10 15:00:16 +030015605 NL80211_FLAG_CLEAR_SKB,
Jouni Malinen636a5d32009-03-19 13:39:22 +020015606 },
15607 {
15608 .cmd = NL80211_CMD_ASSOCIATE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015609 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen636a5d32009-03-19 13:39:22 +020015610 .doit = nl80211_associate,
Martin Willi5617c6c2016-05-09 18:33:58 +020015611 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020015612 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berga05829a2021-01-22 16:19:43 +010015613 0 |
Sunil Duttd6db02a2019-02-25 15:37:20 +053015614 NL80211_FLAG_CLEAR_SKB,
Jouni Malinen636a5d32009-03-19 13:39:22 +020015615 },
15616 {
15617 .cmd = NL80211_CMD_DEAUTHENTICATE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015618 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen636a5d32009-03-19 13:39:22 +020015619 .doit = nl80211_deauthenticate,
Martin Willi5617c6c2016-05-09 18:33:58 +020015620 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015621 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Jouni Malinen636a5d32009-03-19 13:39:22 +020015622 },
15623 {
15624 .cmd = NL80211_CMD_DISASSOCIATE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015625 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen636a5d32009-03-19 13:39:22 +020015626 .doit = nl80211_disassociate,
Martin Willi5617c6c2016-05-09 18:33:58 +020015627 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015628 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Jouni Malinen636a5d32009-03-19 13:39:22 +020015629 },
Johannes Berg04a773a2009-04-19 21:24:32 +020015630 {
15631 .cmd = NL80211_CMD_JOIN_IBSS,
Johannes Bergef6243a2019-04-26 14:07:31 +020015632 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg04a773a2009-04-19 21:24:32 +020015633 .doit = nl80211_join_ibss,
Martin Willi5617c6c2016-05-09 18:33:58 +020015634 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015635 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg04a773a2009-04-19 21:24:32 +020015636 },
15637 {
15638 .cmd = NL80211_CMD_LEAVE_IBSS,
Johannes Bergef6243a2019-04-26 14:07:31 +020015639 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg04a773a2009-04-19 21:24:32 +020015640 .doit = nl80211_leave_ibss,
Martin Willi5617c6c2016-05-09 18:33:58 +020015641 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015642 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg04a773a2009-04-19 21:24:32 +020015643 },
Johannes Bergaff89a92009-07-01 21:26:51 +020015644#ifdef CONFIG_NL80211_TESTMODE
15645 {
15646 .cmd = NL80211_CMD_TESTMODE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015647 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergaff89a92009-07-01 21:26:51 +020015648 .doit = nl80211_testmode_do,
Wey-Yi Guy71063f02011-05-20 09:05:54 -070015649 .dumpit = nl80211_testmode_dump,
Martin Willi5617c6c2016-05-09 18:33:58 +020015650 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015651 .internal_flags = NL80211_FLAG_NEED_WIPHY,
Johannes Bergaff89a92009-07-01 21:26:51 +020015652 },
15653#endif
Samuel Ortizb23aa672009-07-01 21:26:54 +020015654 {
15655 .cmd = NL80211_CMD_CONNECT,
Johannes Bergef6243a2019-04-26 14:07:31 +020015656 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortizb23aa672009-07-01 21:26:54 +020015657 .doit = nl80211_connect,
Martin Willi5617c6c2016-05-09 18:33:58 +020015658 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020015659 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berga05829a2021-01-22 16:19:43 +010015660 0 |
Sunil Duttd6db02a2019-02-25 15:37:20 +053015661 NL80211_FLAG_CLEAR_SKB,
Samuel Ortizb23aa672009-07-01 21:26:54 +020015662 },
15663 {
vamsi krishna088e8df2016-10-27 16:51:11 +030015664 .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
Johannes Bergef6243a2019-04-26 14:07:31 +020015665 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
vamsi krishna088e8df2016-10-27 16:51:11 +030015666 .doit = nl80211_update_connect_params,
vamsi krishna088e8df2016-10-27 16:51:11 +030015667 .flags = GENL_ADMIN_PERM,
15668 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berga05829a2021-01-22 16:19:43 +010015669 0 |
Sunil Duttd6db02a2019-02-25 15:37:20 +053015670 NL80211_FLAG_CLEAR_SKB,
vamsi krishna088e8df2016-10-27 16:51:11 +030015671 },
15672 {
Samuel Ortizb23aa672009-07-01 21:26:54 +020015673 .cmd = NL80211_CMD_DISCONNECT,
Johannes Bergef6243a2019-04-26 14:07:31 +020015674 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortizb23aa672009-07-01 21:26:54 +020015675 .doit = nl80211_disconnect,
Martin Willi5617c6c2016-05-09 18:33:58 +020015676 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015677 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Samuel Ortizb23aa672009-07-01 21:26:54 +020015678 },
Johannes Berg463d0182009-07-14 00:33:35 +020015679 {
15680 .cmd = NL80211_CMD_SET_WIPHY_NETNS,
Johannes Bergef6243a2019-04-26 14:07:31 +020015681 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg463d0182009-07-14 00:33:35 +020015682 .doit = nl80211_wiphy_netns,
Martin Willi5617c6c2016-05-09 18:33:58 +020015683 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg77cbf792021-03-10 21:58:40 +010015684 .internal_flags = NL80211_FLAG_NEED_WIPHY |
15685 NL80211_FLAG_NEED_RTNL |
15686 NL80211_FLAG_NO_WIPHY_MTX,
Johannes Berg463d0182009-07-14 00:33:35 +020015687 },
Holger Schurig61fa7132009-11-11 12:25:40 +010015688 {
15689 .cmd = NL80211_CMD_GET_SURVEY,
Johannes Bergef6243a2019-04-26 14:07:31 +020015690 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Holger Schurig61fa7132009-11-11 12:25:40 +010015691 .dumpit = nl80211_dump_survey,
15692 },
Samuel Ortiz67fbb162009-11-24 23:59:15 +010015693 {
15694 .cmd = NL80211_CMD_SET_PMKSA,
Johannes Bergef6243a2019-04-26 14:07:31 +020015695 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010015696 .doit = nl80211_setdel_pmksa,
Martin Willi5617c6c2016-05-09 18:33:58 +020015697 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020015698 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berga05829a2021-01-22 16:19:43 +010015699 0 |
Sunil Duttd6db02a2019-02-25 15:37:20 +053015700 NL80211_FLAG_CLEAR_SKB,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010015701 },
15702 {
15703 .cmd = NL80211_CMD_DEL_PMKSA,
Johannes Bergef6243a2019-04-26 14:07:31 +020015704 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010015705 .doit = nl80211_setdel_pmksa,
Martin Willi5617c6c2016-05-09 18:33:58 +020015706 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015707 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010015708 },
15709 {
15710 .cmd = NL80211_CMD_FLUSH_PMKSA,
Johannes Bergef6243a2019-04-26 14:07:31 +020015711 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010015712 .doit = nl80211_flush_pmksa,
Martin Willi5617c6c2016-05-09 18:33:58 +020015713 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015714 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010015715 },
Jouni Malinen9588bbd2009-12-23 13:15:41 +010015716 {
15717 .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
Johannes Bergef6243a2019-04-26 14:07:31 +020015718 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010015719 .doit = nl80211_remain_on_channel,
Martin Willi5617c6c2016-05-09 18:33:58 +020015720 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015721 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010015722 },
15723 {
15724 .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
Johannes Bergef6243a2019-04-26 14:07:31 +020015725 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010015726 .doit = nl80211_cancel_remain_on_channel,
Martin Willi5617c6c2016-05-09 18:33:58 +020015727 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015728 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010015729 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +020015730 {
15731 .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
Johannes Bergef6243a2019-04-26 14:07:31 +020015732 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen13ae75b2009-12-29 12:59:45 +020015733 .doit = nl80211_set_tx_bitrate_mask,
Martin Willi5617c6c2016-05-09 18:33:58 +020015734 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015735 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Jouni Malinen13ae75b2009-12-29 12:59:45 +020015736 },
Jouni Malinen026331c2010-02-15 12:53:10 +020015737 {
Johannes Berg2e161f782010-08-12 15:38:38 +020015738 .cmd = NL80211_CMD_REGISTER_FRAME,
Johannes Bergef6243a2019-04-26 14:07:31 +020015739 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg2e161f782010-08-12 15:38:38 +020015740 .doit = nl80211_register_mgmt,
Martin Willi5617c6c2016-05-09 18:33:58 +020015741 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015742 .internal_flags = NL80211_FLAG_NEED_WDEV,
Jouni Malinen026331c2010-02-15 12:53:10 +020015743 },
15744 {
Johannes Berg2e161f782010-08-12 15:38:38 +020015745 .cmd = NL80211_CMD_FRAME,
Johannes Bergef6243a2019-04-26 14:07:31 +020015746 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg2e161f782010-08-12 15:38:38 +020015747 .doit = nl80211_tx_mgmt,
Martin Willi5617c6c2016-05-09 18:33:58 +020015748 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015749 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Jouni Malinen026331c2010-02-15 12:53:10 +020015750 },
Kalle Valoffb9eb32010-02-17 17:58:10 +020015751 {
Johannes Bergf7ca38d2010-11-25 10:02:29 +010015752 .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
Johannes Bergef6243a2019-04-26 14:07:31 +020015753 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergf7ca38d2010-11-25 10:02:29 +010015754 .doit = nl80211_tx_mgmt_cancel_wait,
Martin Willi5617c6c2016-05-09 18:33:58 +020015755 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015756 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Johannes Bergf7ca38d2010-11-25 10:02:29 +010015757 },
15758 {
Kalle Valoffb9eb32010-02-17 17:58:10 +020015759 .cmd = NL80211_CMD_SET_POWER_SAVE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015760 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Kalle Valoffb9eb32010-02-17 17:58:10 +020015761 .doit = nl80211_set_power_save,
Martin Willi5617c6c2016-05-09 18:33:58 +020015762 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015763 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Kalle Valoffb9eb32010-02-17 17:58:10 +020015764 },
15765 {
15766 .cmd = NL80211_CMD_GET_POWER_SAVE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015767 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Kalle Valoffb9eb32010-02-17 17:58:10 +020015768 .doit = nl80211_get_power_save,
Kalle Valoffb9eb32010-02-17 17:58:10 +020015769 /* can be retrieved by unprivileged users */
Johannes Berga05829a2021-01-22 16:19:43 +010015770 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Kalle Valoffb9eb32010-02-17 17:58:10 +020015771 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020015772 {
15773 .cmd = NL80211_CMD_SET_CQM,
Johannes Bergef6243a2019-04-26 14:07:31 +020015774 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020015775 .doit = nl80211_set_cqm,
Martin Willi5617c6c2016-05-09 18:33:58 +020015776 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015777 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020015778 },
Johannes Bergf444de02010-05-05 15:25:02 +020015779 {
15780 .cmd = NL80211_CMD_SET_CHANNEL,
Johannes Bergef6243a2019-04-26 14:07:31 +020015781 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergf444de02010-05-05 15:25:02 +020015782 .doit = nl80211_set_channel,
Martin Willi5617c6c2016-05-09 18:33:58 +020015783 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015784 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Johannes Bergf444de02010-05-05 15:25:02 +020015785 },
Bill Jordane8347eb2010-10-01 13:54:28 -040015786 {
Johannes Berg29cbe682010-12-03 09:20:44 +010015787 .cmd = NL80211_CMD_JOIN_MESH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015788 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg29cbe682010-12-03 09:20:44 +010015789 .doit = nl80211_join_mesh,
Martin Willi5617c6c2016-05-09 18:33:58 +020015790 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015791 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg29cbe682010-12-03 09:20:44 +010015792 },
15793 {
15794 .cmd = NL80211_CMD_LEAVE_MESH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015795 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg29cbe682010-12-03 09:20:44 +010015796 .doit = nl80211_leave_mesh,
Martin Willi5617c6c2016-05-09 18:33:58 +020015797 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015798 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg29cbe682010-12-03 09:20:44 +010015799 },
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010015800 {
15801 .cmd = NL80211_CMD_JOIN_OCB,
Johannes Bergef6243a2019-04-26 14:07:31 +020015802 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010015803 .doit = nl80211_join_ocb,
Martin Willi5617c6c2016-05-09 18:33:58 +020015804 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015805 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010015806 },
15807 {
15808 .cmd = NL80211_CMD_LEAVE_OCB,
Johannes Bergef6243a2019-04-26 14:07:31 +020015809 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010015810 .doit = nl80211_leave_ocb,
Martin Willi5617c6c2016-05-09 18:33:58 +020015811 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015812 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010015813 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020015814#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +020015815 {
15816 .cmd = NL80211_CMD_GET_WOWLAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020015817 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergff1b6e62011-05-04 15:37:28 +020015818 .doit = nl80211_get_wowlan,
Johannes Bergff1b6e62011-05-04 15:37:28 +020015819 /* can be retrieved by unprivileged users */
Johannes Berga05829a2021-01-22 16:19:43 +010015820 .internal_flags = NL80211_FLAG_NEED_WIPHY,
Johannes Bergff1b6e62011-05-04 15:37:28 +020015821 },
15822 {
15823 .cmd = NL80211_CMD_SET_WOWLAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020015824 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergff1b6e62011-05-04 15:37:28 +020015825 .doit = nl80211_set_wowlan,
Martin Willi5617c6c2016-05-09 18:33:58 +020015826 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015827 .internal_flags = NL80211_FLAG_NEED_WIPHY,
Johannes Bergff1b6e62011-05-04 15:37:28 +020015828 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020015829#endif
Johannes Berge5497d72011-07-05 16:35:40 +020015830 {
15831 .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +020015832 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berge5497d72011-07-05 16:35:40 +020015833 .doit = nl80211_set_rekey_data,
Martin Willi5617c6c2016-05-09 18:33:58 +020015834 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berge5497d72011-07-05 16:35:40 +020015835 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berga05829a2021-01-22 16:19:43 +010015836 0 |
Johannes Berg5393b912014-09-10 15:00:16 +030015837 NL80211_FLAG_CLEAR_SKB,
Johannes Berge5497d72011-07-05 16:35:40 +020015838 },
Arik Nemtsov109086c2011-09-28 14:12:50 +030015839 {
15840 .cmd = NL80211_CMD_TDLS_MGMT,
Johannes Bergef6243a2019-04-26 14:07:31 +020015841 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arik Nemtsov109086c2011-09-28 14:12:50 +030015842 .doit = nl80211_tdls_mgmt,
Martin Willi5617c6c2016-05-09 18:33:58 +020015843 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015844 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Arik Nemtsov109086c2011-09-28 14:12:50 +030015845 },
15846 {
15847 .cmd = NL80211_CMD_TDLS_OPER,
Johannes Bergef6243a2019-04-26 14:07:31 +020015848 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arik Nemtsov109086c2011-09-28 14:12:50 +030015849 .doit = nl80211_tdls_oper,
Martin Willi5617c6c2016-05-09 18:33:58 +020015850 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015851 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Arik Nemtsov109086c2011-09-28 14:12:50 +030015852 },
Johannes Berg28946da2011-11-04 11:18:12 +010015853 {
15854 .cmd = NL80211_CMD_UNEXPECTED_FRAME,
Johannes Bergef6243a2019-04-26 14:07:31 +020015855 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg28946da2011-11-04 11:18:12 +010015856 .doit = nl80211_register_unexpected_frame,
Martin Willi5617c6c2016-05-09 18:33:58 +020015857 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015858 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Johannes Berg28946da2011-11-04 11:18:12 +010015859 },
Johannes Berg7f6cf312011-11-04 11:18:15 +010015860 {
15861 .cmd = NL80211_CMD_PROBE_CLIENT,
Johannes Bergef6243a2019-04-26 14:07:31 +020015862 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg7f6cf312011-11-04 11:18:15 +010015863 .doit = nl80211_probe_client,
Martin Willi5617c6c2016-05-09 18:33:58 +020015864 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015865 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg7f6cf312011-11-04 11:18:15 +010015866 },
Johannes Berg5e760232011-11-04 11:18:17 +010015867 {
15868 .cmd = NL80211_CMD_REGISTER_BEACONS,
Johannes Bergef6243a2019-04-26 14:07:31 +020015869 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg5e760232011-11-04 11:18:17 +010015870 .doit = nl80211_register_beacons,
Martin Willi5617c6c2016-05-09 18:33:58 +020015871 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015872 .internal_flags = NL80211_FLAG_NEED_WIPHY,
Johannes Berg5e760232011-11-04 11:18:17 +010015873 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010015874 {
15875 .cmd = NL80211_CMD_SET_NOACK_MAP,
Johannes Bergef6243a2019-04-26 14:07:31 +020015876 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010015877 .doit = nl80211_set_noack_map,
Martin Willi5617c6c2016-05-09 18:33:58 +020015878 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015879 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010015880 },
Johannes Berg98104fde2012-06-16 00:19:54 +020015881 {
15882 .cmd = NL80211_CMD_START_P2P_DEVICE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015883 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg98104fde2012-06-16 00:19:54 +020015884 .doit = nl80211_start_p2p_device,
Martin Willi5617c6c2016-05-09 18:33:58 +020015885 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020015886 .internal_flags = NL80211_FLAG_NEED_WDEV |
15887 NL80211_FLAG_NEED_RTNL,
15888 },
15889 {
15890 .cmd = NL80211_CMD_STOP_P2P_DEVICE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015891 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg98104fde2012-06-16 00:19:54 +020015892 .doit = nl80211_stop_p2p_device,
Martin Willi5617c6c2016-05-09 18:33:58 +020015893 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020015894 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
15895 NL80211_FLAG_NEED_RTNL,
15896 },
Antonio Quartullif4e583c2012-11-02 13:27:48 +010015897 {
Ayala Bekercb3b7d82016-09-20 17:31:13 +030015898 .cmd = NL80211_CMD_START_NAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020015899 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ayala Bekercb3b7d82016-09-20 17:31:13 +030015900 .doit = nl80211_start_nan,
Ayala Bekercb3b7d82016-09-20 17:31:13 +030015901 .flags = GENL_ADMIN_PERM,
15902 .internal_flags = NL80211_FLAG_NEED_WDEV |
15903 NL80211_FLAG_NEED_RTNL,
15904 },
15905 {
15906 .cmd = NL80211_CMD_STOP_NAN,
Johannes Bergef6243a2019-04-26 14:07:31 +020015907 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ayala Bekercb3b7d82016-09-20 17:31:13 +030015908 .doit = nl80211_stop_nan,
Ayala Bekercb3b7d82016-09-20 17:31:13 +030015909 .flags = GENL_ADMIN_PERM,
15910 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
15911 NL80211_FLAG_NEED_RTNL,
15912 },
15913 {
Ayala Bekera442b762016-09-20 17:31:15 +030015914 .cmd = NL80211_CMD_ADD_NAN_FUNCTION,
Johannes Bergef6243a2019-04-26 14:07:31 +020015915 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ayala Bekera442b762016-09-20 17:31:15 +030015916 .doit = nl80211_nan_add_func,
Ayala Bekera442b762016-09-20 17:31:15 +030015917 .flags = GENL_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015918 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Ayala Bekera442b762016-09-20 17:31:15 +030015919 },
15920 {
15921 .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
Johannes Bergef6243a2019-04-26 14:07:31 +020015922 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ayala Bekera442b762016-09-20 17:31:15 +030015923 .doit = nl80211_nan_del_func,
Ayala Bekera442b762016-09-20 17:31:15 +030015924 .flags = GENL_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015925 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Ayala Bekera442b762016-09-20 17:31:15 +030015926 },
15927 {
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030015928 .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
Johannes Bergef6243a2019-04-26 14:07:31 +020015929 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030015930 .doit = nl80211_nan_change_config,
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030015931 .flags = GENL_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015932 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030015933 },
15934 {
Antonio Quartullif4e583c2012-11-02 13:27:48 +010015935 .cmd = NL80211_CMD_SET_MCAST_RATE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015936 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Antonio Quartullif4e583c2012-11-02 13:27:48 +010015937 .doit = nl80211_set_mcast_rate,
Martin Willi5617c6c2016-05-09 18:33:58 +020015938 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015939 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Antonio Quartullif4e583c2012-11-02 13:27:48 +010015940 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053015941 {
15942 .cmd = NL80211_CMD_SET_MAC_ACL,
Johannes Bergef6243a2019-04-26 14:07:31 +020015943 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053015944 .doit = nl80211_set_mac_acl,
Martin Willi5617c6c2016-05-09 18:33:58 +020015945 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015946 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053015947 },
Simon Wunderlich04f39042013-02-08 18:16:19 +010015948 {
15949 .cmd = NL80211_CMD_RADAR_DETECT,
Johannes Bergef6243a2019-04-26 14:07:31 +020015950 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Simon Wunderlich04f39042013-02-08 18:16:19 +010015951 .doit = nl80211_start_radar_detection,
Martin Willi5617c6c2016-05-09 18:33:58 +020015952 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015953 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Simon Wunderlich04f39042013-02-08 18:16:19 +010015954 },
Johannes Berg3713b4e2013-02-14 16:19:38 +010015955 {
15956 .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
Johannes Bergef6243a2019-04-26 14:07:31 +020015957 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg3713b4e2013-02-14 16:19:38 +010015958 .doit = nl80211_get_protocol_features,
Johannes Berg3713b4e2013-02-14 16:19:38 +010015959 },
Jouni Malinen355199e2013-02-27 17:14:27 +020015960 {
15961 .cmd = NL80211_CMD_UPDATE_FT_IES,
Johannes Bergef6243a2019-04-26 14:07:31 +020015962 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jouni Malinen355199e2013-02-27 17:14:27 +020015963 .doit = nl80211_update_ft_ies,
Martin Willi5617c6c2016-05-09 18:33:58 +020015964 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015965 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Jouni Malinen355199e2013-02-27 17:14:27 +020015966 },
Arend van Spriel5de17982013-04-18 15:49:00 +020015967 {
15968 .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
Johannes Bergef6243a2019-04-26 14:07:31 +020015969 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arend van Spriel5de17982013-04-18 15:49:00 +020015970 .doit = nl80211_crit_protocol_start,
Martin Willi5617c6c2016-05-09 18:33:58 +020015971 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015972 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Arend van Spriel5de17982013-04-18 15:49:00 +020015973 },
15974 {
15975 .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
Johannes Bergef6243a2019-04-26 14:07:31 +020015976 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arend van Spriel5de17982013-04-18 15:49:00 +020015977 .doit = nl80211_crit_protocol_stop,
Martin Willi5617c6c2016-05-09 18:33:58 +020015978 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015979 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070015980 },
15981 {
15982 .cmd = NL80211_CMD_GET_COALESCE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015983 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070015984 .doit = nl80211_get_coalesce,
Johannes Berga05829a2021-01-22 16:19:43 +010015985 .internal_flags = NL80211_FLAG_NEED_WIPHY,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070015986 },
15987 {
15988 .cmd = NL80211_CMD_SET_COALESCE,
Johannes Bergef6243a2019-04-26 14:07:31 +020015989 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070015990 .doit = nl80211_set_coalesce,
Martin Willi5617c6c2016-05-09 18:33:58 +020015991 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015992 .internal_flags = NL80211_FLAG_NEED_WIPHY,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020015993 },
15994 {
15995 .cmd = NL80211_CMD_CHANNEL_SWITCH,
Johannes Bergef6243a2019-04-26 14:07:31 +020015996 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020015997 .doit = nl80211_channel_switch,
Martin Willi5617c6c2016-05-09 18:33:58 +020015998 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010015999 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020016000 },
Johannes Bergad7e7182013-11-13 13:37:47 +010016001 {
16002 .cmd = NL80211_CMD_VENDOR,
Johannes Bergef6243a2019-04-26 14:07:31 +020016003 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Bergad7e7182013-11-13 13:37:47 +010016004 .doit = nl80211_vendor_cmd,
Johannes Berg7bdbe402015-08-15 22:39:49 +030016005 .dumpit = nl80211_vendor_cmd_dump,
Martin Willi5617c6c2016-05-09 18:33:58 +020016006 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergad7e7182013-11-13 13:37:47 +010016007 .internal_flags = NL80211_FLAG_NEED_WIPHY |
Johannes Berga05829a2021-01-22 16:19:43 +010016008 0 |
Sunil Duttd6db02a2019-02-25 15:37:20 +053016009 NL80211_FLAG_CLEAR_SKB,
Johannes Bergad7e7182013-11-13 13:37:47 +010016010 },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080016011 {
16012 .cmd = NL80211_CMD_SET_QOS_MAP,
Johannes Bergef6243a2019-04-26 14:07:31 +020016013 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080016014 .doit = nl80211_set_qos_map,
Martin Willi5617c6c2016-05-09 18:33:58 +020016015 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016016 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080016017 },
Johannes Berg960d01a2014-09-09 22:55:35 +030016018 {
16019 .cmd = NL80211_CMD_ADD_TX_TS,
Johannes Bergef6243a2019-04-26 14:07:31 +020016020 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg960d01a2014-09-09 22:55:35 +030016021 .doit = nl80211_add_tx_ts,
Martin Willi5617c6c2016-05-09 18:33:58 +020016022 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016023 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg960d01a2014-09-09 22:55:35 +030016024 },
16025 {
16026 .cmd = NL80211_CMD_DEL_TX_TS,
Johannes Bergef6243a2019-04-26 14:07:31 +020016027 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg960d01a2014-09-09 22:55:35 +030016028 .doit = nl80211_del_tx_ts,
Martin Willi5617c6c2016-05-09 18:33:58 +020016029 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016030 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Johannes Berg960d01a2014-09-09 22:55:35 +030016031 },
Arik Nemtsov1057d352014-11-19 12:54:26 +020016032 {
16033 .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
Johannes Bergef6243a2019-04-26 14:07:31 +020016034 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arik Nemtsov1057d352014-11-19 12:54:26 +020016035 .doit = nl80211_tdls_channel_switch,
Martin Willi5617c6c2016-05-09 18:33:58 +020016036 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016037 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Arik Nemtsov1057d352014-11-19 12:54:26 +020016038 },
16039 {
16040 .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
Johannes Bergef6243a2019-04-26 14:07:31 +020016041 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arik Nemtsov1057d352014-11-19 12:54:26 +020016042 .doit = nl80211_tdls_cancel_channel_switch,
Martin Willi5617c6c2016-05-09 18:33:58 +020016043 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016044 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Arik Nemtsov1057d352014-11-19 12:54:26 +020016045 },
Michael Braunce0ce132016-10-10 19:12:22 +020016046 {
16047 .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
Johannes Bergef6243a2019-04-26 14:07:31 +020016048 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Michael Braunce0ce132016-10-10 19:12:22 +020016049 .doit = nl80211_set_multicast_to_unicast,
Michael Braunce0ce132016-10-10 19:12:22 +020016050 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016051 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Michael Braunce0ce132016-10-10 19:12:22 +020016052 },
Avraham Stern3a00df52017-06-09 13:08:43 +010016053 {
16054 .cmd = NL80211_CMD_SET_PMK,
Johannes Bergef6243a2019-04-26 14:07:31 +020016055 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Avraham Stern3a00df52017-06-09 13:08:43 +010016056 .doit = nl80211_set_pmk,
Avraham Stern3a00df52017-06-09 13:08:43 +010016057 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berga05829a2021-01-22 16:19:43 +010016058 0 |
Sunil Duttd6db02a2019-02-25 15:37:20 +053016059 NL80211_FLAG_CLEAR_SKB,
Avraham Stern3a00df52017-06-09 13:08:43 +010016060 },
16061 {
16062 .cmd = NL80211_CMD_DEL_PMK,
Johannes Bergef6243a2019-04-26 14:07:31 +020016063 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Avraham Stern3a00df52017-06-09 13:08:43 +010016064 .doit = nl80211_del_pmk,
Johannes Berga05829a2021-01-22 16:19:43 +010016065 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Avraham Stern3a00df52017-06-09 13:08:43 +010016066 },
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020016067 {
16068 .cmd = NL80211_CMD_EXTERNAL_AUTH,
Johannes Bergef6243a2019-04-26 14:07:31 +020016069 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020016070 .doit = nl80211_external_auth,
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020016071 .flags = GENL_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016072 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020016073 },
Denis Kenzior2576a9a2018-03-26 12:52:42 -050016074 {
16075 .cmd = NL80211_CMD_CONTROL_PORT_FRAME,
Johannes Bergef6243a2019-04-26 14:07:31 +020016076 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Denis Kenzior2576a9a2018-03-26 12:52:42 -050016077 .doit = nl80211_tx_control_port,
Denis Kenzior2576a9a2018-03-26 12:52:42 -050016078 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016079 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Denis Kenzior2576a9a2018-03-26 12:52:42 -050016080 },
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070016081 {
16082 .cmd = NL80211_CMD_GET_FTM_RESPONDER_STATS,
Johannes Bergef6243a2019-04-26 14:07:31 +020016083 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070016084 .doit = nl80211_get_ftm_responder_stats,
Johannes Berga05829a2021-01-22 16:19:43 +010016085 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Pradeep Kumar Chitrapu81e54d02018-09-20 17:30:09 -070016086 },
Johannes Berg9bb7e0f2018-09-10 13:29:12 +020016087 {
16088 .cmd = NL80211_CMD_PEER_MEASUREMENT_START,
Johannes Bergef6243a2019-04-26 14:07:31 +020016089 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Johannes Berg9bb7e0f2018-09-10 13:29:12 +020016090 .doit = nl80211_pmsr_start,
Johannes Berg9bb7e0f2018-09-10 13:29:12 +020016091 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016092 .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
Johannes Berg9bb7e0f2018-09-10 13:29:12 +020016093 },
Sriram R30c63112018-12-04 17:46:52 +053016094 {
16095 .cmd = NL80211_CMD_NOTIFY_RADAR,
Johannes Bergef6243a2019-04-26 14:07:31 +020016096 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Sriram R30c63112018-12-04 17:46:52 +053016097 .doit = nl80211_notify_radar_detection,
Sriram R30c63112018-12-04 17:46:52 +053016098 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016099 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Sriram R30c63112018-12-04 17:46:52 +053016100 },
Sunil Duttcb74e972019-02-20 16:18:07 +053016101 {
16102 .cmd = NL80211_CMD_UPDATE_OWE_INFO,
16103 .doit = nl80211_update_owe_info,
16104 .flags = GENL_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016105 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Sunil Duttcb74e972019-02-20 16:18:07 +053016106 },
Rajkumar Manoharan5ab92e72019-04-11 13:47:24 -070016107 {
16108 .cmd = NL80211_CMD_PROBE_MESH_LINK,
16109 .doit = nl80211_probe_mesh_link,
16110 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016111 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
Rajkumar Manoharan5ab92e72019-04-11 13:47:24 -070016112 },
Tamizh chelvam77f576d2020-01-20 13:21:22 +053016113 {
16114 .cmd = NL80211_CMD_SET_TID_CONFIG,
16115 .doit = nl80211_set_tid_config,
16116 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berga05829a2021-01-22 16:19:43 +010016117 .internal_flags = NL80211_FLAG_NEED_NETDEV,
Tamizh chelvam77f576d2020-01-20 13:21:22 +053016118 },
Carl Huang6bdb68c2020-12-03 05:37:26 -050016119 {
16120 .cmd = NL80211_CMD_SET_SAR_SPECS,
16121 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
16122 .doit = nl80211_set_sar_specs,
16123 .flags = GENL_UNS_ADMIN_PERM,
16124 .internal_flags = NL80211_FLAG_NEED_WIPHY |
16125 NL80211_FLAG_NEED_RTNL,
16126 },
John Crispin0d2ab3ae2021-07-02 19:44:07 +020016127 {
16128 .cmd = NL80211_CMD_COLOR_CHANGE_REQUEST,
16129 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
16130 .doit = nl80211_color_change,
16131 .flags = GENL_UNS_ADMIN_PERM,
16132 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
16133 NL80211_FLAG_NEED_RTNL,
16134 },
Subrat Mishrae3067842021-09-15 11:22:23 +053016135 {
16136 .cmd = NL80211_CMD_SET_FILS_AAD,
16137 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
16138 .doit = nl80211_set_fils_aad,
16139 .flags = GENL_UNS_ADMIN_PERM,
16140 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
16141 },
Johannes Berg55682962007-09-20 13:09:35 -040016142};
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016143
Johannes Berg56989f62016-10-24 14:40:05 +020016144static struct genl_family nl80211_fam __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +020016145 .name = NL80211_GENL_NAME, /* have users key off the name instead */
16146 .hdrsize = 0, /* no private header */
16147 .version = 1, /* no particular meaning now */
16148 .maxattr = NL80211_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +010016149 .policy = nl80211_policy,
Johannes Berg489111e2016-10-24 14:40:03 +020016150 .netnsok = true,
16151 .pre_doit = nl80211_pre_doit,
16152 .post_doit = nl80211_post_doit,
16153 .module = THIS_MODULE,
16154 .ops = nl80211_ops,
16155 .n_ops = ARRAY_SIZE(nl80211_ops),
Jakub Kicinski66a9b922020-10-02 14:49:54 -070016156 .small_ops = nl80211_small_ops,
16157 .n_small_ops = ARRAY_SIZE(nl80211_small_ops),
Johannes Berg489111e2016-10-24 14:40:03 +020016158 .mcgrps = nl80211_mcgrps,
16159 .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
Johannes Berg50508d92019-07-29 16:31:09 +020016160 .parallel_ops = true,
Johannes Berg489111e2016-10-24 14:40:03 +020016161};
16162
Johannes Berg55682962007-09-20 13:09:35 -040016163/* notification functions */
16164
Johannes Berg3bb20552014-05-26 13:52:25 +020016165void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
16166 enum nl80211_commands cmd)
Johannes Berg55682962007-09-20 13:09:35 -040016167{
16168 struct sk_buff *msg;
Johannes Berg86e8cf92013-06-19 10:57:22 +020016169 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -040016170
Johannes Berg3bb20552014-05-26 13:52:25 +020016171 WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
16172 cmd != NL80211_CMD_DEL_WIPHY);
16173
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070016174 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040016175 if (!msg)
16176 return;
16177
Johannes Berg3bb20552014-05-26 13:52:25 +020016178 if (nl80211_send_wiphy(rdev, cmd, msg, 0, 0, 0, &state) < 0) {
Johannes Berg55682962007-09-20 13:09:35 -040016179 nlmsg_free(msg);
16180 return;
16181 }
16182
Johannes Berg68eb5502013-11-19 15:19:38 +010016183 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016184 NL80211_MCGRP_CONFIG, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040016185}
16186
Denis Kenzior896ff062016-08-03 16:58:33 -050016187void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
16188 struct wireless_dev *wdev,
16189 enum nl80211_commands cmd)
16190{
16191 struct sk_buff *msg;
16192
Denis Kenzior896ff062016-08-03 16:58:33 -050016193 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
16194 if (!msg)
16195 return;
16196
Andrew Zaborowski3d1a5bb2018-10-19 23:19:06 +020016197 if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, cmd) < 0) {
Denis Kenzior896ff062016-08-03 16:58:33 -050016198 nlmsg_free(msg);
16199 return;
16200 }
16201
16202 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16203 NL80211_MCGRP_CONFIG, GFP_KERNEL);
16204}
16205
Johannes Berg362a4152009-05-24 16:43:15 +020016206static int nl80211_add_scan_req(struct sk_buff *msg,
16207 struct cfg80211_registered_device *rdev)
16208{
16209 struct cfg80211_scan_request *req = rdev->scan_req;
16210 struct nlattr *nest;
16211 int i;
Tova Mussaic8cb5b82020-09-18 11:33:13 +020016212 struct cfg80211_scan_info *info;
Johannes Berg362a4152009-05-24 16:43:15 +020016213
16214 if (WARN_ON(!req))
16215 return 0;
16216
Michal Kubecekae0be8d2019-04-26 11:13:06 +020016217 nest = nla_nest_start_noflag(msg, NL80211_ATTR_SCAN_SSIDS);
Johannes Berg362a4152009-05-24 16:43:15 +020016218 if (!nest)
16219 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040016220 for (i = 0; i < req->n_ssids; i++) {
16221 if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
16222 goto nla_put_failure;
16223 }
Johannes Berg362a4152009-05-24 16:43:15 +020016224 nla_nest_end(msg, nest);
16225
Thomas Pedersen2032f3b2020-04-30 10:25:52 -070016226 if (req->flags & NL80211_SCAN_FLAG_FREQ_KHZ) {
16227 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQ_KHZ);
16228 if (!nest)
David S. Miller9360ffd2012-03-29 04:41:26 -040016229 goto nla_put_failure;
Thomas Pedersen2032f3b2020-04-30 10:25:52 -070016230 for (i = 0; i < req->n_channels; i++) {
16231 if (nla_put_u32(msg, i,
16232 ieee80211_channel_to_khz(req->channels[i])))
16233 goto nla_put_failure;
16234 }
16235 nla_nest_end(msg, nest);
16236 } else {
16237 nest = nla_nest_start_noflag(msg,
16238 NL80211_ATTR_SCAN_FREQUENCIES);
16239 if (!nest)
16240 goto nla_put_failure;
16241 for (i = 0; i < req->n_channels; i++) {
16242 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
16243 goto nla_put_failure;
16244 }
16245 nla_nest_end(msg, nest);
David S. Miller9360ffd2012-03-29 04:41:26 -040016246 }
Johannes Berg362a4152009-05-24 16:43:15 +020016247
David S. Miller9360ffd2012-03-29 04:41:26 -040016248 if (req->ie &&
16249 nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
16250 goto nla_put_failure;
Johannes Berg362a4152009-05-24 16:43:15 +020016251
Johannes Bergae917c92013-10-25 11:05:22 +020016252 if (req->flags &&
16253 nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
16254 goto nla_put_failure;
Sam Lefflered4737712012-10-11 21:03:31 -070016255
Tova Mussaic8cb5b82020-09-18 11:33:13 +020016256 info = rdev->int_scan_req ? &rdev->int_scan_req->info :
16257 &rdev->scan_req->info;
16258 if (info->scan_start_tsf &&
Avraham Stern1d762502016-07-05 17:10:13 +030016259 (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
Tova Mussaic8cb5b82020-09-18 11:33:13 +020016260 info->scan_start_tsf, NL80211_BSS_PAD) ||
Avraham Stern1d762502016-07-05 17:10:13 +030016261 nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
Tova Mussaic8cb5b82020-09-18 11:33:13 +020016262 info->tsf_bssid)))
Avraham Stern1d762502016-07-05 17:10:13 +030016263 goto nla_put_failure;
16264
Johannes Berg362a4152009-05-24 16:43:15 +020016265 return 0;
16266 nla_put_failure:
16267 return -ENOBUFS;
16268}
16269
Arend Van Spriel505a2e82016-12-16 11:21:54 +000016270static int nl80211_prep_scan_msg(struct sk_buff *msg,
Johannes Berga538e2d2009-06-16 19:56:42 +020016271 struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020016272 struct wireless_dev *wdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000016273 u32 portid, u32 seq, int flags,
Johannes Berga538e2d2009-06-16 19:56:42 +020016274 u32 cmd)
Johannes Berg2a519312009-02-10 21:25:55 +010016275{
16276 void *hdr;
16277
Eric W. Biederman15e47302012-09-07 20:12:54 +000016278 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg2a519312009-02-10 21:25:55 +010016279 if (!hdr)
16280 return -1;
16281
David S. Miller9360ffd2012-03-29 04:41:26 -040016282 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Bergfd014282012-06-18 19:17:03 +020016283 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
16284 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020016285 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
16286 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040016287 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +010016288
Johannes Berg362a4152009-05-24 16:43:15 +020016289 /* ignore errors and send incomplete event anyway */
16290 nl80211_add_scan_req(msg, rdev);
Johannes Berg2a519312009-02-10 21:25:55 +010016291
Johannes Berg053c0952015-01-16 22:09:00 +010016292 genlmsg_end(msg, hdr);
16293 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +010016294
16295 nla_put_failure:
16296 genlmsg_cancel(msg, hdr);
16297 return -EMSGSIZE;
16298}
16299
Luciano Coelho807f8a82011-05-11 17:09:35 +030016300static int
Arend Van Spriel505a2e82016-12-16 11:21:54 +000016301nl80211_prep_sched_scan_msg(struct sk_buff *msg,
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010016302 struct cfg80211_sched_scan_request *req, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030016303{
16304 void *hdr;
16305
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010016306 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Luciano Coelho807f8a82011-05-11 17:09:35 +030016307 if (!hdr)
16308 return -1;
16309
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010016310 if (nla_put_u32(msg, NL80211_ATTR_WIPHY,
16311 wiphy_to_rdev(req->wiphy)->wiphy_idx) ||
16312 nla_put_u32(msg, NL80211_ATTR_IFINDEX, req->dev->ifindex) ||
16313 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->reqid,
16314 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040016315 goto nla_put_failure;
Luciano Coelho807f8a82011-05-11 17:09:35 +030016316
Johannes Berg053c0952015-01-16 22:09:00 +010016317 genlmsg_end(msg, hdr);
16318 return 0;
Luciano Coelho807f8a82011-05-11 17:09:35 +030016319
16320 nla_put_failure:
16321 genlmsg_cancel(msg, hdr);
16322 return -EMSGSIZE;
16323}
16324
Johannes Berga538e2d2009-06-16 19:56:42 +020016325void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020016326 struct wireless_dev *wdev)
Johannes Berga538e2d2009-06-16 19:56:42 +020016327{
16328 struct sk_buff *msg;
16329
Thomas Graf58050fc2012-06-28 03:57:45 +000016330 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020016331 if (!msg)
16332 return;
16333
Arend Van Spriel505a2e82016-12-16 11:21:54 +000016334 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Berga538e2d2009-06-16 19:56:42 +020016335 NL80211_CMD_TRIGGER_SCAN) < 0) {
16336 nlmsg_free(msg);
16337 return;
16338 }
16339
Johannes Berg68eb5502013-11-19 15:19:38 +010016340 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016341 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020016342}
16343
Johannes Bergf9d15d12014-01-22 11:14:19 +020016344struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
16345 struct wireless_dev *wdev, bool aborted)
Johannes Berg2a519312009-02-10 21:25:55 +010016346{
16347 struct sk_buff *msg;
16348
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070016349 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010016350 if (!msg)
Johannes Bergf9d15d12014-01-22 11:14:19 +020016351 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010016352
Arend Van Spriel505a2e82016-12-16 11:21:54 +000016353 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Bergf9d15d12014-01-22 11:14:19 +020016354 aborted ? NL80211_CMD_SCAN_ABORTED :
16355 NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +010016356 nlmsg_free(msg);
Johannes Bergf9d15d12014-01-22 11:14:19 +020016357 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010016358 }
16359
Johannes Bergf9d15d12014-01-22 11:14:19 +020016360 return msg;
Johannes Berg2a519312009-02-10 21:25:55 +010016361}
16362
Arend Van Spriel505a2e82016-12-16 11:21:54 +000016363/* send message created by nl80211_build_scan_msg() */
16364void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
16365 struct sk_buff *msg)
Johannes Berg2a519312009-02-10 21:25:55 +010016366{
Johannes Berg2a519312009-02-10 21:25:55 +010016367 if (!msg)
16368 return;
16369
Johannes Berg68eb5502013-11-19 15:19:38 +010016370 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016371 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010016372}
16373
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010016374void nl80211_send_sched_scan(struct cfg80211_sched_scan_request *req, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030016375{
16376 struct sk_buff *msg;
16377
Thomas Graf58050fc2012-06-28 03:57:45 +000016378 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030016379 if (!msg)
16380 return;
16381
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010016382 if (nl80211_prep_sched_scan_msg(msg, req, cmd) < 0) {
Luciano Coelho807f8a82011-05-11 17:09:35 +030016383 nlmsg_free(msg);
16384 return;
16385 }
16386
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010016387 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(req->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016388 NL80211_MCGRP_SCAN, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030016389}
16390
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020016391static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
16392 struct regulatory_request *request)
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040016393{
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040016394 /* Userspace can always count this one always being set */
David S. Miller9360ffd2012-03-29 04:41:26 -040016395 if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
16396 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040016397
David S. Miller9360ffd2012-03-29 04:41:26 -040016398 if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
16399 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
16400 NL80211_REGDOM_TYPE_WORLD))
16401 goto nla_put_failure;
16402 } else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
16403 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
16404 NL80211_REGDOM_TYPE_CUSTOM_WORLD))
16405 goto nla_put_failure;
16406 } else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
16407 request->intersect) {
16408 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
16409 NL80211_REGDOM_TYPE_INTERSECTION))
16410 goto nla_put_failure;
16411 } else {
16412 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
16413 NL80211_REGDOM_TYPE_COUNTRY) ||
16414 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
16415 request->alpha2))
16416 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040016417 }
16418
Arik Nemtsovad30ca22014-12-15 19:25:59 +020016419 if (request->wiphy_idx != WIPHY_IDX_INVALID) {
16420 struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
16421
16422 if (wiphy &&
16423 nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
16424 goto nla_put_failure;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +020016425
16426 if (wiphy &&
16427 wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
16428 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
16429 goto nla_put_failure;
Arik Nemtsovad30ca22014-12-15 19:25:59 +020016430 }
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040016431
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020016432 return true;
16433
16434nla_put_failure:
16435 return false;
16436}
16437
16438/*
16439 * This can happen on global regulatory changes or device specific settings
16440 * based on custom regulatory domains.
16441 */
16442void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
16443 struct regulatory_request *request)
16444{
16445 struct sk_buff *msg;
16446 void *hdr;
16447
16448 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
16449 if (!msg)
16450 return;
16451
16452 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
zhong jiang24f6d762019-09-05 12:25:37 +080016453 if (!hdr)
16454 goto nla_put_failure;
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020016455
zhong jiang24f6d762019-09-05 12:25:37 +080016456 if (!nl80211_reg_change_event_fill(msg, request))
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020016457 goto nla_put_failure;
16458
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016459 genlmsg_end(msg, hdr);
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040016460
Johannes Bergbc43b282009-07-25 10:54:13 +020016461 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010016462 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016463 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Bergbc43b282009-07-25 10:54:13 +020016464 rcu_read_unlock();
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040016465
16466 return;
16467
16468nla_put_failure:
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040016469 nlmsg_free(msg);
16470}
16471
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016472static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
16473 struct net_device *netdev,
16474 const u8 *buf, size_t len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030016475 enum nl80211_commands cmd, gfp_t gfp,
Jouni Malinen4d9ec732019-02-15 02:14:33 +020016476 int uapsd_queues, const u8 *req_ies,
Johannes Berg3bb02142020-12-06 14:54:42 +020016477 size_t req_ies_len, bool reconnect)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016478{
16479 struct sk_buff *msg;
16480 void *hdr;
16481
Jouni Malinen4d9ec732019-02-15 02:14:33 +020016482 msg = nlmsg_new(100 + len + req_ies_len, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016483 if (!msg)
16484 return;
16485
16486 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
16487 if (!hdr) {
16488 nlmsg_free(msg);
16489 return;
16490 }
16491
David S. Miller9360ffd2012-03-29 04:41:26 -040016492 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16493 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Jouni Malinen4d9ec732019-02-15 02:14:33 +020016494 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
16495 (req_ies &&
16496 nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies)))
David S. Miller9360ffd2012-03-29 04:41:26 -040016497 goto nla_put_failure;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016498
Johannes Berg3bb02142020-12-06 14:54:42 +020016499 if (reconnect && nla_put_flag(msg, NL80211_ATTR_RECONNECT_REQUESTED))
16500 goto nla_put_failure;
16501
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030016502 if (uapsd_queues >= 0) {
16503 struct nlattr *nla_wmm =
Michal Kubecekae0be8d2019-04-26 11:13:06 +020016504 nla_nest_start_noflag(msg, NL80211_ATTR_STA_WME);
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030016505 if (!nla_wmm)
16506 goto nla_put_failure;
16507
16508 if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
16509 uapsd_queues))
16510 goto nla_put_failure;
16511
16512 nla_nest_end(msg, nla_wmm);
16513 }
16514
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016515 genlmsg_end(msg, hdr);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016516
Johannes Berg68eb5502013-11-19 15:19:38 +010016517 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016518 NL80211_MCGRP_MLME, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016519 return;
16520
16521 nla_put_failure:
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016522 nlmsg_free(msg);
16523}
16524
16525void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020016526 struct net_device *netdev, const u8 *buf,
16527 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016528{
16529 nl80211_send_mlme_event(rdev, netdev, buf, len,
Johannes Berg3bb02142020-12-06 14:54:42 +020016530 NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0,
16531 false);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016532}
16533
16534void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
16535 struct net_device *netdev, const u8 *buf,
Jouni Malinen4d9ec732019-02-15 02:14:33 +020016536 size_t len, gfp_t gfp, int uapsd_queues,
16537 const u8 *req_ies, size_t req_ies_len)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016538{
Johannes Berge6d6e342009-07-01 21:26:47 +020016539 nl80211_send_mlme_event(rdev, netdev, buf, len,
Jouni Malinen4d9ec732019-02-15 02:14:33 +020016540 NL80211_CMD_ASSOCIATE, gfp, uapsd_queues,
Johannes Berg3bb02142020-12-06 14:54:42 +020016541 req_ies, req_ies_len, false);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016542}
16543
Jouni Malinen53b46b82009-03-27 20:53:56 +020016544void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020016545 struct net_device *netdev, const u8 *buf,
Johannes Berg3bb02142020-12-06 14:54:42 +020016546 size_t len, bool reconnect, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016547{
16548 nl80211_send_mlme_event(rdev, netdev, buf, len,
Johannes Berg3bb02142020-12-06 14:54:42 +020016549 NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0,
16550 reconnect);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016551}
16552
Jouni Malinen53b46b82009-03-27 20:53:56 +020016553void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
16554 struct net_device *netdev, const u8 *buf,
Johannes Berg3bb02142020-12-06 14:54:42 +020016555 size_t len, bool reconnect, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016556{
16557 nl80211_send_mlme_event(rdev, netdev, buf, len,
Johannes Berg3bb02142020-12-06 14:54:42 +020016558 NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0,
16559 reconnect);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016560}
16561
Johannes Berg6ff57cf2013-05-16 00:55:00 +020016562void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
16563 size_t len)
Jouni Malinencf4e5942010-12-16 00:52:40 +020016564{
Johannes Berg947add32013-02-22 22:05:20 +010016565 struct wireless_dev *wdev = dev->ieee80211_ptr;
16566 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016567 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg6ff57cf2013-05-16 00:55:00 +020016568 const struct ieee80211_mgmt *mgmt = (void *)buf;
16569 u32 cmd;
Jouni Malinencf4e5942010-12-16 00:52:40 +020016570
Johannes Berg6ff57cf2013-05-16 00:55:00 +020016571 if (WARN_ON(len < 2))
16572 return;
16573
Jouni Malinen4d797fc2020-04-01 17:25:47 +030016574 if (ieee80211_is_deauth(mgmt->frame_control)) {
Johannes Berg6ff57cf2013-05-16 00:55:00 +020016575 cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
Jouni Malinen4d797fc2020-04-01 17:25:47 +030016576 } else if (ieee80211_is_disassoc(mgmt->frame_control)) {
Johannes Berg6ff57cf2013-05-16 00:55:00 +020016577 cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
Jouni Malinen4d797fc2020-04-01 17:25:47 +030016578 } else if (ieee80211_is_beacon(mgmt->frame_control)) {
16579 if (wdev->unprot_beacon_reported &&
16580 elapsed_jiffies_msecs(wdev->unprot_beacon_reported) < 10000)
16581 return;
16582 cmd = NL80211_CMD_UNPROT_BEACON;
16583 wdev->unprot_beacon_reported = jiffies;
16584 } else {
16585 return;
16586 }
Johannes Berg6ff57cf2013-05-16 00:55:00 +020016587
16588 trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
Jouni Malinen4d9ec732019-02-15 02:14:33 +020016589 nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1,
Johannes Berg3bb02142020-12-06 14:54:42 +020016590 NULL, 0, false);
Jouni Malinencf4e5942010-12-16 00:52:40 +020016591}
Johannes Berg6ff57cf2013-05-16 00:55:00 +020016592EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
Jouni Malinencf4e5942010-12-16 00:52:40 +020016593
Luis R. Rodriguez1b06bb42009-05-02 00:34:48 -040016594static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
16595 struct net_device *netdev, int cmd,
Johannes Berge6d6e342009-07-01 21:26:47 +020016596 const u8 *addr, gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030016597{
16598 struct sk_buff *msg;
16599 void *hdr;
16600
Johannes Berge6d6e342009-07-01 21:26:47 +020016601 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030016602 if (!msg)
16603 return;
16604
16605 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
16606 if (!hdr) {
16607 nlmsg_free(msg);
16608 return;
16609 }
16610
David S. Miller9360ffd2012-03-29 04:41:26 -040016611 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16612 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
16613 nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
16614 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
16615 goto nla_put_failure;
Jouni Malinen1965c852009-04-22 21:38:25 +030016616
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016617 genlmsg_end(msg, hdr);
Jouni Malinen1965c852009-04-22 21:38:25 +030016618
Johannes Berg68eb5502013-11-19 15:19:38 +010016619 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016620 NL80211_MCGRP_MLME, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030016621 return;
16622
16623 nla_put_failure:
Jouni Malinen1965c852009-04-22 21:38:25 +030016624 nlmsg_free(msg);
16625}
16626
16627void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020016628 struct net_device *netdev, const u8 *addr,
16629 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030016630{
16631 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
Johannes Berge6d6e342009-07-01 21:26:47 +020016632 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030016633}
16634
16635void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020016636 struct net_device *netdev, const u8 *addr,
16637 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030016638{
Johannes Berge6d6e342009-07-01 21:26:47 +020016639 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
16640 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030016641}
16642
Samuel Ortizb23aa672009-07-01 21:26:54 +020016643void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030016644 struct net_device *netdev,
16645 struct cfg80211_connect_resp_params *cr,
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020016646 gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020016647{
16648 struct sk_buff *msg;
16649 void *hdr;
16650
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030016651 msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
Arend Van Spriel76804d22018-05-22 10:19:06 +020016652 cr->fils.kek_len + cr->fils.pmk_len +
16653 (cr->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016654 if (!msg)
16655 return;
16656
16657 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
16658 if (!hdr) {
16659 nlmsg_free(msg);
16660 return;
16661 }
16662
David S. Miller9360ffd2012-03-29 04:41:26 -040016663 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16664 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030016665 (cr->bssid &&
16666 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
Jouni Malinenbf1ecd22016-05-31 00:16:50 +030016667 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030016668 cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
16669 cr->status) ||
16670 (cr->status < 0 &&
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020016671 (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030016672 nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
16673 cr->timeout_reason))) ||
16674 (cr->req_ie &&
16675 nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
16676 (cr->resp_ie &&
16677 nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030016678 cr->resp_ie)) ||
Arend Van Spriel76804d22018-05-22 10:19:06 +020016679 (cr->fils.update_erp_next_seq_num &&
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030016680 nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
Arend Van Spriel76804d22018-05-22 10:19:06 +020016681 cr->fils.erp_next_seq_num)) ||
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030016682 (cr->status == WLAN_STATUS_SUCCESS &&
Arend Van Spriel76804d22018-05-22 10:19:06 +020016683 ((cr->fils.kek &&
16684 nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils.kek_len,
16685 cr->fils.kek)) ||
16686 (cr->fils.pmk &&
16687 nla_put(msg, NL80211_ATTR_PMK, cr->fils.pmk_len, cr->fils.pmk)) ||
16688 (cr->fils.pmkid &&
16689 nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->fils.pmkid)))))
David S. Miller9360ffd2012-03-29 04:41:26 -040016690 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020016691
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016692 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016693
Johannes Berg68eb5502013-11-19 15:19:38 +010016694 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016695 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016696 return;
16697
16698 nla_put_failure:
Samuel Ortizb23aa672009-07-01 21:26:54 +020016699 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016700}
16701
16702void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
Avraham Stern29ce6ec2017-04-26 10:58:49 +030016703 struct net_device *netdev,
16704 struct cfg80211_roam_info *info, gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020016705{
16706 struct sk_buff *msg;
16707 void *hdr;
Avraham Stern29ce6ec2017-04-26 10:58:49 +030016708 const u8 *bssid = info->bss ? info->bss->bssid : info->bssid;
Samuel Ortizb23aa672009-07-01 21:26:54 +020016709
Arend Van Spriele841b7b2018-05-22 10:19:07 +020016710 msg = nlmsg_new(100 + info->req_ie_len + info->resp_ie_len +
16711 info->fils.kek_len + info->fils.pmk_len +
16712 (info->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016713 if (!msg)
16714 return;
16715
16716 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
16717 if (!hdr) {
16718 nlmsg_free(msg);
16719 return;
16720 }
16721
David S. Miller9360ffd2012-03-29 04:41:26 -040016722 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16723 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
16724 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
Avraham Stern29ce6ec2017-04-26 10:58:49 +030016725 (info->req_ie &&
16726 nla_put(msg, NL80211_ATTR_REQ_IE, info->req_ie_len,
16727 info->req_ie)) ||
16728 (info->resp_ie &&
16729 nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
Arend Van Spriele841b7b2018-05-22 10:19:07 +020016730 info->resp_ie)) ||
16731 (info->fils.update_erp_next_seq_num &&
16732 nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
16733 info->fils.erp_next_seq_num)) ||
16734 (info->fils.kek &&
16735 nla_put(msg, NL80211_ATTR_FILS_KEK, info->fils.kek_len,
16736 info->fils.kek)) ||
16737 (info->fils.pmk &&
16738 nla_put(msg, NL80211_ATTR_PMK, info->fils.pmk_len, info->fils.pmk)) ||
16739 (info->fils.pmkid &&
16740 nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, info->fils.pmkid)))
David S. Miller9360ffd2012-03-29 04:41:26 -040016741 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020016742
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016743 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016744
Johannes Berg68eb5502013-11-19 15:19:38 +010016745 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016746 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016747 return;
16748
16749 nla_put_failure:
Samuel Ortizb23aa672009-07-01 21:26:54 +020016750 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016751}
16752
Avraham Stern503c1fb2017-09-29 14:21:49 +020016753void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
16754 struct net_device *netdev, const u8 *bssid)
16755{
16756 struct sk_buff *msg;
16757 void *hdr;
16758
16759 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
16760 if (!msg)
16761 return;
16762
16763 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PORT_AUTHORIZED);
16764 if (!hdr) {
16765 nlmsg_free(msg);
16766 return;
16767 }
16768
Chung-Hsien Hsuf4d75992019-05-09 09:48:25 +000016769 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16770 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
16771 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
Avraham Stern503c1fb2017-09-29 14:21:49 +020016772 goto nla_put_failure;
16773
16774 genlmsg_end(msg, hdr);
16775
16776 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16777 NL80211_MCGRP_MLME, GFP_KERNEL);
16778 return;
16779
16780 nla_put_failure:
Avraham Stern503c1fb2017-09-29 14:21:49 +020016781 nlmsg_free(msg);
16782}
16783
Samuel Ortizb23aa672009-07-01 21:26:54 +020016784void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
16785 struct net_device *netdev, u16 reason,
Johannes Berg667503d2009-07-07 03:56:11 +020016786 const u8 *ie, size_t ie_len, bool from_ap)
Samuel Ortizb23aa672009-07-01 21:26:54 +020016787{
16788 struct sk_buff *msg;
16789 void *hdr;
16790
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010016791 msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016792 if (!msg)
16793 return;
16794
16795 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
16796 if (!hdr) {
16797 nlmsg_free(msg);
16798 return;
16799 }
16800
David S. Miller9360ffd2012-03-29 04:41:26 -040016801 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16802 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
David Spinadel86b6c462017-12-18 12:14:05 +020016803 (reason &&
David S. Miller9360ffd2012-03-29 04:41:26 -040016804 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
16805 (from_ap &&
16806 nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
16807 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
16808 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020016809
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016810 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016811
Johannes Berg68eb5502013-11-19 15:19:38 +010016812 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016813 NL80211_MCGRP_MLME, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016814 return;
16815
16816 nla_put_failure:
Samuel Ortizb23aa672009-07-01 21:26:54 +020016817 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020016818}
16819
Johannes Berg04a773a2009-04-19 21:24:32 +020016820void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
16821 struct net_device *netdev, const u8 *bssid,
16822 gfp_t gfp)
16823{
16824 struct sk_buff *msg;
16825 void *hdr;
16826
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070016827 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020016828 if (!msg)
16829 return;
16830
16831 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
16832 if (!hdr) {
16833 nlmsg_free(msg);
16834 return;
16835 }
16836
David S. Miller9360ffd2012-03-29 04:41:26 -040016837 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16838 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
16839 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
16840 goto nla_put_failure;
Johannes Berg04a773a2009-04-19 21:24:32 +020016841
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016842 genlmsg_end(msg, hdr);
Johannes Berg04a773a2009-04-19 21:24:32 +020016843
Johannes Berg68eb5502013-11-19 15:19:38 +010016844 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016845 NL80211_MCGRP_MLME, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020016846 return;
16847
16848 nla_put_failure:
Johannes Berg04a773a2009-04-19 21:24:32 +020016849 nlmsg_free(msg);
16850}
16851
Johannes Berg947add32013-02-22 22:05:20 +010016852void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
Bob Copelandecbc12a2018-10-26 10:03:50 -040016853 const u8 *ie, u8 ie_len,
16854 int sig_dbm, gfp_t gfp)
Javier Cardonac93b5e72011-04-07 15:08:34 -070016855{
Johannes Berg947add32013-02-22 22:05:20 +010016856 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080016857 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Javier Cardonac93b5e72011-04-07 15:08:34 -070016858 struct sk_buff *msg;
16859 void *hdr;
16860
Johannes Berg947add32013-02-22 22:05:20 +010016861 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
16862 return;
16863
16864 trace_cfg80211_notify_new_peer_candidate(dev, addr);
16865
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010016866 msg = nlmsg_new(100 + ie_len, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070016867 if (!msg)
16868 return;
16869
16870 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
16871 if (!hdr) {
16872 nlmsg_free(msg);
16873 return;
16874 }
16875
David S. Miller9360ffd2012-03-29 04:41:26 -040016876 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010016877 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
16878 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040016879 (ie_len && ie &&
Bob Copelandecbc12a2018-10-26 10:03:50 -040016880 nla_put(msg, NL80211_ATTR_IE, ie_len, ie)) ||
16881 (sig_dbm &&
16882 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)))
David S. Miller9360ffd2012-03-29 04:41:26 -040016883 goto nla_put_failure;
Javier Cardonac93b5e72011-04-07 15:08:34 -070016884
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016885 genlmsg_end(msg, hdr);
Javier Cardonac93b5e72011-04-07 15:08:34 -070016886
Johannes Berg68eb5502013-11-19 15:19:38 +010016887 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016888 NL80211_MCGRP_MLME, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070016889 return;
16890
16891 nla_put_failure:
Javier Cardonac93b5e72011-04-07 15:08:34 -070016892 nlmsg_free(msg);
16893}
Johannes Berg947add32013-02-22 22:05:20 +010016894EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
Javier Cardonac93b5e72011-04-07 15:08:34 -070016895
Jouni Malinena3b8b052009-03-27 21:59:49 +020016896void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
16897 struct net_device *netdev, const u8 *addr,
16898 enum nl80211_key_type key_type, int key_id,
Johannes Berge6d6e342009-07-01 21:26:47 +020016899 const u8 *tsc, gfp_t gfp)
Jouni Malinena3b8b052009-03-27 21:59:49 +020016900{
16901 struct sk_buff *msg;
16902 void *hdr;
16903
Johannes Berge6d6e342009-07-01 21:26:47 +020016904 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020016905 if (!msg)
16906 return;
16907
16908 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
16909 if (!hdr) {
16910 nlmsg_free(msg);
16911 return;
16912 }
16913
David S. Miller9360ffd2012-03-29 04:41:26 -040016914 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16915 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
16916 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
16917 nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
16918 (key_id != -1 &&
16919 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
16920 (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
16921 goto nla_put_failure;
Jouni Malinena3b8b052009-03-27 21:59:49 +020016922
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016923 genlmsg_end(msg, hdr);
Jouni Malinena3b8b052009-03-27 21:59:49 +020016924
Johannes Berg68eb5502013-11-19 15:19:38 +010016925 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016926 NL80211_MCGRP_MLME, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020016927 return;
16928
16929 nla_put_failure:
Jouni Malinena3b8b052009-03-27 21:59:49 +020016930 nlmsg_free(msg);
16931}
16932
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016933void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
16934 struct ieee80211_channel *channel_before,
16935 struct ieee80211_channel *channel_after)
16936{
16937 struct sk_buff *msg;
16938 void *hdr;
16939 struct nlattr *nl_freq;
16940
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070016941 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016942 if (!msg)
16943 return;
16944
16945 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
16946 if (!hdr) {
16947 nlmsg_free(msg);
16948 return;
16949 }
16950
16951 /*
16952 * Since we are applying the beacon hint to a wiphy we know its
16953 * wiphy_idx is valid
16954 */
David S. Miller9360ffd2012-03-29 04:41:26 -040016955 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
16956 goto nla_put_failure;
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016957
16958 /* Before */
Michal Kubecekae0be8d2019-04-26 11:13:06 +020016959 nl_freq = nla_nest_start_noflag(msg, NL80211_ATTR_FREQ_BEFORE);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016960 if (!nl_freq)
16961 goto nla_put_failure;
Haim Dreyfuss50f32712018-04-20 13:49:26 +030016962
16963 if (nl80211_msg_put_channel(msg, wiphy, channel_before, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016964 goto nla_put_failure;
16965 nla_nest_end(msg, nl_freq);
16966
16967 /* After */
Michal Kubecekae0be8d2019-04-26 11:13:06 +020016968 nl_freq = nla_nest_start_noflag(msg, NL80211_ATTR_FREQ_AFTER);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016969 if (!nl_freq)
16970 goto nla_put_failure;
Haim Dreyfuss50f32712018-04-20 13:49:26 +030016971
16972 if (nl80211_msg_put_channel(msg, wiphy, channel_after, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016973 goto nla_put_failure;
16974 nla_nest_end(msg, nl_freq);
16975
Johannes Berg3b7b72e2011-10-22 19:05:51 +020016976 genlmsg_end(msg, hdr);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016977
Johannes Berg463d0182009-07-14 00:33:35 +020016978 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010016979 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010016980 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Berg463d0182009-07-14 00:33:35 +020016981 rcu_read_unlock();
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016982
16983 return;
16984
16985nla_put_failure:
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040016986 nlmsg_free(msg);
16987}
16988
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016989static void nl80211_send_remain_on_chan_event(
16990 int cmd, struct cfg80211_registered_device *rdev,
Johannes Berg71bbc992012-06-15 15:30:18 +020016991 struct wireless_dev *wdev, u64 cookie,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016992 struct ieee80211_channel *chan,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010016993 unsigned int duration, gfp_t gfp)
16994{
16995 struct sk_buff *msg;
16996 void *hdr;
16997
16998 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16999 if (!msg)
17000 return;
17001
17002 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
17003 if (!hdr) {
17004 nlmsg_free(msg);
17005 return;
17006 }
17007
David S. Miller9360ffd2012-03-29 04:41:26 -040017008 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020017009 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
17010 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020017011 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
17012 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040017013 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
Johannes Berg42d97a52012-11-08 18:31:02 +010017014 nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
17015 NL80211_CHAN_NO_HT) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020017016 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
17017 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040017018 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017019
David S. Miller9360ffd2012-03-29 04:41:26 -040017020 if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
17021 nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
17022 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017023
Johannes Berg3b7b72e2011-10-22 19:05:51 +020017024 genlmsg_end(msg, hdr);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017025
Johannes Berg68eb5502013-11-19 15:19:38 +010017026 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017027 NL80211_MCGRP_MLME, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017028 return;
17029
17030 nla_put_failure:
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017031 nlmsg_free(msg);
17032}
17033
Johannes Berg947add32013-02-22 22:05:20 +010017034void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
17035 struct ieee80211_channel *chan,
17036 unsigned int duration, gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017037{
Johannes Berg947add32013-02-22 22:05:20 +010017038 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017039 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010017040
17041 trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017042 nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
Johannes Berg71bbc992012-06-15 15:30:18 +020017043 rdev, wdev, cookie, chan,
Johannes Berg42d97a52012-11-08 18:31:02 +010017044 duration, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017045}
Johannes Berg947add32013-02-22 22:05:20 +010017046EXPORT_SYMBOL(cfg80211_ready_on_channel);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017047
Johannes Berg947add32013-02-22 22:05:20 +010017048void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
17049 struct ieee80211_channel *chan,
17050 gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017051{
Johannes Berg947add32013-02-22 22:05:20 +010017052 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017053 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010017054
17055 trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017056 nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
Johannes Berg42d97a52012-11-08 18:31:02 +010017057 rdev, wdev, cookie, chan, 0, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017058}
Johannes Berg947add32013-02-22 22:05:20 +010017059EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010017060
James Prestwood1c38c7f2019-06-12 12:35:09 -070017061void cfg80211_tx_mgmt_expired(struct wireless_dev *wdev, u64 cookie,
17062 struct ieee80211_channel *chan,
17063 gfp_t gfp)
17064{
17065 struct wiphy *wiphy = wdev->wiphy;
17066 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
17067
17068 trace_cfg80211_tx_mgmt_expired(wdev, cookie, chan);
17069 nl80211_send_remain_on_chan_event(NL80211_CMD_FRAME_WAIT_CANCEL,
17070 rdev, wdev, cookie, chan, 0, gfp);
17071}
17072EXPORT_SYMBOL(cfg80211_tx_mgmt_expired);
17073
Johannes Berg947add32013-02-22 22:05:20 +010017074void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
17075 struct station_info *sinfo, gfp_t gfp)
Johannes Berg98b62182009-12-23 13:15:44 +010017076{
Johannes Berg947add32013-02-22 22:05:20 +010017077 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017078 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg98b62182009-12-23 13:15:44 +010017079 struct sk_buff *msg;
17080
Johannes Berg947add32013-02-22 22:05:20 +010017081 trace_cfg80211_new_sta(dev, mac_addr, sinfo);
17082
Thomas Graf58050fc2012-06-28 03:57:45 +000017083 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010017084 if (!msg)
17085 return;
17086
Johannes Bergcf5ead82014-11-14 17:14:00 +010017087 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
John W. Linville66266b32012-03-15 13:25:41 -040017088 rdev, dev, mac_addr, sinfo) < 0) {
Johannes Berg98b62182009-12-23 13:15:44 +010017089 nlmsg_free(msg);
17090 return;
17091 }
17092
Johannes Berg68eb5502013-11-19 15:19:38 +010017093 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017094 NL80211_MCGRP_MLME, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010017095}
Johannes Berg947add32013-02-22 22:05:20 +010017096EXPORT_SYMBOL(cfg80211_new_sta);
Johannes Berg98b62182009-12-23 13:15:44 +010017097
Johannes Bergcf5ead82014-11-14 17:14:00 +010017098void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
17099 struct station_info *sinfo, gfp_t gfp)
Jouni Malinenec15e682011-03-23 15:29:52 +020017100{
Johannes Berg947add32013-02-22 22:05:20 +010017101 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017102 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinenec15e682011-03-23 15:29:52 +020017103 struct sk_buff *msg;
Johannes Berg73887fd2018-05-18 09:57:55 +020017104 struct station_info empty_sinfo = {};
Johannes Bergcf5ead82014-11-14 17:14:00 +010017105
Johannes Berg73887fd2018-05-18 09:57:55 +020017106 if (!sinfo)
17107 sinfo = &empty_sinfo;
Jouni Malinenec15e682011-03-23 15:29:52 +020017108
Johannes Berg947add32013-02-22 22:05:20 +010017109 trace_cfg80211_del_sta(dev, mac_addr);
17110
Thomas Graf58050fc2012-06-28 03:57:45 +000017111 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg7ea3e112018-05-18 11:40:44 +020017112 if (!msg) {
17113 cfg80211_sinfo_release_content(sinfo);
Johannes Berg73887fd2018-05-18 09:57:55 +020017114 return;
Johannes Berg7ea3e112018-05-18 11:40:44 +020017115 }
Jouni Malinenec15e682011-03-23 15:29:52 +020017116
Johannes Bergcf5ead82014-11-14 17:14:00 +010017117 if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
Johannes Berg57007122015-01-16 21:05:02 +010017118 rdev, dev, mac_addr, sinfo) < 0) {
Jouni Malinenec15e682011-03-23 15:29:52 +020017119 nlmsg_free(msg);
Johannes Berg73887fd2018-05-18 09:57:55 +020017120 return;
Jouni Malinenec15e682011-03-23 15:29:52 +020017121 }
17122
Johannes Berg68eb5502013-11-19 15:19:38 +010017123 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017124 NL80211_MCGRP_MLME, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020017125}
Johannes Bergcf5ead82014-11-14 17:14:00 +010017126EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
Jouni Malinenec15e682011-03-23 15:29:52 +020017127
Johannes Berg947add32013-02-22 22:05:20 +010017128void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
17129 enum nl80211_connect_failed_reason reason,
17130 gfp_t gfp)
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053017131{
Johannes Berg947add32013-02-22 22:05:20 +010017132 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017133 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053017134 struct sk_buff *msg;
17135 void *hdr;
17136
17137 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
17138 if (!msg)
17139 return;
17140
17141 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED);
17142 if (!hdr) {
17143 nlmsg_free(msg);
17144 return;
17145 }
17146
17147 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
17148 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
17149 nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason))
17150 goto nla_put_failure;
17151
17152 genlmsg_end(msg, hdr);
17153
Johannes Berg68eb5502013-11-19 15:19:38 +010017154 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017155 NL80211_MCGRP_MLME, gfp);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053017156 return;
17157
17158 nla_put_failure:
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053017159 nlmsg_free(msg);
17160}
Johannes Berg947add32013-02-22 22:05:20 +010017161EXPORT_SYMBOL(cfg80211_conn_failed);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053017162
Johannes Bergb92ab5d2011-11-04 11:18:19 +010017163static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
17164 const u8 *addr, gfp_t gfp)
Johannes Berg28946da2011-11-04 11:18:12 +010017165{
17166 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017167 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg28946da2011-11-04 11:18:12 +010017168 struct sk_buff *msg;
17169 void *hdr;
Mark Rutland6aa7de02017-10-23 14:07:29 -070017170 u32 nlportid = READ_ONCE(wdev->ap_unexpected_nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010017171
Eric W. Biederman15e47302012-09-07 20:12:54 +000017172 if (!nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010017173 return false;
17174
17175 msg = nlmsg_new(100, gfp);
17176 if (!msg)
17177 return true;
17178
Johannes Bergb92ab5d2011-11-04 11:18:19 +010017179 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Johannes Berg28946da2011-11-04 11:18:12 +010017180 if (!hdr) {
17181 nlmsg_free(msg);
17182 return true;
17183 }
17184
David S. Miller9360ffd2012-03-29 04:41:26 -040017185 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17186 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
17187 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
17188 goto nla_put_failure;
Johannes Berg28946da2011-11-04 11:18:12 +010017189
Johannes Berg9c90a9f2013-06-04 12:46:03 +020017190 genlmsg_end(msg, hdr);
Eric W. Biederman15e47302012-09-07 20:12:54 +000017191 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010017192 return true;
17193
17194 nla_put_failure:
Johannes Berg28946da2011-11-04 11:18:12 +010017195 nlmsg_free(msg);
17196 return true;
17197}
17198
Johannes Berg947add32013-02-22 22:05:20 +010017199bool cfg80211_rx_spurious_frame(struct net_device *dev,
17200 const u8 *addr, gfp_t gfp)
Johannes Bergb92ab5d2011-11-04 11:18:19 +010017201{
Johannes Berg947add32013-02-22 22:05:20 +010017202 struct wireless_dev *wdev = dev->ieee80211_ptr;
17203 bool ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010017204
Johannes Berg947add32013-02-22 22:05:20 +010017205 trace_cfg80211_rx_spurious_frame(dev, addr);
17206
17207 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
17208 wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
17209 trace_cfg80211_return_bool(false);
17210 return false;
17211 }
17212 ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
17213 addr, gfp);
17214 trace_cfg80211_return_bool(ret);
17215 return ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010017216}
Johannes Berg947add32013-02-22 22:05:20 +010017217EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
17218
17219bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
17220 const u8 *addr, gfp_t gfp)
17221{
17222 struct wireless_dev *wdev = dev->ieee80211_ptr;
17223 bool ret;
17224
17225 trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
17226
17227 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
17228 wdev->iftype != NL80211_IFTYPE_P2P_GO &&
17229 wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
17230 trace_cfg80211_return_bool(false);
17231 return false;
17232 }
17233 ret = __nl80211_unexpected_frame(dev,
17234 NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
17235 addr, gfp);
17236 trace_cfg80211_return_bool(ret);
17237 return ret;
17238}
17239EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
Johannes Bergb92ab5d2011-11-04 11:18:19 +010017240
Johannes Berg2e161f782010-08-12 15:38:38 +020017241int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000017242 struct wireless_dev *wdev, u32 nlportid,
Johannes Berg804483e2012-03-05 22:18:41 +010017243 int freq, int sig_dbm,
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030017244 const u8 *buf, size_t len, u32 flags, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020017245{
Johannes Berg71bbc992012-06-15 15:30:18 +020017246 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020017247 struct sk_buff *msg;
17248 void *hdr;
Jouni Malinen026331c2010-02-15 12:53:10 +020017249
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010017250 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020017251 if (!msg)
17252 return -ENOMEM;
17253
Johannes Berg2e161f782010-08-12 15:38:38 +020017254 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
Jouni Malinen026331c2010-02-15 12:53:10 +020017255 if (!hdr) {
17256 nlmsg_free(msg);
17257 return -ENOMEM;
17258 }
17259
David S. Miller9360ffd2012-03-29 04:41:26 -040017260 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020017261 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
17262 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020017263 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
17264 NL80211_ATTR_PAD) ||
Thomas Pedersene76fede2020-04-30 10:25:50 -070017265 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(freq)) ||
Thomas Pedersen942ba882020-04-30 10:25:51 -070017266 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, freq % 1000) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040017267 (sig_dbm &&
17268 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030017269 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
17270 (flags &&
17271 nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
David S. Miller9360ffd2012-03-29 04:41:26 -040017272 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020017273
Johannes Berg3b7b72e2011-10-22 19:05:51 +020017274 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020017275
Eric W. Biederman15e47302012-09-07 20:12:54 +000017276 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Jouni Malinen026331c2010-02-15 12:53:10 +020017277
17278 nla_put_failure:
Jouni Malinen026331c2010-02-15 12:53:10 +020017279 nlmsg_free(msg);
17280 return -ENOBUFS;
17281}
17282
Markus Theildca9ca22020-05-08 16:42:00 +020017283static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie,
17284 const u8 *buf, size_t len, bool ack,
17285 gfp_t gfp, enum nl80211_commands command)
Jouni Malinen026331c2010-02-15 12:53:10 +020017286{
Johannes Berg947add32013-02-22 22:05:20 +010017287 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017288 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg71bbc992012-06-15 15:30:18 +020017289 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020017290 struct sk_buff *msg;
17291 void *hdr;
17292
Markus Theildca9ca22020-05-08 16:42:00 +020017293 if (command == NL80211_CMD_FRAME_TX_STATUS)
17294 trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
17295 else
17296 trace_cfg80211_control_port_tx_status(wdev, cookie, ack);
Johannes Berg947add32013-02-22 22:05:20 +010017297
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010017298 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020017299 if (!msg)
17300 return;
17301
Markus Theildca9ca22020-05-08 16:42:00 +020017302 hdr = nl80211hdr_put(msg, 0, 0, 0, command);
Jouni Malinen026331c2010-02-15 12:53:10 +020017303 if (!hdr) {
17304 nlmsg_free(msg);
17305 return;
17306 }
17307
David S. Miller9360ffd2012-03-29 04:41:26 -040017308 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020017309 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
17310 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020017311 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
17312 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040017313 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020017314 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
17315 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040017316 (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
17317 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020017318
Johannes Berg3b7b72e2011-10-22 19:05:51 +020017319 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020017320
Johannes Berg68eb5502013-11-19 15:19:38 +010017321 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017322 NL80211_MCGRP_MLME, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020017323 return;
17324
Markus Theildca9ca22020-05-08 16:42:00 +020017325nla_put_failure:
Jouni Malinen026331c2010-02-15 12:53:10 +020017326 nlmsg_free(msg);
17327}
Markus Theildca9ca22020-05-08 16:42:00 +020017328
17329void cfg80211_control_port_tx_status(struct wireless_dev *wdev, u64 cookie,
17330 const u8 *buf, size_t len, bool ack,
17331 gfp_t gfp)
17332{
17333 nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp,
17334 NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS);
17335}
17336EXPORT_SYMBOL(cfg80211_control_port_tx_status);
17337
17338void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
17339 const u8 *buf, size_t len, bool ack, gfp_t gfp)
17340{
17341 nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp,
17342 NL80211_CMD_FRAME_TX_STATUS);
17343}
Johannes Berg947add32013-02-22 22:05:20 +010017344EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
Jouni Malinen026331c2010-02-15 12:53:10 +020017345
Denis Kenzior6a671a52018-03-26 12:52:41 -050017346static int __nl80211_rx_control_port(struct net_device *dev,
Denis Kenziora948f712018-07-03 15:05:48 -050017347 struct sk_buff *skb,
Denis Kenzior6a671a52018-03-26 12:52:41 -050017348 bool unencrypted, gfp_t gfp)
17349{
17350 struct wireless_dev *wdev = dev->ieee80211_ptr;
17351 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Denis Kenziora948f712018-07-03 15:05:48 -050017352 struct ethhdr *ehdr = eth_hdr(skb);
Johannes Berg8d74a622020-02-24 10:19:12 +010017353 const u8 *addr = ehdr->h_source;
Denis Kenziora948f712018-07-03 15:05:48 -050017354 u16 proto = be16_to_cpu(skb->protocol);
Denis Kenzior6a671a52018-03-26 12:52:41 -050017355 struct sk_buff *msg;
17356 void *hdr;
Denis Kenziora948f712018-07-03 15:05:48 -050017357 struct nlattr *frame;
17358
Denis Kenzior6a671a52018-03-26 12:52:41 -050017359 u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid);
17360
17361 if (!nlportid)
17362 return -ENOENT;
17363
Denis Kenziora948f712018-07-03 15:05:48 -050017364 msg = nlmsg_new(100 + skb->len, gfp);
Denis Kenzior6a671a52018-03-26 12:52:41 -050017365 if (!msg)
17366 return -ENOMEM;
17367
17368 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME);
17369 if (!hdr) {
17370 nlmsg_free(msg);
17371 return -ENOBUFS;
17372 }
17373
17374 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17375 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
17376 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
17377 NL80211_ATTR_PAD) ||
Johannes Berg8d74a622020-02-24 10:19:12 +010017378 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Denis Kenzior6a671a52018-03-26 12:52:41 -050017379 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
17380 (unencrypted && nla_put_flag(msg,
17381 NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
17382 goto nla_put_failure;
17383
Denis Kenziora948f712018-07-03 15:05:48 -050017384 frame = nla_reserve(msg, NL80211_ATTR_FRAME, skb->len);
17385 if (!frame)
17386 goto nla_put_failure;
17387
17388 skb_copy_bits(skb, 0, nla_data(frame), skb->len);
Denis Kenzior6a671a52018-03-26 12:52:41 -050017389 genlmsg_end(msg, hdr);
17390
17391 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
17392
17393 nla_put_failure:
17394 nlmsg_free(msg);
17395 return -ENOBUFS;
17396}
17397
17398bool cfg80211_rx_control_port(struct net_device *dev,
Denis Kenziora948f712018-07-03 15:05:48 -050017399 struct sk_buff *skb, bool unencrypted)
Denis Kenzior6a671a52018-03-26 12:52:41 -050017400{
17401 int ret;
17402
Denis Kenziora948f712018-07-03 15:05:48 -050017403 trace_cfg80211_rx_control_port(dev, skb, unencrypted);
17404 ret = __nl80211_rx_control_port(dev, skb, unencrypted, GFP_ATOMIC);
Denis Kenzior6a671a52018-03-26 12:52:41 -050017405 trace_cfg80211_return_bool(ret == 0);
17406 return ret == 0;
17407}
17408EXPORT_SYMBOL(cfg80211_rx_control_port);
17409
Johannes Berg5b97f492014-11-26 12:37:43 +010017410static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
17411 const char *mac, gfp_t gfp)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017412{
Johannes Berg947add32013-02-22 22:05:20 +010017413 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg5b97f492014-11-26 12:37:43 +010017414 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
17415 struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
17416 void **cb;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017417
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017418 if (!msg)
Johannes Berg5b97f492014-11-26 12:37:43 +010017419 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017420
Johannes Berg5b97f492014-11-26 12:37:43 +010017421 cb = (void **)msg->cb;
17422
17423 cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
17424 if (!cb[0]) {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017425 nlmsg_free(msg);
Johannes Berg5b97f492014-11-26 12:37:43 +010017426 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017427 }
17428
David S. Miller9360ffd2012-03-29 04:41:26 -040017429 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010017430 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
David S. Miller9360ffd2012-03-29 04:41:26 -040017431 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017432
Johannes Berg5b97f492014-11-26 12:37:43 +010017433 if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017434 goto nla_put_failure;
17435
Michal Kubecekae0be8d2019-04-26 11:13:06 +020017436 cb[1] = nla_nest_start_noflag(msg, NL80211_ATTR_CQM);
Johannes Berg5b97f492014-11-26 12:37:43 +010017437 if (!cb[1])
17438 goto nla_put_failure;
17439
17440 cb[2] = rdev;
17441
17442 return msg;
17443 nla_put_failure:
17444 nlmsg_free(msg);
17445 return NULL;
17446}
17447
17448static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
17449{
17450 void **cb = (void **)msg->cb;
17451 struct cfg80211_registered_device *rdev = cb[2];
17452
17453 nla_nest_end(msg, cb[1]);
17454 genlmsg_end(msg, cb[0]);
17455
17456 memset(msg->cb, 0, sizeof(msg->cb));
17457
17458 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
17459 NL80211_MCGRP_MLME, gfp);
17460}
17461
17462void cfg80211_cqm_rssi_notify(struct net_device *dev,
17463 enum nl80211_cqm_rssi_threshold_event rssi_event,
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010017464 s32 rssi_level, gfp_t gfp)
Johannes Berg5b97f492014-11-26 12:37:43 +010017465{
17466 struct sk_buff *msg;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010017467 struct wireless_dev *wdev = dev->ieee80211_ptr;
17468 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg5b97f492014-11-26 12:37:43 +010017469
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010017470 trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
Johannes Berg5b97f492014-11-26 12:37:43 +010017471
Johannes Berg98f03342014-11-26 12:42:02 +010017472 if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
17473 rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
17474 return;
17475
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010017476 if (wdev->cqm_config) {
17477 wdev->cqm_config->last_rssi_event_value = rssi_level;
17478
17479 cfg80211_cqm_rssi_update(rdev, dev);
17480
17481 if (rssi_level == 0)
17482 rssi_level = wdev->cqm_config->last_rssi_event_value;
17483 }
17484
Johannes Berg5b97f492014-11-26 12:37:43 +010017485 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
17486 if (!msg)
17487 return;
17488
David S. Miller9360ffd2012-03-29 04:41:26 -040017489 if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
17490 rssi_event))
17491 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017492
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010017493 if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
17494 rssi_level))
17495 goto nla_put_failure;
17496
Johannes Berg5b97f492014-11-26 12:37:43 +010017497 cfg80211_send_cqm(msg, gfp);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017498
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017499 return;
17500
17501 nla_put_failure:
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017502 nlmsg_free(msg);
17503}
Johannes Berg947add32013-02-22 22:05:20 +010017504EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020017505
Johannes Berg5b97f492014-11-26 12:37:43 +010017506void cfg80211_cqm_txe_notify(struct net_device *dev,
17507 const u8 *peer, u32 num_packets,
17508 u32 rate, u32 intvl, gfp_t gfp)
17509{
17510 struct sk_buff *msg;
17511
17512 msg = cfg80211_prepare_cqm(dev, peer, gfp);
17513 if (!msg)
17514 return;
17515
17516 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
17517 goto nla_put_failure;
17518
17519 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
17520 goto nla_put_failure;
17521
17522 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
17523 goto nla_put_failure;
17524
17525 cfg80211_send_cqm(msg, gfp);
17526 return;
17527
17528 nla_put_failure:
17529 nlmsg_free(msg);
17530}
17531EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
17532
17533void cfg80211_cqm_pktloss_notify(struct net_device *dev,
17534 const u8 *peer, u32 num_packets, gfp_t gfp)
17535{
17536 struct sk_buff *msg;
17537
17538 trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
17539
17540 msg = cfg80211_prepare_cqm(dev, peer, gfp);
17541 if (!msg)
17542 return;
17543
17544 if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
17545 goto nla_put_failure;
17546
17547 cfg80211_send_cqm(msg, gfp);
17548 return;
17549
17550 nla_put_failure:
17551 nlmsg_free(msg);
17552}
17553EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
17554
Johannes Berg98f03342014-11-26 12:42:02 +010017555void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
17556{
17557 struct sk_buff *msg;
17558
17559 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
17560 if (!msg)
17561 return;
17562
17563 if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
17564 goto nla_put_failure;
17565
17566 cfg80211_send_cqm(msg, gfp);
17567 return;
17568
17569 nla_put_failure:
17570 nlmsg_free(msg);
17571}
17572EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
17573
Johannes Berg947add32013-02-22 22:05:20 +010017574static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
17575 struct net_device *netdev, const u8 *bssid,
17576 const u8 *replay_ctr, gfp_t gfp)
Johannes Berge5497d72011-07-05 16:35:40 +020017577{
17578 struct sk_buff *msg;
17579 struct nlattr *rekey_attr;
17580 void *hdr;
17581
Thomas Graf58050fc2012-06-28 03:57:45 +000017582 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020017583 if (!msg)
17584 return;
17585
17586 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
17587 if (!hdr) {
17588 nlmsg_free(msg);
17589 return;
17590 }
17591
David S. Miller9360ffd2012-03-29 04:41:26 -040017592 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17593 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
17594 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
17595 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020017596
Michal Kubecekae0be8d2019-04-26 11:13:06 +020017597 rekey_attr = nla_nest_start_noflag(msg, NL80211_ATTR_REKEY_DATA);
Johannes Berge5497d72011-07-05 16:35:40 +020017598 if (!rekey_attr)
17599 goto nla_put_failure;
17600
David S. Miller9360ffd2012-03-29 04:41:26 -040017601 if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
17602 NL80211_REPLAY_CTR_LEN, replay_ctr))
17603 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020017604
17605 nla_nest_end(msg, rekey_attr);
17606
Johannes Berg3b7b72e2011-10-22 19:05:51 +020017607 genlmsg_end(msg, hdr);
Johannes Berge5497d72011-07-05 16:35:40 +020017608
Johannes Berg68eb5502013-11-19 15:19:38 +010017609 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017610 NL80211_MCGRP_MLME, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020017611 return;
17612
17613 nla_put_failure:
Johannes Berge5497d72011-07-05 16:35:40 +020017614 nlmsg_free(msg);
17615}
17616
Johannes Berg947add32013-02-22 22:05:20 +010017617void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
17618 const u8 *replay_ctr, gfp_t gfp)
17619{
17620 struct wireless_dev *wdev = dev->ieee80211_ptr;
17621 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017622 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010017623
17624 trace_cfg80211_gtk_rekey_notify(dev, bssid);
17625 nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
17626}
17627EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
17628
17629static void
17630nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
17631 struct net_device *netdev, int index,
17632 const u8 *bssid, bool preauth, gfp_t gfp)
Jouni Malinenc9df56b2011-09-16 18:56:23 +030017633{
17634 struct sk_buff *msg;
17635 struct nlattr *attr;
17636 void *hdr;
17637
Thomas Graf58050fc2012-06-28 03:57:45 +000017638 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030017639 if (!msg)
17640 return;
17641
17642 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
17643 if (!hdr) {
17644 nlmsg_free(msg);
17645 return;
17646 }
17647
David S. Miller9360ffd2012-03-29 04:41:26 -040017648 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17649 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
17650 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030017651
Michal Kubecekae0be8d2019-04-26 11:13:06 +020017652 attr = nla_nest_start_noflag(msg, NL80211_ATTR_PMKSA_CANDIDATE);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030017653 if (!attr)
17654 goto nla_put_failure;
17655
David S. Miller9360ffd2012-03-29 04:41:26 -040017656 if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
17657 nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
17658 (preauth &&
17659 nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
17660 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030017661
17662 nla_nest_end(msg, attr);
17663
Johannes Berg3b7b72e2011-10-22 19:05:51 +020017664 genlmsg_end(msg, hdr);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030017665
Johannes Berg68eb5502013-11-19 15:19:38 +010017666 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017667 NL80211_MCGRP_MLME, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030017668 return;
17669
17670 nla_put_failure:
Jouni Malinenc9df56b2011-09-16 18:56:23 +030017671 nlmsg_free(msg);
17672}
17673
Johannes Berg947add32013-02-22 22:05:20 +010017674void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
17675 const u8 *bssid, bool preauth, gfp_t gfp)
17676{
17677 struct wireless_dev *wdev = dev->ieee80211_ptr;
17678 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017679 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010017680
17681 trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
17682 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
17683}
17684EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
17685
17686static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
17687 struct net_device *netdev,
17688 struct cfg80211_chan_def *chandef,
Luciano Coelhof8d75522014-11-07 14:31:35 +020017689 gfp_t gfp,
17690 enum nl80211_commands notif,
Johannes Berg669b8412020-11-29 17:30:55 +020017691 u8 count, bool quiet)
Thomas Pedersen53145262012-04-06 13:35:47 -070017692{
17693 struct sk_buff *msg;
17694 void *hdr;
17695
Thomas Graf58050fc2012-06-28 03:57:45 +000017696 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070017697 if (!msg)
17698 return;
17699
Luciano Coelhof8d75522014-11-07 14:31:35 +020017700 hdr = nl80211hdr_put(msg, 0, 0, 0, notif);
Thomas Pedersen53145262012-04-06 13:35:47 -070017701 if (!hdr) {
17702 nlmsg_free(msg);
17703 return;
17704 }
17705
Johannes Berg683b6d32012-11-08 21:25:48 +010017706 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
17707 goto nla_put_failure;
17708
17709 if (nl80211_send_chandef(msg, chandef))
John W. Linville7eab0f62012-04-12 14:25:14 -040017710 goto nla_put_failure;
Thomas Pedersen53145262012-04-06 13:35:47 -070017711
Johannes Berg669b8412020-11-29 17:30:55 +020017712 if (notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) {
17713 if (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count))
Luciano Coelhof8d75522014-11-07 14:31:35 +020017714 goto nla_put_failure;
Johannes Berg669b8412020-11-29 17:30:55 +020017715 if (quiet &&
17716 nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX))
17717 goto nla_put_failure;
17718 }
Luciano Coelhof8d75522014-11-07 14:31:35 +020017719
Thomas Pedersen53145262012-04-06 13:35:47 -070017720 genlmsg_end(msg, hdr);
17721
Johannes Berg68eb5502013-11-19 15:19:38 +010017722 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017723 NL80211_MCGRP_MLME, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070017724 return;
17725
17726 nla_put_failure:
Thomas Pedersen53145262012-04-06 13:35:47 -070017727 nlmsg_free(msg);
17728}
17729
Johannes Berg947add32013-02-22 22:05:20 +010017730void cfg80211_ch_switch_notify(struct net_device *dev,
17731 struct cfg80211_chan_def *chandef)
Thomas Pedersen84f10702012-07-12 16:17:33 -070017732{
Johannes Berg947add32013-02-22 22:05:20 +010017733 struct wireless_dev *wdev = dev->ieee80211_ptr;
17734 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017735 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010017736
Simon Wunderliche487eae2013-11-21 18:19:51 +010017737 ASSERT_WDEV_LOCK(wdev);
Johannes Berg947add32013-02-22 22:05:20 +010017738
Simon Wunderliche487eae2013-11-21 18:19:51 +010017739 trace_cfg80211_ch_switch_notify(dev, chandef);
Johannes Berg947add32013-02-22 22:05:20 +010017740
Michal Kazior9e0e2962014-01-29 14:22:27 +010017741 wdev->chandef = *chandef;
Janusz Dziedzic96f55f12014-01-24 14:29:21 +010017742 wdev->preset_chandef = *chandef;
Sergey Matyukevich5dc8cdc2019-03-26 09:27:37 +000017743
17744 if (wdev->iftype == NL80211_IFTYPE_STATION &&
17745 !WARN_ON(!wdev->current_bss))
Sergey Matyukevich0afd4252019-07-26 16:39:34 +000017746 cfg80211_update_assoc_bss_entry(wdev, chandef->chan);
Sergey Matyukevich5dc8cdc2019-03-26 09:27:37 +000017747
Michael Vassernisd34990b2019-07-29 06:01:16 +000017748 cfg80211_sched_dfs_chan_update(rdev);
17749
Luciano Coelhof8d75522014-11-07 14:31:35 +020017750 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
Johannes Berg669b8412020-11-29 17:30:55 +020017751 NL80211_CMD_CH_SWITCH_NOTIFY, 0, false);
Johannes Berg947add32013-02-22 22:05:20 +010017752}
17753EXPORT_SYMBOL(cfg80211_ch_switch_notify);
17754
Luciano Coelhof8d75522014-11-07 14:31:35 +020017755void cfg80211_ch_switch_started_notify(struct net_device *dev,
17756 struct cfg80211_chan_def *chandef,
Johannes Berg669b8412020-11-29 17:30:55 +020017757 u8 count, bool quiet)
Luciano Coelhof8d75522014-11-07 14:31:35 +020017758{
17759 struct wireless_dev *wdev = dev->ieee80211_ptr;
17760 struct wiphy *wiphy = wdev->wiphy;
17761 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
17762
17763 trace_cfg80211_ch_switch_started_notify(dev, chandef);
17764
17765 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
Johannes Berg669b8412020-11-29 17:30:55 +020017766 NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
17767 count, quiet);
Luciano Coelhof8d75522014-11-07 14:31:35 +020017768}
17769EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
17770
John Crispin0d2ab3ae2021-07-02 19:44:07 +020017771int cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp,
17772 enum nl80211_commands cmd, u8 count,
17773 u64 color_bitmap)
17774{
17775 struct wireless_dev *wdev = dev->ieee80211_ptr;
17776 struct wiphy *wiphy = wdev->wiphy;
17777 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
17778 struct sk_buff *msg;
17779 void *hdr;
17780
17781 ASSERT_WDEV_LOCK(wdev);
17782
17783 trace_cfg80211_bss_color_notify(dev, cmd, count, color_bitmap);
17784
17785 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
17786 if (!msg)
17787 return -ENOMEM;
17788
17789 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
17790 if (!hdr)
17791 goto nla_put_failure;
17792
17793 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
17794 goto nla_put_failure;
17795
17796 if (cmd == NL80211_CMD_COLOR_CHANGE_STARTED &&
17797 nla_put_u32(msg, NL80211_ATTR_COLOR_CHANGE_COUNT, count))
17798 goto nla_put_failure;
17799
17800 if (cmd == NL80211_CMD_OBSS_COLOR_COLLISION &&
17801 nla_put_u64_64bit(msg, NL80211_ATTR_OBSS_COLOR_BITMAP,
17802 color_bitmap, NL80211_ATTR_PAD))
17803 goto nla_put_failure;
17804
17805 genlmsg_end(msg, hdr);
17806
17807 return genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
17808 msg, 0, NL80211_MCGRP_MLME, gfp);
17809
17810nla_put_failure:
17811 nlmsg_free(msg);
17812 return -EINVAL;
17813}
17814EXPORT_SYMBOL(cfg80211_bss_color_notify);
17815
Thomas Pedersen84f10702012-07-12 16:17:33 -070017816void
Simon Wunderlich04f39042013-02-08 18:16:19 +010017817nl80211_radar_notify(struct cfg80211_registered_device *rdev,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +010017818 const struct cfg80211_chan_def *chandef,
Simon Wunderlich04f39042013-02-08 18:16:19 +010017819 enum nl80211_radar_event event,
17820 struct net_device *netdev, gfp_t gfp)
17821{
17822 struct sk_buff *msg;
17823 void *hdr;
17824
17825 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
17826 if (!msg)
17827 return;
17828
17829 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
17830 if (!hdr) {
17831 nlmsg_free(msg);
17832 return;
17833 }
17834
17835 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
17836 goto nla_put_failure;
17837
17838 /* NOP and radar events don't need a netdev parameter */
17839 if (netdev) {
17840 struct wireless_dev *wdev = netdev->ieee80211_ptr;
17841
17842 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020017843 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
17844 NL80211_ATTR_PAD))
Simon Wunderlich04f39042013-02-08 18:16:19 +010017845 goto nla_put_failure;
17846 }
17847
17848 if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
17849 goto nla_put_failure;
17850
17851 if (nl80211_send_chandef(msg, chandef))
17852 goto nla_put_failure;
17853
Johannes Berg9c90a9f2013-06-04 12:46:03 +020017854 genlmsg_end(msg, hdr);
Simon Wunderlich04f39042013-02-08 18:16:19 +010017855
Johannes Berg68eb5502013-11-19 15:19:38 +010017856 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017857 NL80211_MCGRP_MLME, gfp);
Simon Wunderlich04f39042013-02-08 18:16:19 +010017858 return;
17859
17860 nla_put_failure:
Simon Wunderlich04f39042013-02-08 18:16:19 +010017861 nlmsg_free(msg);
17862}
17863
tamizhr@codeaurora.org466b9932018-01-31 16:24:49 +053017864void cfg80211_sta_opmode_change_notify(struct net_device *dev, const u8 *mac,
17865 struct sta_opmode_info *sta_opmode,
17866 gfp_t gfp)
17867{
17868 struct sk_buff *msg;
17869 struct wireless_dev *wdev = dev->ieee80211_ptr;
17870 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
17871 void *hdr;
17872
17873 if (WARN_ON(!mac))
17874 return;
17875
17876 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
17877 if (!msg)
17878 return;
17879
17880 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STA_OPMODE_CHANGED);
17881 if (!hdr) {
17882 nlmsg_free(msg);
17883 return;
17884 }
17885
17886 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
17887 goto nla_put_failure;
17888
17889 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
17890 goto nla_put_failure;
17891
17892 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
17893 goto nla_put_failure;
17894
17895 if ((sta_opmode->changed & STA_OPMODE_SMPS_MODE_CHANGED) &&
17896 nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, sta_opmode->smps_mode))
17897 goto nla_put_failure;
17898
17899 if ((sta_opmode->changed & STA_OPMODE_MAX_BW_CHANGED) &&
Johannes Berg0016d322020-03-25 09:05:32 +010017900 nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, sta_opmode->bw))
tamizhr@codeaurora.org466b9932018-01-31 16:24:49 +053017901 goto nla_put_failure;
17902
17903 if ((sta_opmode->changed & STA_OPMODE_N_SS_CHANGED) &&
17904 nla_put_u8(msg, NL80211_ATTR_NSS, sta_opmode->rx_nss))
17905 goto nla_put_failure;
17906
17907 genlmsg_end(msg, hdr);
17908
17909 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
17910 NL80211_MCGRP_MLME, gfp);
17911
17912 return;
17913
17914nla_put_failure:
17915 nlmsg_free(msg);
17916}
17917EXPORT_SYMBOL(cfg80211_sta_opmode_change_notify);
17918
Johannes Berg7f6cf312011-11-04 11:18:15 +010017919void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
Venkateswara Naralasettyc4b50cd2018-02-13 11:03:06 +053017920 u64 cookie, bool acked, s32 ack_signal,
17921 bool is_valid_ack_signal, gfp_t gfp)
Johannes Berg7f6cf312011-11-04 11:18:15 +010017922{
17923 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017924 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg7f6cf312011-11-04 11:18:15 +010017925 struct sk_buff *msg;
17926 void *hdr;
Johannes Berg7f6cf312011-11-04 11:18:15 +010017927
Beni Lev4ee3e062012-08-27 12:49:39 +030017928 trace_cfg80211_probe_status(dev, addr, cookie, acked);
17929
Thomas Graf58050fc2012-06-28 03:57:45 +000017930 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Beni Lev4ee3e062012-08-27 12:49:39 +030017931
Johannes Berg7f6cf312011-11-04 11:18:15 +010017932 if (!msg)
17933 return;
17934
17935 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
17936 if (!hdr) {
17937 nlmsg_free(msg);
17938 return;
17939 }
17940
David S. Miller9360ffd2012-03-29 04:41:26 -040017941 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17942 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
17943 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020017944 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
17945 NL80211_ATTR_PAD) ||
Venkateswara Naralasettyc4b50cd2018-02-13 11:03:06 +053017946 (acked && nla_put_flag(msg, NL80211_ATTR_ACK)) ||
17947 (is_valid_ack_signal && nla_put_s32(msg, NL80211_ATTR_ACK_SIGNAL,
17948 ack_signal)))
David S. Miller9360ffd2012-03-29 04:41:26 -040017949 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010017950
Johannes Berg9c90a9f2013-06-04 12:46:03 +020017951 genlmsg_end(msg, hdr);
Johannes Berg7f6cf312011-11-04 11:18:15 +010017952
Johannes Berg68eb5502013-11-19 15:19:38 +010017953 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010017954 NL80211_MCGRP_MLME, gfp);
Johannes Berg7f6cf312011-11-04 11:18:15 +010017955 return;
17956
17957 nla_put_failure:
Johannes Berg7f6cf312011-11-04 11:18:15 +010017958 nlmsg_free(msg);
17959}
17960EXPORT_SYMBOL(cfg80211_probe_status);
17961
Thomas Pedersene76fede2020-04-30 10:25:50 -070017962void cfg80211_report_obss_beacon_khz(struct wiphy *wiphy, const u8 *frame,
17963 size_t len, int freq, int sig_dbm)
Johannes Berg5e760232011-11-04 11:18:17 +010017964{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080017965 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg5e760232011-11-04 11:18:17 +010017966 struct sk_buff *msg;
17967 void *hdr;
Ben Greear37c73b52012-10-26 14:49:25 -070017968 struct cfg80211_beacon_registration *reg;
Johannes Berg5e760232011-11-04 11:18:17 +010017969
Beni Lev4ee3e062012-08-27 12:49:39 +030017970 trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
17971
Ben Greear37c73b52012-10-26 14:49:25 -070017972 spin_lock_bh(&rdev->beacon_registrations_lock);
17973 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
17974 msg = nlmsg_new(len + 100, GFP_ATOMIC);
17975 if (!msg) {
17976 spin_unlock_bh(&rdev->beacon_registrations_lock);
17977 return;
17978 }
Johannes Berg5e760232011-11-04 11:18:17 +010017979
Ben Greear37c73b52012-10-26 14:49:25 -070017980 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
17981 if (!hdr)
17982 goto nla_put_failure;
Johannes Berg5e760232011-11-04 11:18:17 +010017983
Ben Greear37c73b52012-10-26 14:49:25 -070017984 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
17985 (freq &&
Thomas Pedersen942ba882020-04-30 10:25:51 -070017986 (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
17987 KHZ_TO_MHZ(freq)) ||
17988 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET,
17989 freq % 1000))) ||
Ben Greear37c73b52012-10-26 14:49:25 -070017990 (sig_dbm &&
17991 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
17992 nla_put(msg, NL80211_ATTR_FRAME, len, frame))
17993 goto nla_put_failure;
17994
17995 genlmsg_end(msg, hdr);
17996
17997 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
Johannes Berg5e760232011-11-04 11:18:17 +010017998 }
Ben Greear37c73b52012-10-26 14:49:25 -070017999 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010018000 return;
18001
18002 nla_put_failure:
Ben Greear37c73b52012-10-26 14:49:25 -070018003 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010018004 nlmsg_free(msg);
18005}
Thomas Pedersene76fede2020-04-30 10:25:50 -070018006EXPORT_SYMBOL(cfg80211_report_obss_beacon_khz);
Johannes Berg5e760232011-11-04 11:18:17 +010018007
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010018008#ifdef CONFIG_PM
Luciano Coelho8cd4d452014-09-17 11:55:28 +030018009static int cfg80211_net_detect_results(struct sk_buff *msg,
18010 struct cfg80211_wowlan_wakeup *wakeup)
18011{
18012 struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect;
18013 struct nlattr *nl_results, *nl_match, *nl_freqs;
18014 int i, j;
18015
Michal Kubecekae0be8d2019-04-26 11:13:06 +020018016 nl_results = nla_nest_start_noflag(msg,
18017 NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030018018 if (!nl_results)
18019 return -EMSGSIZE;
18020
18021 for (i = 0; i < nd->n_matches; i++) {
18022 struct cfg80211_wowlan_nd_match *match = nd->matches[i];
18023
Michal Kubecekae0be8d2019-04-26 11:13:06 +020018024 nl_match = nla_nest_start_noflag(msg, i);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030018025 if (!nl_match)
18026 break;
18027
18028 /* The SSID attribute is optional in nl80211, but for
18029 * simplicity reasons it's always present in the
18030 * cfg80211 structure. If a driver can't pass the
18031 * SSID, that needs to be changed. A zero length SSID
18032 * is still a valid SSID (wildcard), so it cannot be
18033 * used for this purpose.
18034 */
18035 if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len,
18036 match->ssid.ssid)) {
18037 nla_nest_cancel(msg, nl_match);
18038 goto out;
18039 }
18040
18041 if (match->n_channels) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +020018042 nl_freqs = nla_nest_start_noflag(msg,
18043 NL80211_ATTR_SCAN_FREQUENCIES);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030018044 if (!nl_freqs) {
18045 nla_nest_cancel(msg, nl_match);
18046 goto out;
18047 }
18048
18049 for (j = 0; j < match->n_channels; j++) {
Samuel Tan5528fae82015-02-09 21:29:15 +020018050 if (nla_put_u32(msg, j, match->channels[j])) {
Luciano Coelho8cd4d452014-09-17 11:55:28 +030018051 nla_nest_cancel(msg, nl_freqs);
18052 nla_nest_cancel(msg, nl_match);
18053 goto out;
18054 }
18055 }
18056
18057 nla_nest_end(msg, nl_freqs);
18058 }
18059
18060 nla_nest_end(msg, nl_match);
18061 }
18062
18063out:
18064 nla_nest_end(msg, nl_results);
18065 return 0;
18066}
18067
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010018068void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
18069 struct cfg80211_wowlan_wakeup *wakeup,
18070 gfp_t gfp)
18071{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080018072 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010018073 struct sk_buff *msg;
18074 void *hdr;
Johannes Berg9c90a9f2013-06-04 12:46:03 +020018075 int size = 200;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010018076
18077 trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
18078
18079 if (wakeup)
18080 size += wakeup->packet_present_len;
18081
18082 msg = nlmsg_new(size, gfp);
18083 if (!msg)
18084 return;
18085
18086 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN);
18087 if (!hdr)
18088 goto free_msg;
18089
18090 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020018091 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
18092 NL80211_ATTR_PAD))
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010018093 goto free_msg;
18094
18095 if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
18096 wdev->netdev->ifindex))
18097 goto free_msg;
18098
18099 if (wakeup) {
18100 struct nlattr *reasons;
18101
Michal Kubecekae0be8d2019-04-26 11:13:06 +020018102 reasons = nla_nest_start_noflag(msg,
18103 NL80211_ATTR_WOWLAN_TRIGGERS);
Johannes Berg7fa322c2013-10-25 11:16:58 +020018104 if (!reasons)
18105 goto free_msg;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010018106
18107 if (wakeup->disconnect &&
18108 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
18109 goto free_msg;
18110 if (wakeup->magic_pkt &&
18111 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT))
18112 goto free_msg;
18113 if (wakeup->gtk_rekey_failure &&
18114 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE))
18115 goto free_msg;
18116 if (wakeup->eap_identity_req &&
18117 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST))
18118 goto free_msg;
18119 if (wakeup->four_way_handshake &&
18120 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE))
18121 goto free_msg;
18122 if (wakeup->rfkill_release &&
18123 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))
18124 goto free_msg;
18125
18126 if (wakeup->pattern_idx >= 0 &&
18127 nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
18128 wakeup->pattern_idx))
18129 goto free_msg;
18130
Johannes Bergae917c92013-10-25 11:05:22 +020018131 if (wakeup->tcp_match &&
18132 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
18133 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010018134
Johannes Bergae917c92013-10-25 11:05:22 +020018135 if (wakeup->tcp_connlost &&
18136 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
18137 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010018138
Johannes Bergae917c92013-10-25 11:05:22 +020018139 if (wakeup->tcp_nomoretokens &&
18140 nla_put_flag(msg,
18141 NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
18142 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010018143
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010018144 if (wakeup->packet) {
18145 u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
18146 u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN;
18147
18148 if (!wakeup->packet_80211) {
18149 pkt_attr =
18150 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023;
18151 len_attr =
18152 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN;
18153 }
18154
18155 if (wakeup->packet_len &&
18156 nla_put_u32(msg, len_attr, wakeup->packet_len))
18157 goto free_msg;
18158
18159 if (nla_put(msg, pkt_attr, wakeup->packet_present_len,
18160 wakeup->packet))
18161 goto free_msg;
18162 }
18163
Luciano Coelho8cd4d452014-09-17 11:55:28 +030018164 if (wakeup->net_detect &&
18165 cfg80211_net_detect_results(msg, wakeup))
18166 goto free_msg;
18167
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010018168 nla_nest_end(msg, reasons);
18169 }
18170
Johannes Berg9c90a9f2013-06-04 12:46:03 +020018171 genlmsg_end(msg, hdr);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010018172
Johannes Berg68eb5502013-11-19 15:19:38 +010018173 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010018174 NL80211_MCGRP_MLME, gfp);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010018175 return;
18176
18177 free_msg:
18178 nlmsg_free(msg);
18179}
18180EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup);
18181#endif
18182
Jouni Malinen3475b092012-11-16 22:49:57 +020018183void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
18184 enum nl80211_tdls_operation oper,
18185 u16 reason_code, gfp_t gfp)
18186{
18187 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080018188 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Jouni Malinen3475b092012-11-16 22:49:57 +020018189 struct sk_buff *msg;
18190 void *hdr;
Jouni Malinen3475b092012-11-16 22:49:57 +020018191
18192 trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
18193 reason_code);
18194
18195 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
18196 if (!msg)
18197 return;
18198
18199 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
18200 if (!hdr) {
18201 nlmsg_free(msg);
18202 return;
18203 }
18204
18205 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
18206 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
18207 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
18208 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
18209 (reason_code > 0 &&
18210 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
18211 goto nla_put_failure;
18212
Johannes Berg9c90a9f2013-06-04 12:46:03 +020018213 genlmsg_end(msg, hdr);
Jouni Malinen3475b092012-11-16 22:49:57 +020018214
Johannes Berg68eb5502013-11-19 15:19:38 +010018215 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010018216 NL80211_MCGRP_MLME, gfp);
Jouni Malinen3475b092012-11-16 22:49:57 +020018217 return;
18218
18219 nla_put_failure:
Jouni Malinen3475b092012-11-16 22:49:57 +020018220 nlmsg_free(msg);
18221}
18222EXPORT_SYMBOL(cfg80211_tdls_oper_request);
18223
Jouni Malinen026331c2010-02-15 12:53:10 +020018224static int nl80211_netlink_notify(struct notifier_block * nb,
18225 unsigned long state,
18226 void *_notify)
18227{
18228 struct netlink_notify *notify = _notify;
18229 struct cfg80211_registered_device *rdev;
18230 struct wireless_dev *wdev;
Ben Greear37c73b52012-10-26 14:49:25 -070018231 struct cfg80211_beacon_registration *reg, *tmp;
Jouni Malinen026331c2010-02-15 12:53:10 +020018232
Dmitry Ivanov8f815cd2016-04-06 17:23:18 +030018233 if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
Jouni Malinen026331c2010-02-15 12:53:10 +020018234 return NOTIFY_DONE;
18235
18236 rcu_read_lock();
18237
Johannes Berg5e760232011-11-04 11:18:17 +010018238 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
Arend Van Sprielca986ad2017-04-21 13:05:00 +010018239 struct cfg80211_sched_scan_request *sched_scan_req;
Jukka Rissanen93a1e862014-12-15 13:25:39 +020018240
Arend Van Sprielca986ad2017-04-21 13:05:00 +010018241 list_for_each_entry_rcu(sched_scan_req,
18242 &rdev->sched_scan_req_list,
18243 list) {
18244 if (sched_scan_req->owner_nlportid == notify->portid) {
18245 sched_scan_req->nl_owner_dead = true;
Johannes Berg753aacf2017-01-05 10:57:14 +010018246 schedule_work(&rdev->sched_scan_stop_wk);
Arend Van Sprielca986ad2017-04-21 13:05:00 +010018247 }
Johannes Berg753aacf2017-01-05 10:57:14 +010018248 }
Johannes Berg78f22b62014-03-24 17:57:27 +010018249
Johannes Berg53873f12016-05-03 16:52:04 +030018250 list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
Eric W. Biederman15e47302012-09-07 20:12:54 +000018251 cfg80211_mlme_unregister_socket(wdev, notify->portid);
Ben Greear37c73b52012-10-26 14:49:25 -070018252
Johannes Bergab810072017-04-26 07:43:41 +020018253 if (wdev->owner_nlportid == notify->portid) {
18254 wdev->nl_owner_dead = true;
18255 schedule_work(&rdev->destroy_work);
18256 } else if (wdev->conn_owner_nlportid == notify->portid) {
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050018257 schedule_work(&wdev->disconnect_wk);
Johannes Bergab810072017-04-26 07:43:41 +020018258 }
Johannes Berg9bb7e0f2018-09-10 13:29:12 +020018259
18260 cfg80211_release_pmsr(wdev, notify->portid);
Johannes Berg78f22b62014-03-24 17:57:27 +010018261 }
18262
Ben Greear37c73b52012-10-26 14:49:25 -070018263 spin_lock_bh(&rdev->beacon_registrations_lock);
18264 list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
18265 list) {
18266 if (reg->nlportid == notify->portid) {
18267 list_del(&reg->list);
18268 kfree(reg);
18269 break;
18270 }
18271 }
18272 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010018273 }
Jouni Malinen026331c2010-02-15 12:53:10 +020018274
18275 rcu_read_unlock();
18276
Ilan peer05050752015-03-04 00:32:06 -050018277 /*
18278 * It is possible that the user space process that is controlling the
18279 * indoor setting disappeared, so notify the regulatory core.
18280 */
18281 regulatory_netlink_notify(notify->portid);
Zhao, Gang6784c7d2014-04-21 12:53:04 +080018282 return NOTIFY_OK;
Jouni Malinen026331c2010-02-15 12:53:10 +020018283}
18284
18285static struct notifier_block nl80211_netlink_notifier = {
18286 .notifier_call = nl80211_netlink_notify,
18287};
18288
Jouni Malinen355199e2013-02-27 17:14:27 +020018289void cfg80211_ft_event(struct net_device *netdev,
18290 struct cfg80211_ft_event_params *ft_event)
18291{
18292 struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080018293 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinen355199e2013-02-27 17:14:27 +020018294 struct sk_buff *msg;
18295 void *hdr;
Jouni Malinen355199e2013-02-27 17:14:27 +020018296
18297 trace_cfg80211_ft_event(wiphy, netdev, ft_event);
18298
18299 if (!ft_event->target_ap)
18300 return;
18301
Dedy Lansky1039d082018-05-17 16:25:03 +030018302 msg = nlmsg_new(100 + ft_event->ies_len + ft_event->ric_ies_len,
18303 GFP_KERNEL);
Jouni Malinen355199e2013-02-27 17:14:27 +020018304 if (!msg)
18305 return;
18306
18307 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
Johannes Bergae917c92013-10-25 11:05:22 +020018308 if (!hdr)
18309 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020018310
Johannes Bergae917c92013-10-25 11:05:22 +020018311 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
18312 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
18313 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
18314 goto out;
18315
18316 if (ft_event->ies &&
18317 nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
18318 goto out;
18319 if (ft_event->ric_ies &&
18320 nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
18321 ft_event->ric_ies))
18322 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020018323
Johannes Berg9c90a9f2013-06-04 12:46:03 +020018324 genlmsg_end(msg, hdr);
Jouni Malinen355199e2013-02-27 17:14:27 +020018325
Johannes Berg68eb5502013-11-19 15:19:38 +010018326 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010018327 NL80211_MCGRP_MLME, GFP_KERNEL);
Johannes Bergae917c92013-10-25 11:05:22 +020018328 return;
18329 out:
18330 nlmsg_free(msg);
Jouni Malinen355199e2013-02-27 17:14:27 +020018331}
18332EXPORT_SYMBOL(cfg80211_ft_event);
18333
Arend van Spriel5de17982013-04-18 15:49:00 +020018334void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
18335{
18336 struct cfg80211_registered_device *rdev;
18337 struct sk_buff *msg;
18338 void *hdr;
18339 u32 nlportid;
18340
Zhao, Gangf26cbf42014-04-21 12:53:03 +080018341 rdev = wiphy_to_rdev(wdev->wiphy);
Arend van Spriel5de17982013-04-18 15:49:00 +020018342 if (!rdev->crit_proto_nlportid)
18343 return;
18344
18345 nlportid = rdev->crit_proto_nlportid;
18346 rdev->crit_proto_nlportid = 0;
18347
18348 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
18349 if (!msg)
18350 return;
18351
18352 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
18353 if (!hdr)
18354 goto nla_put_failure;
18355
18356 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020018357 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
18358 NL80211_ATTR_PAD))
Arend van Spriel5de17982013-04-18 15:49:00 +020018359 goto nla_put_failure;
18360
18361 genlmsg_end(msg, hdr);
18362
18363 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
18364 return;
18365
18366 nla_put_failure:
Arend van Spriel5de17982013-04-18 15:49:00 +020018367 nlmsg_free(msg);
Arend van Spriel5de17982013-04-18 15:49:00 +020018368}
18369EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
18370
Johannes Berg348baf02014-01-24 14:06:29 +010018371void nl80211_send_ap_stopped(struct wireless_dev *wdev)
18372{
18373 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080018374 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg348baf02014-01-24 14:06:29 +010018375 struct sk_buff *msg;
18376 void *hdr;
18377
18378 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
18379 if (!msg)
18380 return;
18381
18382 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
18383 if (!hdr)
18384 goto out;
18385
18386 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
18387 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020018388 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
18389 NL80211_ATTR_PAD))
Johannes Berg348baf02014-01-24 14:06:29 +010018390 goto out;
18391
18392 genlmsg_end(msg, hdr);
18393
18394 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
18395 NL80211_MCGRP_MLME, GFP_KERNEL);
18396 return;
18397 out:
18398 nlmsg_free(msg);
18399}
18400
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020018401int cfg80211_external_auth_request(struct net_device *dev,
18402 struct cfg80211_external_auth_params *params,
18403 gfp_t gfp)
18404{
18405 struct wireless_dev *wdev = dev->ieee80211_ptr;
18406 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
18407 struct sk_buff *msg;
18408 void *hdr;
18409
18410 if (!wdev->conn_owner_nlportid)
18411 return -EINVAL;
18412
18413 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
18414 if (!msg)
18415 return -ENOMEM;
18416
18417 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_EXTERNAL_AUTH);
18418 if (!hdr)
18419 goto nla_put_failure;
18420
18421 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
18422 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
18423 nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) ||
18424 nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION,
18425 params->action) ||
18426 nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) ||
18427 nla_put(msg, NL80211_ATTR_SSID, params->ssid.ssid_len,
18428 params->ssid.ssid))
18429 goto nla_put_failure;
18430
18431 genlmsg_end(msg, hdr);
18432 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
18433 wdev->conn_owner_nlportid);
18434 return 0;
18435
18436 nla_put_failure:
18437 nlmsg_free(msg);
18438 return -ENOBUFS;
18439}
18440EXPORT_SYMBOL(cfg80211_external_auth_request);
18441
Sunil Duttcb74e972019-02-20 16:18:07 +053018442void cfg80211_update_owe_info_event(struct net_device *netdev,
18443 struct cfg80211_update_owe_info *owe_info,
18444 gfp_t gfp)
18445{
18446 struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
18447 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
18448 struct sk_buff *msg;
18449 void *hdr;
18450
18451 trace_cfg80211_update_owe_info_event(wiphy, netdev, owe_info);
18452
18453 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
18454 if (!msg)
18455 return;
18456
18457 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UPDATE_OWE_INFO);
18458 if (!hdr)
18459 goto nla_put_failure;
18460
18461 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
18462 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
18463 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, owe_info->peer))
18464 goto nla_put_failure;
18465
18466 if (!owe_info->ie_len ||
18467 nla_put(msg, NL80211_ATTR_IE, owe_info->ie_len, owe_info->ie))
18468 goto nla_put_failure;
18469
18470 genlmsg_end(msg, hdr);
18471
18472 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
18473 NL80211_MCGRP_MLME, gfp);
18474 return;
18475
18476nla_put_failure:
18477 genlmsg_cancel(msg, hdr);
18478 nlmsg_free(msg);
18479}
18480EXPORT_SYMBOL(cfg80211_update_owe_info_event);
18481
Johannes Berg55682962007-09-20 13:09:35 -040018482/* initialisation/exit functions */
18483
Johannes Berg56989f62016-10-24 14:40:05 +020018484int __init nl80211_init(void)
Johannes Berg55682962007-09-20 13:09:35 -040018485{
Michał Mirosław0d63cbb2009-05-21 10:34:06 +000018486 int err;
Johannes Berg55682962007-09-20 13:09:35 -040018487
Johannes Berg489111e2016-10-24 14:40:03 +020018488 err = genl_register_family(&nl80211_fam);
Johannes Berg55682962007-09-20 13:09:35 -040018489 if (err)
18490 return err;
18491
Jouni Malinen026331c2010-02-15 12:53:10 +020018492 err = netlink_register_notifier(&nl80211_netlink_notifier);
18493 if (err)
18494 goto err_out;
18495
Johannes Berg55682962007-09-20 13:09:35 -040018496 return 0;
18497 err_out:
18498 genl_unregister_family(&nl80211_fam);
18499 return err;
18500}
18501
18502void nl80211_exit(void)
18503{
Jouni Malinen026331c2010-02-15 12:53:10 +020018504 netlink_unregister_notifier(&nl80211_netlink_notifier);
Johannes Berg55682962007-09-20 13:09:35 -040018505 genl_unregister_family(&nl80211_fam);
18506}