Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * This is the new netlink-based wireless configuration interface.
4 : : *
5 : : * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
6 : : * Copyright 2013-2014 Intel Mobile Communications GmbH
7 : : * Copyright 2015-2017 Intel Deutschland GmbH
8 : : * Copyright (C) 2018-2019 Intel Corporation
9 : : */
10 : :
11 : : #include <linux/if.h>
12 : : #include <linux/module.h>
13 : : #include <linux/err.h>
14 : : #include <linux/slab.h>
15 : : #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>
21 : : #include <linux/nospec.h>
22 : : #include <linux/etherdevice.h>
23 : : #include <linux/if_vlan.h>
24 : : #include <net/net_namespace.h>
25 : : #include <net/genetlink.h>
26 : : #include <net/cfg80211.h>
27 : : #include <net/sock.h>
28 : : #include <net/inet_connection_sock.h>
29 : : #include "core.h"
30 : : #include "nl80211.h"
31 : : #include "reg.h"
32 : : #include "rdev-ops.h"
33 : :
34 : : static 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 : :
39 : : /* the netlink family */
40 : : static struct genl_family nl80211_fam;
41 : :
42 : : /* multicast groups */
43 : : enum nl80211_multicast_groups {
44 : : NL80211_MCGRP_CONFIG,
45 : : NL80211_MCGRP_SCAN,
46 : : NL80211_MCGRP_REGULATORY,
47 : : NL80211_MCGRP_MLME,
48 : : NL80211_MCGRP_VENDOR,
49 : : NL80211_MCGRP_NAN,
50 : : NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
51 : : };
52 : :
53 : : static const struct genl_multicast_group nl80211_mcgrps[] = {
54 : : [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 },
59 : : [NL80211_MCGRP_NAN] = { .name = NL80211_MULTICAST_GROUP_NAN },
60 : : #ifdef CONFIG_NL80211_TESTMODE
61 : : [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }
62 : : #endif
63 : : };
64 : :
65 : : /* returns ERR_PTR values */
66 : : static struct wireless_dev *
67 : 0 : __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
68 : : {
69 : 0 : struct cfg80211_registered_device *rdev;
70 : 0 : struct wireless_dev *result = NULL;
71 : 0 : bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
72 : 0 : bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
73 : 0 : u64 wdev_id;
74 : 0 : int wiphy_idx = -1;
75 : 0 : int ifidx = -1;
76 : :
77 [ # # # # ]: 0 : ASSERT_RTNL();
78 : :
79 [ # # ]: 0 : if (!have_ifidx && !have_wdev_id)
80 : : return ERR_PTR(-EINVAL);
81 : :
82 [ # # ]: 0 : if (have_ifidx)
83 : 0 : ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
84 [ # # ]: 0 : if (have_wdev_id) {
85 : 0 : wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
86 : 0 : wiphy_idx = wdev_id >> 32;
87 : : }
88 : :
89 [ # # ]: 0 : list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
90 : 0 : struct wireless_dev *wdev;
91 : :
92 [ # # ]: 0 : if (wiphy_net(&rdev->wiphy) != netns)
93 : 0 : continue;
94 : :
95 [ # # # # ]: 0 : if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
96 : 0 : continue;
97 : :
98 [ # # ]: 0 : list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
99 [ # # # # ]: 0 : if (have_ifidx && wdev->netdev &&
100 [ # # ]: 0 : wdev->netdev->ifindex == ifidx) {
101 : : result = wdev;
102 : : break;
103 : : }
104 [ # # # # ]: 0 : if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
105 : : result = wdev;
106 : : break;
107 : : }
108 : : }
109 : :
110 [ # # ]: 0 : if (result)
111 : : break;
112 : : }
113 : :
114 [ # # ]: 0 : if (result)
115 : 0 : return result;
116 : : return ERR_PTR(-ENODEV);
117 : : }
118 : :
119 : : static struct cfg80211_registered_device *
120 : 0 : __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
121 : : {
122 : 0 : struct cfg80211_registered_device *rdev = NULL, *tmp;
123 : 0 : struct net_device *netdev;
124 : :
125 [ # # # # ]: 0 : ASSERT_RTNL();
126 : :
127 [ # # ]: 0 : if (!attrs[NL80211_ATTR_WIPHY] &&
128 [ # # ]: 0 : !attrs[NL80211_ATTR_IFINDEX] &&
129 [ # # ]: 0 : !attrs[NL80211_ATTR_WDEV])
130 : : return ERR_PTR(-EINVAL);
131 : :
132 [ # # ]: 0 : if (attrs[NL80211_ATTR_WIPHY])
133 : 0 : rdev = cfg80211_rdev_by_wiphy_idx(
134 : : nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
135 : :
136 [ # # ]: 0 : if (attrs[NL80211_ATTR_WDEV]) {
137 : 0 : u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
138 : 0 : struct wireless_dev *wdev;
139 : 0 : bool found = false;
140 : :
141 : 0 : tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
142 [ # # ]: 0 : if (tmp) {
143 : : /* make sure wdev exists */
144 [ # # ]: 0 : list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
145 [ # # ]: 0 : if (wdev->identifier != (u32)wdev_id)
146 : 0 : continue;
147 : : found = true;
148 : : break;
149 : : }
150 : :
151 [ # # ]: 0 : if (!found)
152 : 0 : tmp = NULL;
153 : :
154 [ # # ]: 0 : if (rdev && tmp != rdev)
155 : : return ERR_PTR(-EINVAL);
156 : : rdev = tmp;
157 : : }
158 : : }
159 : :
160 [ # # ]: 0 : if (attrs[NL80211_ATTR_IFINDEX]) {
161 : 0 : int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
162 : :
163 : 0 : netdev = __dev_get_by_index(netns, ifindex);
164 [ # # ]: 0 : if (netdev) {
165 [ # # ]: 0 : if (netdev->ieee80211_ptr)
166 [ # # ]: 0 : tmp = wiphy_to_rdev(
167 : : netdev->ieee80211_ptr->wiphy);
168 : : else
169 : : tmp = NULL;
170 : :
171 : : /* not wireless device -- return error */
172 [ # # ]: 0 : if (!tmp)
173 : : return ERR_PTR(-EINVAL);
174 : :
175 : : /* mismatch -- return error */
176 [ # # ]: 0 : if (rdev && tmp != rdev)
177 : : return ERR_PTR(-EINVAL);
178 : :
179 : : rdev = tmp;
180 : : }
181 : : }
182 : :
183 [ # # ]: 0 : if (!rdev)
184 : : return ERR_PTR(-ENODEV);
185 : :
186 [ # # ]: 0 : if (netns != wiphy_net(&rdev->wiphy))
187 : 0 : return ERR_PTR(-ENODEV);
188 : :
189 : : return rdev;
190 : : }
191 : :
192 : : /*
193 : : * This function returns a pointer to the driver
194 : : * that the genl_info item that is passed refers to.
195 : : *
196 : : * The result of this can be a PTR_ERR and hence must
197 : : * be checked with IS_ERR() for errors.
198 : : */
199 : : static struct cfg80211_registered_device *
200 : 0 : cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
201 : : {
202 : 0 : return __cfg80211_rdev_from_attrs(netns, info->attrs);
203 : : }
204 : :
205 : 0 : static int validate_beacon_head(const struct nlattr *attr,
206 : : struct netlink_ext_ack *extack)
207 : : {
208 [ # # ]: 0 : const u8 *data = nla_data(attr);
209 [ # # ]: 0 : unsigned int len = nla_len(attr);
210 : 0 : const struct element *elem;
211 : 0 : const struct ieee80211_mgmt *mgmt = (void *)data;
212 : 0 : unsigned int fixedlen = offsetof(struct ieee80211_mgmt,
213 : : u.beacon.variable);
214 : :
215 [ # # ]: 0 : if (len < fixedlen)
216 : 0 : goto err;
217 : :
218 [ # # ]: 0 : if (ieee80211_hdrlen(mgmt->frame_control) !=
219 : : offsetof(struct ieee80211_mgmt, u.beacon))
220 : 0 : goto err;
221 : :
222 : 0 : data += fixedlen;
223 : 0 : len -= fixedlen;
224 : :
225 [ # # # # ]: 0 : for_each_element(elem, data, len) {
226 : : /* nothing */
227 : 0 : }
228 : :
229 [ # # ]: 0 : if (for_each_element_completed(elem, data, len))
230 : : return 0;
231 : :
232 : 0 : err:
233 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, attr, "malformed beacon head");
234 : : return -EINVAL;
235 : : }
236 : :
237 : 0 : static int validate_ie_attr(const struct nlattr *attr,
238 : : struct netlink_ext_ack *extack)
239 : : {
240 : 0 : const u8 *data = nla_data(attr);
241 : 0 : unsigned int len = nla_len(attr);
242 : 0 : const struct element *elem;
243 : :
244 [ # # # # ]: 0 : for_each_element(elem, data, len) {
245 : : /* nothing */
246 : 0 : }
247 : :
248 [ # # ]: 0 : if (for_each_element_completed(elem, data, len))
249 : : return 0;
250 : :
251 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, attr, "malformed information elements");
252 : : return -EINVAL;
253 : : }
254 : :
255 : : /* policy for the attributes */
256 : : static const struct nla_policy
257 : : nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
258 : : [NL80211_FTM_RESP_ATTR_ENABLED] = { .type = NLA_FLAG, },
259 : : [NL80211_FTM_RESP_ATTR_LCI] = { .type = NLA_BINARY,
260 : : .len = U8_MAX },
261 : : [NL80211_FTM_RESP_ATTR_CIVICLOC] = { .type = NLA_BINARY,
262 : : .len = U8_MAX },
263 : : };
264 : :
265 : : static const struct nla_policy
266 : : nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = {
267 : : [NL80211_PMSR_FTM_REQ_ATTR_ASAP] = { .type = NLA_FLAG },
268 : : [NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] = { .type = NLA_U32 },
269 : : [NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP] =
270 : : NLA_POLICY_MAX(NLA_U8, 15),
271 : : [NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 },
272 : : [NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] =
273 : : NLA_POLICY_MAX(NLA_U8, 15),
274 : : [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] =
275 : : NLA_POLICY_MAX(NLA_U8, 31),
276 : : [NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES] = { .type = NLA_U8 },
277 : : [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI] = { .type = NLA_FLAG },
278 : : [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC] = { .type = NLA_FLAG },
279 : : };
280 : :
281 : : static const struct nla_policy
282 : : nl80211_pmsr_req_data_policy[NL80211_PMSR_TYPE_MAX + 1] = {
283 : : [NL80211_PMSR_TYPE_FTM] =
284 : : NLA_POLICY_NESTED(nl80211_pmsr_ftm_req_attr_policy),
285 : : };
286 : :
287 : : static const struct nla_policy
288 : : nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = {
289 : : [NL80211_PMSR_REQ_ATTR_DATA] =
290 : : NLA_POLICY_NESTED(nl80211_pmsr_req_data_policy),
291 : : [NL80211_PMSR_REQ_ATTR_GET_AP_TSF] = { .type = NLA_FLAG },
292 : : };
293 : :
294 : : static const struct nla_policy
295 : : nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
296 : : [NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR,
297 : : /*
298 : : * we could specify this again to be the top-level policy,
299 : : * but that would open us up to recursion problems ...
300 : : */
301 : : [NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_NESTED },
302 : : [NL80211_PMSR_PEER_ATTR_REQ] =
303 : : NLA_POLICY_NESTED(nl80211_pmsr_req_attr_policy),
304 : : [NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_REJECT },
305 : : };
306 : :
307 : : static const struct nla_policy
308 : : nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
309 : : [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_REJECT },
310 : : [NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_REJECT },
311 : : [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT },
312 : : [NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_REJECT },
313 : : [NL80211_PMSR_ATTR_PEERS] =
314 : : NLA_POLICY_NESTED_ARRAY(nl80211_psmr_peer_attr_policy),
315 : : };
316 : :
317 : : static const struct nla_policy
318 : : he_obss_pd_policy[NL80211_HE_OBSS_PD_ATTR_MAX + 1] = {
319 : : [NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET] =
320 : : NLA_POLICY_RANGE(NLA_U8, 1, 20),
321 : : [NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET] =
322 : : NLA_POLICY_RANGE(NLA_U8, 1, 20),
323 : : };
324 : :
325 : : const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
326 : : [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
327 : : [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
328 : : [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
329 : : .len = 20-1 },
330 : : [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
331 : :
332 : : [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
333 : : [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
334 : : [NL80211_ATTR_WIPHY_EDMG_CHANNELS] = NLA_POLICY_RANGE(NLA_U8,
335 : : NL80211_EDMG_CHANNELS_MIN,
336 : : NL80211_EDMG_CHANNELS_MAX),
337 : : [NL80211_ATTR_WIPHY_EDMG_BW_CONFIG] = NLA_POLICY_RANGE(NLA_U8,
338 : : NL80211_EDMG_BW_CONFIG_MIN,
339 : : NL80211_EDMG_BW_CONFIG_MAX),
340 : :
341 : : [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
342 : : [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
343 : : [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
344 : :
345 : : [NL80211_ATTR_WIPHY_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
346 : : [NL80211_ATTR_WIPHY_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
347 : : [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
348 : : [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
349 : : [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
350 : : [NL80211_ATTR_WIPHY_DYN_ACK] = { .type = NLA_FLAG },
351 : :
352 : : [NL80211_ATTR_IFTYPE] = NLA_POLICY_MAX(NLA_U32, NL80211_IFTYPE_MAX),
353 : : [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
354 : : [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
355 : :
356 : : [NL80211_ATTR_MAC] = { .type = NLA_EXACT_LEN_WARN, .len = ETH_ALEN },
357 : : [NL80211_ATTR_PREV_BSSID] = {
358 : : .type = NLA_EXACT_LEN_WARN,
359 : : .len = ETH_ALEN
360 : : },
361 : :
362 : : [NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
363 : : [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
364 : : .len = WLAN_MAX_KEY_LEN },
365 : : [NL80211_ATTR_KEY_IDX] = NLA_POLICY_MAX(NLA_U8, 5),
366 : : [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
367 : : [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
368 : : [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
369 : : [NL80211_ATTR_KEY_TYPE] =
370 : : NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES),
371 : :
372 : : [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
373 : : [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
374 : : [NL80211_ATTR_BEACON_HEAD] =
375 : : NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_beacon_head,
376 : : IEEE80211_MAX_DATA_LEN),
377 : : [NL80211_ATTR_BEACON_TAIL] =
378 : : NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
379 : : IEEE80211_MAX_DATA_LEN),
380 : : [NL80211_ATTR_STA_AID] =
381 : : NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
382 : : [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
383 : : [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
384 : : [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
385 : : .len = NL80211_MAX_SUPP_RATES },
386 : : [NL80211_ATTR_STA_PLINK_ACTION] =
387 : : NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_ACTIONS - 1),
388 : : [NL80211_ATTR_STA_TX_POWER_SETTING] =
389 : : NLA_POLICY_RANGE(NLA_U8,
390 : : NL80211_TX_POWER_AUTOMATIC,
391 : : NL80211_TX_POWER_FIXED),
392 : : [NL80211_ATTR_STA_TX_POWER] = { .type = NLA_S16 },
393 : : [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
394 : : [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
395 : : [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
396 : : .len = IEEE80211_MAX_MESH_ID_LEN },
397 : : [NL80211_ATTR_MPATH_NEXT_HOP] = NLA_POLICY_ETH_ADDR_COMPAT,
398 : :
399 : : [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
400 : : [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
401 : :
402 : : [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
403 : : [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
404 : : [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
405 : : [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY,
406 : : .len = NL80211_MAX_SUPP_RATES },
407 : : [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 },
408 : :
409 : : [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
410 : : [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
411 : :
412 : : [NL80211_ATTR_HT_CAPABILITY] = {
413 : : .type = NLA_EXACT_LEN_WARN,
414 : : .len = NL80211_HT_CAPABILITY_LEN
415 : : },
416 : :
417 : : [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
418 : : [NL80211_ATTR_IE] = NLA_POLICY_VALIDATE_FN(NLA_BINARY,
419 : : validate_ie_attr,
420 : : IEEE80211_MAX_DATA_LEN),
421 : : [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
422 : : [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
423 : :
424 : : [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
425 : : .len = IEEE80211_MAX_SSID_LEN },
426 : : [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
427 : : [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
428 : : [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
429 : : [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
430 : : [NL80211_ATTR_USE_MFP] = NLA_POLICY_RANGE(NLA_U32,
431 : : NL80211_MFP_NO,
432 : : NL80211_MFP_OPTIONAL),
433 : : [NL80211_ATTR_STA_FLAGS2] = {
434 : : .len = sizeof(struct nl80211_sta_flag_update),
435 : : },
436 : : [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
437 : : [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
438 : : [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
439 : : [NL80211_ATTR_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG },
440 : : [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
441 : : [NL80211_ATTR_STATUS_CODE] = { .type = NLA_U16 },
442 : : [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
443 : : [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
444 : : [NL80211_ATTR_PID] = { .type = NLA_U32 },
445 : : [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
446 : : [NL80211_ATTR_PMKID] = {
447 : : .type = NLA_EXACT_LEN_WARN,
448 : : .len = WLAN_PMKID_LEN
449 : : },
450 : : [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
451 : : [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
452 : : [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
453 : : [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
454 : : .len = IEEE80211_MAX_DATA_LEN },
455 : : [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
456 : : [NL80211_ATTR_PS_STATE] = NLA_POLICY_RANGE(NLA_U32,
457 : : NL80211_PS_DISABLED,
458 : : NL80211_PS_ENABLED),
459 : : [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
460 : : [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
461 : : [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
462 : : [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
463 : : [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
464 : : [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
465 : : [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 },
466 : : [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
467 : : [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
468 : : [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
469 : : [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
470 : : [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
471 : : [NL80211_ATTR_STA_PLINK_STATE] =
472 : : NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_STATES - 1),
473 : : [NL80211_ATTR_MEASUREMENT_DURATION] = { .type = NLA_U16 },
474 : : [NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY] = { .type = NLA_FLAG },
475 : : [NL80211_ATTR_MESH_PEER_AID] =
476 : : NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
477 : : [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
478 : : [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
479 : : [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
480 : : [NL80211_ATTR_HIDDEN_SSID] =
481 : : NLA_POLICY_RANGE(NLA_U32,
482 : : NL80211_HIDDEN_SSID_NOT_IN_USE,
483 : : NL80211_HIDDEN_SSID_ZERO_CONTENTS),
484 : : [NL80211_ATTR_IE_PROBE_RESP] =
485 : : NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
486 : : IEEE80211_MAX_DATA_LEN),
487 : : [NL80211_ATTR_IE_ASSOC_RESP] =
488 : : NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
489 : : IEEE80211_MAX_DATA_LEN),
490 : : [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
491 : : [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
492 : : [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
493 : : [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
494 : : [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
495 : : [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
496 : : [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
497 : : [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
498 : : [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG },
499 : : [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
500 : : [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
501 : : .len = IEEE80211_MAX_DATA_LEN },
502 : : [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
503 : : [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
504 : : [NL80211_ATTR_HT_CAPABILITY_MASK] = {
505 : : .len = NL80211_HT_CAPABILITY_LEN
506 : : },
507 : : [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
508 : : [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
509 : : [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
510 : : [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
511 : : [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
512 : : [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
513 : : [NL80211_ATTR_VHT_CAPABILITY] = {
514 : : .type = NLA_EXACT_LEN_WARN,
515 : : .len = NL80211_VHT_CAPABILITY_LEN
516 : : },
517 : : [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
518 : : [NL80211_ATTR_P2P_CTWINDOW] = NLA_POLICY_MAX(NLA_U8, 127),
519 : : [NL80211_ATTR_P2P_OPPPS] = NLA_POLICY_MAX(NLA_U8, 1),
520 : : [NL80211_ATTR_LOCAL_MESH_POWER_MODE] =
521 : : NLA_POLICY_RANGE(NLA_U32,
522 : : NL80211_MESH_POWER_UNKNOWN + 1,
523 : : NL80211_MESH_POWER_MAX),
524 : : [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
525 : : [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
526 : : [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
527 : : [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
528 : : [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
529 : : [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG },
530 : : [NL80211_ATTR_VHT_CAPABILITY_MASK] = {
531 : : .len = NL80211_VHT_CAPABILITY_LEN,
532 : : },
533 : : [NL80211_ATTR_MDID] = { .type = NLA_U16 },
534 : : [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
535 : : .len = IEEE80211_MAX_DATA_LEN },
536 : : [NL80211_ATTR_CRIT_PROT_ID] = { .type = NLA_U16 },
537 : : [NL80211_ATTR_MAX_CRIT_PROT_DURATION] = { .type = NLA_U16 },
538 : : [NL80211_ATTR_PEER_AID] =
539 : : NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
540 : : [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
541 : : [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
542 : : [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
543 : : [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_BINARY },
544 : : [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_BINARY },
545 : : [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
546 : : [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
547 : : [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
548 : : [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
549 : : [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
550 : : [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
551 : : [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
552 : : [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
553 : : .len = IEEE80211_QOS_MAP_LEN_MAX },
554 : : [NL80211_ATTR_MAC_HINT] = {
555 : : .type = NLA_EXACT_LEN_WARN,
556 : : .len = ETH_ALEN
557 : : },
558 : : [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
559 : : [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
560 : : [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
561 : : [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
562 : : [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
563 : : [NL80211_ATTR_TSID] = NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_TIDS - 1),
564 : : [NL80211_ATTR_USER_PRIO] =
565 : : NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_UPS - 1),
566 : : [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
567 : : [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
568 : : [NL80211_ATTR_OPER_CLASS] = { .type = NLA_U8 },
569 : : [NL80211_ATTR_MAC_MASK] = {
570 : : .type = NLA_EXACT_LEN_WARN,
571 : : .len = ETH_ALEN
572 : : },
573 : : [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
574 : : [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
575 : : [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
576 : : [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
577 : : [NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
578 : : [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
579 : : [NL80211_ATTR_STA_SUPPORT_P2P_PS] =
580 : : NLA_POLICY_MAX(NLA_U8, NUM_NL80211_P2P_PS_STATUS - 1),
581 : : [NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
582 : : .len = VHT_MUMIMO_GROUPS_DATA_LEN
583 : : },
584 : : [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = {
585 : : .type = NLA_EXACT_LEN_WARN,
586 : : .len = ETH_ALEN
587 : : },
588 : : [NL80211_ATTR_NAN_MASTER_PREF] = NLA_POLICY_MIN(NLA_U8, 1),
589 : : [NL80211_ATTR_BANDS] = { .type = NLA_U32 },
590 : : [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
591 : : [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
592 : : .len = FILS_MAX_KEK_LEN },
593 : : [NL80211_ATTR_FILS_NONCES] = {
594 : : .type = NLA_EXACT_LEN_WARN,
595 : : .len = 2 * FILS_NONCE_LEN
596 : : },
597 : : [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
598 : : [NL80211_ATTR_BSSID] = { .type = NLA_EXACT_LEN_WARN, .len = ETH_ALEN },
599 : : [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
600 : : [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
601 : : .len = sizeof(struct nl80211_bss_select_rssi_adjust)
602 : : },
603 : : [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
604 : : [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
605 : : .len = FILS_ERP_MAX_USERNAME_LEN },
606 : : [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
607 : : .len = FILS_ERP_MAX_REALM_LEN },
608 : : [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
609 : : [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
610 : : .len = FILS_ERP_MAX_RRK_LEN },
611 : : [NL80211_ATTR_FILS_CACHE_ID] = { .type = NLA_EXACT_LEN_WARN, .len = 2 },
612 : : [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
613 : : [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
614 : : [NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
615 : :
616 : : [NL80211_ATTR_TXQ_LIMIT] = { .type = NLA_U32 },
617 : : [NL80211_ATTR_TXQ_MEMORY_LIMIT] = { .type = NLA_U32 },
618 : : [NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
619 : : [NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
620 : : .len = NL80211_HE_MAX_CAPABILITY_LEN },
621 : :
622 : : [NL80211_ATTR_FTM_RESPONDER] = {
623 : : .type = NLA_NESTED,
624 : : .validation_data = nl80211_ftm_responder_policy,
625 : : },
626 : : [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1),
627 : : [NL80211_ATTR_PEER_MEASUREMENTS] =
628 : : NLA_POLICY_NESTED(nl80211_pmsr_attr_policy),
629 : : [NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
630 : : [NL80211_ATTR_SAE_PASSWORD] = { .type = NLA_BINARY,
631 : : .len = SAE_PASSWORD_MAX_LEN },
632 : : [NL80211_ATTR_TWT_RESPONDER] = { .type = NLA_FLAG },
633 : : [NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy),
634 : : [NL80211_ATTR_VLAN_ID] = NLA_POLICY_RANGE(NLA_U16, 1, VLAN_N_VID - 2),
635 : : };
636 : :
637 : : /* policy for the key attributes */
638 : : static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
639 : : [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
640 : : [NL80211_KEY_IDX] = { .type = NLA_U8 },
641 : : [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
642 : : [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
643 : : [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
644 : : [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
645 : : [NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1),
646 : : [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
647 : : [NL80211_KEY_MODE] = NLA_POLICY_RANGE(NLA_U8, 0, NL80211_KEY_SET_TX),
648 : : };
649 : :
650 : : /* policy for the key default flags */
651 : : static const struct nla_policy
652 : : nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
653 : : [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
654 : : [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
655 : : };
656 : :
657 : : #ifdef CONFIG_PM
658 : : /* policy for WoWLAN attributes */
659 : : static const struct nla_policy
660 : : nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
661 : : [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
662 : : [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
663 : : [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
664 : : [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
665 : : [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG },
666 : : [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG },
667 : : [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG },
668 : : [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG },
669 : : [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED },
670 : : [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED },
671 : : };
672 : :
673 : : static const struct nla_policy
674 : : nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
675 : : [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
676 : : [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
677 : : [NL80211_WOWLAN_TCP_DST_MAC] = {
678 : : .type = NLA_EXACT_LEN_WARN,
679 : : .len = ETH_ALEN
680 : : },
681 : : [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
682 : : [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
683 : : [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .type = NLA_MIN_LEN, .len = 1 },
684 : : [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
685 : : .len = sizeof(struct nl80211_wowlan_tcp_data_seq)
686 : : },
687 : : [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = {
688 : : .len = sizeof(struct nl80211_wowlan_tcp_data_token)
689 : : },
690 : : [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
691 : : [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .type = NLA_MIN_LEN, .len = 1 },
692 : : [NL80211_WOWLAN_TCP_WAKE_MASK] = { .type = NLA_MIN_LEN, .len = 1 },
693 : : };
694 : : #endif /* CONFIG_PM */
695 : :
696 : : /* policy for coalesce rule attributes */
697 : : static const struct nla_policy
698 : : nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
699 : : [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
700 : : [NL80211_ATTR_COALESCE_RULE_CONDITION] =
701 : : NLA_POLICY_RANGE(NLA_U32,
702 : : NL80211_COALESCE_CONDITION_MATCH,
703 : : NL80211_COALESCE_CONDITION_NO_MATCH),
704 : : [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
705 : : };
706 : :
707 : : /* policy for GTK rekey offload attributes */
708 : : static const struct nla_policy
709 : : nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
710 : : [NL80211_REKEY_DATA_KEK] = {
711 : : .type = NLA_EXACT_LEN_WARN,
712 : : .len = NL80211_KEK_LEN,
713 : : },
714 : : [NL80211_REKEY_DATA_KCK] = {
715 : : .type = NLA_EXACT_LEN_WARN,
716 : : .len = NL80211_KCK_LEN,
717 : : },
718 : : [NL80211_REKEY_DATA_REPLAY_CTR] = {
719 : : .type = NLA_EXACT_LEN_WARN,
720 : : .len = NL80211_REPLAY_CTR_LEN
721 : : },
722 : : };
723 : :
724 : : static const struct nla_policy
725 : : nl80211_match_band_rssi_policy[NUM_NL80211_BANDS] = {
726 : : [NL80211_BAND_2GHZ] = { .type = NLA_S32 },
727 : : [NL80211_BAND_5GHZ] = { .type = NLA_S32 },
728 : : [NL80211_BAND_6GHZ] = { .type = NLA_S32 },
729 : : [NL80211_BAND_60GHZ] = { .type = NLA_S32 },
730 : : };
731 : :
732 : : static const struct nla_policy
733 : : nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
734 : : [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
735 : : .len = IEEE80211_MAX_SSID_LEN },
736 : : [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = {
737 : : .type = NLA_EXACT_LEN_WARN,
738 : : .len = ETH_ALEN
739 : : },
740 : : [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
741 : : [NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] =
742 : : NLA_POLICY_NESTED(nl80211_match_band_rssi_policy),
743 : : };
744 : :
745 : : static const struct nla_policy
746 : : nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
747 : : [NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
748 : : [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
749 : : };
750 : :
751 : : static const struct nla_policy
752 : : nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
753 : : [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
754 : : [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
755 : : [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
756 : : .len = sizeof(struct nl80211_bss_select_rssi_adjust)
757 : : },
758 : : };
759 : :
760 : : /* policy for NAN function attributes */
761 : : static const struct nla_policy
762 : : nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
763 : : [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
764 : : [NL80211_NAN_FUNC_SERVICE_ID] = {
765 : : .len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
766 : : [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
767 : : [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
768 : : [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
769 : : [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
770 : : [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
771 : : [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = {
772 : : .type = NLA_EXACT_LEN_WARN,
773 : : .len = ETH_ALEN
774 : : },
775 : : [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
776 : : [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
777 : : [NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
778 : : .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN },
779 : : [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
780 : : [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
781 : : [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
782 : : [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8 },
783 : : [NL80211_NAN_FUNC_TERM_REASON] = { .type = NLA_U8 },
784 : : };
785 : :
786 : : /* policy for Service Response Filter attributes */
787 : : static const struct nla_policy
788 : : nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
789 : : [NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG },
790 : : [NL80211_NAN_SRF_BF] = { .type = NLA_BINARY,
791 : : .len = NL80211_NAN_FUNC_SRF_MAX_LEN },
792 : : [NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 },
793 : : [NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED },
794 : : };
795 : :
796 : : /* policy for packet pattern attributes */
797 : : static const struct nla_policy
798 : : nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
799 : : [NL80211_PKTPAT_MASK] = { .type = NLA_BINARY, },
800 : : [NL80211_PKTPAT_PATTERN] = { .type = NLA_BINARY, },
801 : : [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 },
802 : : };
803 : :
804 : 0 : int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
805 : : struct cfg80211_registered_device **rdev,
806 : : struct wireless_dev **wdev)
807 : : {
808 : 0 : int err;
809 : :
810 [ # # ]: 0 : if (!cb->args[0]) {
811 : 0 : struct nlattr **attrbuf;
812 : :
813 : 0 : attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
814 : : GFP_KERNEL);
815 [ # # ]: 0 : if (!attrbuf)
816 : : return -ENOMEM;
817 : :
818 : 0 : err = nlmsg_parse_deprecated(cb->nlh,
819 : 0 : GENL_HDRLEN + nl80211_fam.hdrsize,
820 : 0 : attrbuf, nl80211_fam.maxattr,
821 : : nl80211_policy, NULL);
822 [ # # ]: 0 : if (err) {
823 : 0 : kfree(attrbuf);
824 : 0 : return err;
825 : : }
826 : :
827 : 0 : *wdev = __cfg80211_wdev_from_attrs(sock_net(cb->skb->sk),
828 : : attrbuf);
829 : 0 : kfree(attrbuf);
830 [ # # ]: 0 : if (IS_ERR(*wdev))
831 : 0 : return PTR_ERR(*wdev);
832 [ # # ]: 0 : *rdev = wiphy_to_rdev((*wdev)->wiphy);
833 : : /* 0 is the first index - add 1 to parse only once */
834 : 0 : cb->args[0] = (*rdev)->wiphy_idx + 1;
835 : 0 : cb->args[1] = (*wdev)->identifier;
836 : : } else {
837 : : /* subtract the 1 again here */
838 : 0 : struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
839 : 0 : struct wireless_dev *tmp;
840 : :
841 [ # # ]: 0 : if (!wiphy)
842 : : return -ENODEV;
843 : 0 : *rdev = wiphy_to_rdev(wiphy);
844 : 0 : *wdev = NULL;
845 : :
846 [ # # ]: 0 : list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
847 [ # # ]: 0 : if (tmp->identifier == cb->args[1]) {
848 : 0 : *wdev = tmp;
849 : 0 : break;
850 : : }
851 : : }
852 : :
853 [ # # ]: 0 : if (!*wdev)
854 : 0 : return -ENODEV;
855 : : }
856 : :
857 : : return 0;
858 : : }
859 : :
860 : : /* message building helper */
861 : 0 : void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
862 : : int flags, u8 cmd)
863 : : {
864 : : /* since there is no private header just add the generic one */
865 : 0 : return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
866 : : }
867 : :
868 : 0 : static int nl80211_msg_put_wmm_rules(struct sk_buff *msg,
869 : : const struct ieee80211_reg_rule *rule)
870 : : {
871 : 0 : int j;
872 : 0 : struct nlattr *nl_wmm_rules =
873 : : nla_nest_start_noflag(msg, NL80211_FREQUENCY_ATTR_WMM);
874 : :
875 [ # # ]: 0 : if (!nl_wmm_rules)
876 : 0 : goto nla_put_failure;
877 : :
878 [ # # ]: 0 : for (j = 0; j < IEEE80211_NUM_ACS; j++) {
879 : 0 : struct nlattr *nl_wmm_rule = nla_nest_start_noflag(msg, j);
880 : :
881 [ # # ]: 0 : if (!nl_wmm_rule)
882 : 0 : goto nla_put_failure;
883 : :
884 [ # # ]: 0 : if (nla_put_u16(msg, NL80211_WMMR_CW_MIN,
885 [ # # ]: 0 : rule->wmm_rule.client[j].cw_min) ||
886 : : nla_put_u16(msg, NL80211_WMMR_CW_MAX,
887 [ # # ]: 0 : rule->wmm_rule.client[j].cw_max) ||
888 : : nla_put_u8(msg, NL80211_WMMR_AIFSN,
889 [ # # ]: 0 : rule->wmm_rule.client[j].aifsn) ||
890 : : nla_put_u16(msg, NL80211_WMMR_TXOP,
891 : 0 : rule->wmm_rule.client[j].cot))
892 : 0 : goto nla_put_failure;
893 : :
894 : 0 : nla_nest_end(msg, nl_wmm_rule);
895 : : }
896 : 0 : nla_nest_end(msg, nl_wmm_rules);
897 : :
898 : 0 : return 0;
899 : :
900 : : nla_put_failure:
901 : : return -ENOBUFS;
902 : : }
903 : :
904 : 0 : static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
905 : : struct ieee80211_channel *chan,
906 : : bool large)
907 : : {
908 : : /* Some channels must be completely excluded from the
909 : : * list to protect old user-space tools from breaking
910 : : */
911 [ # # # # ]: 0 : if (!large && chan->flags &
912 : : (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
913 : : return 0;
914 : :
915 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
916 : : chan->center_freq))
917 : 0 : goto nla_put_failure;
918 : :
919 [ # # # # ]: 0 : if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
920 : : nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
921 : 0 : goto nla_put_failure;
922 [ # # ]: 0 : if (chan->flags & IEEE80211_CHAN_NO_IR) {
923 [ # # ]: 0 : if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
924 : 0 : goto nla_put_failure;
925 [ # # ]: 0 : if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
926 : 0 : goto nla_put_failure;
927 : : }
928 [ # # ]: 0 : if (chan->flags & IEEE80211_CHAN_RADAR) {
929 [ # # ]: 0 : if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
930 : 0 : goto nla_put_failure;
931 [ # # ]: 0 : if (large) {
932 : 0 : u32 time;
933 : :
934 : 0 : time = elapsed_jiffies_msecs(chan->dfs_state_entered);
935 : :
936 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
937 : 0 : chan->dfs_state))
938 : 0 : goto nla_put_failure;
939 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
940 : : time))
941 : 0 : goto nla_put_failure;
942 [ # # ]: 0 : if (nla_put_u32(msg,
943 : : NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
944 : : chan->dfs_cac_ms))
945 : 0 : goto nla_put_failure;
946 : : }
947 : : }
948 : :
949 [ # # ]: 0 : if (large) {
950 [ # # # # ]: 0 : if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
951 : : nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
952 : 0 : goto nla_put_failure;
953 [ # # # # ]: 0 : if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
954 : : nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
955 : 0 : goto nla_put_failure;
956 [ # # # # ]: 0 : if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
957 : : nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
958 : 0 : goto nla_put_failure;
959 [ # # # # ]: 0 : if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
960 : : nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
961 : 0 : goto nla_put_failure;
962 [ # # # # ]: 0 : if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
963 : : nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
964 : 0 : goto nla_put_failure;
965 [ # # # # ]: 0 : if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
966 : : nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
967 : 0 : goto nla_put_failure;
968 [ # # # # ]: 0 : if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
969 : : nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
970 : 0 : goto nla_put_failure;
971 [ # # # # ]: 0 : if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
972 : : nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
973 : 0 : goto nla_put_failure;
974 : : }
975 : :
976 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
977 : 0 : DBM_TO_MBM(chan->max_power)))
978 : 0 : goto nla_put_failure;
979 : :
980 [ # # ]: 0 : if (large) {
981 : 0 : const struct ieee80211_reg_rule *rule =
982 : 0 : freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
983 : :
984 [ # # # # : 0 : if (!IS_ERR_OR_NULL(rule) && rule->has_wmm) {
# # ]
985 [ # # ]: 0 : if (nl80211_msg_put_wmm_rules(msg, rule))
986 : 0 : goto nla_put_failure;
987 : : }
988 : : }
989 : :
990 : : return 0;
991 : :
992 : : nla_put_failure:
993 : : return -ENOBUFS;
994 : : }
995 : :
996 : 0 : static bool nl80211_put_txq_stats(struct sk_buff *msg,
997 : : struct cfg80211_txq_stats *txqstats,
998 : : int attrtype)
999 : : {
1000 : 0 : struct nlattr *txqattr;
1001 : :
1002 : : #define PUT_TXQVAL_U32(attr, memb) do { \
1003 : : if (txqstats->filled & BIT(NL80211_TXQ_STATS_ ## attr) && \
1004 : : nla_put_u32(msg, NL80211_TXQ_STATS_ ## attr, txqstats->memb)) \
1005 : : return false; \
1006 : : } while (0)
1007 : :
1008 : 0 : txqattr = nla_nest_start_noflag(msg, attrtype);
1009 [ # # ]: 0 : if (!txqattr)
1010 : : return false;
1011 : :
1012 [ # # # # ]: 0 : PUT_TXQVAL_U32(BACKLOG_BYTES, backlog_bytes);
1013 [ # # # # ]: 0 : PUT_TXQVAL_U32(BACKLOG_PACKETS, backlog_packets);
1014 [ # # # # ]: 0 : PUT_TXQVAL_U32(FLOWS, flows);
1015 [ # # # # ]: 0 : PUT_TXQVAL_U32(DROPS, drops);
1016 [ # # # # ]: 0 : PUT_TXQVAL_U32(ECN_MARKS, ecn_marks);
1017 [ # # # # ]: 0 : PUT_TXQVAL_U32(OVERLIMIT, overlimit);
1018 [ # # # # ]: 0 : PUT_TXQVAL_U32(OVERMEMORY, overmemory);
1019 [ # # # # ]: 0 : PUT_TXQVAL_U32(COLLISIONS, collisions);
1020 [ # # # # ]: 0 : PUT_TXQVAL_U32(TX_BYTES, tx_bytes);
1021 [ # # # # ]: 0 : PUT_TXQVAL_U32(TX_PACKETS, tx_packets);
1022 [ # # # # ]: 0 : PUT_TXQVAL_U32(MAX_FLOWS, max_flows);
1023 : 0 : nla_nest_end(msg, txqattr);
1024 : :
1025 : : #undef PUT_TXQVAL_U32
1026 : 0 : return true;
1027 : : }
1028 : :
1029 : : /* netlink command implementations */
1030 : :
1031 : : struct key_parse {
1032 : : struct key_params p;
1033 : : int idx;
1034 : : int type;
1035 : : bool def, defmgmt;
1036 : : bool def_uni, def_multi;
1037 : : };
1038 : :
1039 : : static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
1040 : : struct key_parse *k)
1041 : : {
1042 : : struct nlattr *tb[NL80211_KEY_MAX + 1];
1043 : : int err = nla_parse_nested_deprecated(tb, NL80211_KEY_MAX, key,
1044 : : nl80211_key_policy,
1045 : : info->extack);
1046 : : if (err)
1047 : : return err;
1048 : :
1049 : : k->def = !!tb[NL80211_KEY_DEFAULT];
1050 : : k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
1051 : :
1052 : : if (k->def) {
1053 : : k->def_uni = true;
1054 : : k->def_multi = true;
1055 : : }
1056 : : if (k->defmgmt)
1057 : : k->def_multi = true;
1058 : :
1059 : : if (tb[NL80211_KEY_IDX])
1060 : : k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
1061 : :
1062 : : if (tb[NL80211_KEY_DATA]) {
1063 : : k->p.key = nla_data(tb[NL80211_KEY_DATA]);
1064 : : k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
1065 : : }
1066 : :
1067 : : if (tb[NL80211_KEY_SEQ]) {
1068 : : k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
1069 : : k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
1070 : : }
1071 : :
1072 : : if (tb[NL80211_KEY_CIPHER])
1073 : : k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
1074 : :
1075 : : if (tb[NL80211_KEY_TYPE])
1076 : : k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
1077 : :
1078 : : if (tb[NL80211_KEY_DEFAULT_TYPES]) {
1079 : : struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
1080 : :
1081 : : err = nla_parse_nested_deprecated(kdt,
1082 : : NUM_NL80211_KEY_DEFAULT_TYPES - 1,
1083 : : tb[NL80211_KEY_DEFAULT_TYPES],
1084 : : nl80211_key_default_policy,
1085 : : info->extack);
1086 : : if (err)
1087 : : return err;
1088 : :
1089 : : k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
1090 : : k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
1091 : : }
1092 : :
1093 : : if (tb[NL80211_KEY_MODE])
1094 : : k->p.mode = nla_get_u8(tb[NL80211_KEY_MODE]);
1095 : :
1096 : : return 0;
1097 : : }
1098 : :
1099 : : static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
1100 : : {
1101 : : if (info->attrs[NL80211_ATTR_KEY_DATA]) {
1102 : : k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
1103 : : k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
1104 : : }
1105 : :
1106 : : if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
1107 : : k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
1108 : : k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
1109 : : }
1110 : :
1111 : : if (info->attrs[NL80211_ATTR_KEY_IDX])
1112 : : k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
1113 : :
1114 : : if (info->attrs[NL80211_ATTR_KEY_CIPHER])
1115 : : k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
1116 : :
1117 : : k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
1118 : : k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
1119 : :
1120 : : if (k->def) {
1121 : : k->def_uni = true;
1122 : : k->def_multi = true;
1123 : : }
1124 : : if (k->defmgmt)
1125 : : k->def_multi = true;
1126 : :
1127 : : if (info->attrs[NL80211_ATTR_KEY_TYPE])
1128 : : k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
1129 : :
1130 : : if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
1131 : : struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
1132 : : int err = nla_parse_nested_deprecated(kdt,
1133 : : NUM_NL80211_KEY_DEFAULT_TYPES - 1,
1134 : : info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
1135 : : nl80211_key_default_policy,
1136 : : info->extack);
1137 : : if (err)
1138 : : return err;
1139 : :
1140 : : k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
1141 : : k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
1142 : : }
1143 : :
1144 : : return 0;
1145 : : }
1146 : :
1147 : 0 : static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
1148 : : {
1149 : 0 : int err;
1150 : :
1151 : 0 : memset(k, 0, sizeof(*k));
1152 : 0 : k->idx = -1;
1153 : 0 : k->type = -1;
1154 : :
1155 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_KEY])
1156 : 0 : err = nl80211_parse_key_new(info, info->attrs[NL80211_ATTR_KEY], k);
1157 : : else
1158 : 0 : err = nl80211_parse_key_old(info, k);
1159 : :
1160 [ # # ]: 0 : if (err)
1161 : : return err;
1162 : :
1163 [ # # # # ]: 0 : if (k->def && k->defmgmt) {
1164 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "key with def && defmgmt is invalid");
1165 : 0 : return -EINVAL;
1166 : : }
1167 : :
1168 [ # # ]: 0 : if (k->defmgmt) {
1169 [ # # # # ]: 0 : if (k->def_uni || !k->def_multi) {
1170 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "defmgmt key must be mcast");
1171 : 0 : return -EINVAL;
1172 : : }
1173 : : }
1174 : :
1175 [ # # ]: 0 : if (k->idx != -1) {
1176 [ # # ]: 0 : if (k->defmgmt) {
1177 [ # # ]: 0 : if (k->idx < 4 || k->idx > 5) {
1178 [ # # ]: 0 : GENL_SET_ERR_MSG(info,
1179 : : "defmgmt key idx not 4 or 5");
1180 : 0 : return -EINVAL;
1181 : : }
1182 [ # # ]: 0 : } else if (k->def) {
1183 [ # # ]: 0 : if (k->idx < 0 || k->idx > 3) {
1184 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "def key idx not 0-3");
1185 : 0 : return -EINVAL;
1186 : : }
1187 : : } else {
1188 [ # # ]: 0 : if (k->idx < 0 || k->idx > 5) {
1189 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "key idx not 0-5");
1190 : 0 : return -EINVAL;
1191 : : }
1192 : : }
1193 : : }
1194 : :
1195 : : return 0;
1196 : : }
1197 : :
1198 : : static struct cfg80211_cached_keys *
1199 : 0 : nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
1200 : : struct genl_info *info, bool *no_ht)
1201 : : {
1202 : 0 : struct nlattr *keys = info->attrs[NL80211_ATTR_KEYS];
1203 : 0 : struct key_parse parse;
1204 : 0 : struct nlattr *key;
1205 : 0 : struct cfg80211_cached_keys *result;
1206 : 0 : int rem, err, def = 0;
1207 : 0 : bool have_key = false;
1208 : :
1209 [ # # ]: 0 : nla_for_each_nested(key, keys, rem) {
1210 : 0 : have_key = true;
1211 : 0 : break;
1212 : : }
1213 : :
1214 : 0 : if (!have_key)
1215 : : return NULL;
1216 : :
1217 : 0 : result = kzalloc(sizeof(*result), GFP_KERNEL);
1218 [ # # ]: 0 : if (!result)
1219 : : return ERR_PTR(-ENOMEM);
1220 : :
1221 : 0 : result->def = -1;
1222 : :
1223 [ # # ]: 0 : nla_for_each_nested(key, keys, rem) {
1224 : 0 : memset(&parse, 0, sizeof(parse));
1225 : 0 : parse.idx = -1;
1226 : :
1227 : 0 : err = nl80211_parse_key_new(info, key, &parse);
1228 [ # # ]: 0 : if (err)
1229 : 0 : goto error;
1230 : 0 : err = -EINVAL;
1231 [ # # ]: 0 : if (!parse.p.key)
1232 : 0 : goto error;
1233 [ # # ]: 0 : if (parse.idx < 0 || parse.idx > 3) {
1234 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "key index out of range [0-3]");
1235 : 0 : goto error;
1236 : : }
1237 [ # # ]: 0 : if (parse.def) {
1238 [ # # ]: 0 : if (def) {
1239 [ # # ]: 0 : GENL_SET_ERR_MSG(info,
1240 : : "only one key can be default");
1241 : 0 : goto error;
1242 : : }
1243 : 0 : def = 1;
1244 : 0 : result->def = parse.idx;
1245 [ # # # # ]: 0 : if (!parse.def_uni || !parse.def_multi)
1246 : 0 : goto error;
1247 [ # # ]: 0 : } else if (parse.defmgmt)
1248 : 0 : goto error;
1249 : 0 : err = cfg80211_validate_key_settings(rdev, &parse.p,
1250 : : parse.idx, false, NULL);
1251 [ # # ]: 0 : if (err)
1252 : 0 : goto error;
1253 [ # # ]: 0 : if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
1254 : : parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) {
1255 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "connect key must be WEP");
1256 : 0 : err = -EINVAL;
1257 : 0 : goto error;
1258 : : }
1259 : 0 : result->params[parse.idx].cipher = parse.p.cipher;
1260 : 0 : result->params[parse.idx].key_len = parse.p.key_len;
1261 : 0 : result->params[parse.idx].key = result->data[parse.idx];
1262 : 0 : memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
1263 : :
1264 : : /* must be WEP key if we got here */
1265 [ # # ]: 0 : if (no_ht)
1266 : 0 : *no_ht = true;
1267 : : }
1268 : :
1269 [ # # ]: 0 : if (result->def < 0) {
1270 : 0 : err = -EINVAL;
1271 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "need a default/TX key");
1272 : 0 : goto error;
1273 : : }
1274 : :
1275 : : return result;
1276 : 0 : error:
1277 : 0 : kfree(result);
1278 : 0 : return ERR_PTR(err);
1279 : : }
1280 : :
1281 : 0 : static int nl80211_key_allowed(struct wireless_dev *wdev)
1282 : : {
1283 : 0 : ASSERT_WDEV_LOCK(wdev);
1284 : :
1285 : 0 : switch (wdev->iftype) {
1286 : : case NL80211_IFTYPE_AP:
1287 : : case NL80211_IFTYPE_AP_VLAN:
1288 : : case NL80211_IFTYPE_P2P_GO:
1289 : : case NL80211_IFTYPE_MESH_POINT:
1290 : : break;
1291 : 0 : case NL80211_IFTYPE_ADHOC:
1292 : : case NL80211_IFTYPE_STATION:
1293 : : case NL80211_IFTYPE_P2P_CLIENT:
1294 [ # # # # : 0 : if (!wdev->current_bss)
# # # # #
# ]
1295 : : return -ENOLINK;
1296 : : break;
1297 : : case NL80211_IFTYPE_UNSPECIFIED:
1298 : : case NL80211_IFTYPE_OCB:
1299 : : case NL80211_IFTYPE_MONITOR:
1300 : : case NL80211_IFTYPE_NAN:
1301 : : case NL80211_IFTYPE_P2P_DEVICE:
1302 : : case NL80211_IFTYPE_WDS:
1303 : : case NUM_NL80211_IFTYPES:
1304 : : return -EINVAL;
1305 : : }
1306 : :
1307 : 0 : return 0;
1308 : : }
1309 : :
1310 : 0 : static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
1311 : : struct nlattr *tb)
1312 : : {
1313 : 0 : struct ieee80211_channel *chan;
1314 : :
1315 [ # # ]: 0 : if (tb == NULL)
1316 : : return NULL;
1317 : 0 : chan = ieee80211_get_channel(wiphy, nla_get_u32(tb));
1318 [ # # # # ]: 0 : if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
1319 : 0 : return NULL;
1320 : : return chan;
1321 : : }
1322 : :
1323 : 0 : static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
1324 : : {
1325 : 0 : struct nlattr *nl_modes = nla_nest_start_noflag(msg, attr);
1326 : 0 : int i;
1327 : :
1328 [ # # ]: 0 : if (!nl_modes)
1329 : 0 : goto nla_put_failure;
1330 : :
1331 : : i = 0;
1332 [ # # ]: 0 : while (ifmodes) {
1333 [ # # # # ]: 0 : if ((ifmodes & 1) && nla_put_flag(msg, i))
1334 : 0 : goto nla_put_failure;
1335 : 0 : ifmodes >>= 1;
1336 : 0 : i++;
1337 : : }
1338 : :
1339 : 0 : nla_nest_end(msg, nl_modes);
1340 : 0 : return 0;
1341 : :
1342 : : nla_put_failure:
1343 : : return -ENOBUFS;
1344 : : }
1345 : :
1346 : 0 : static int nl80211_put_iface_combinations(struct wiphy *wiphy,
1347 : : struct sk_buff *msg,
1348 : : bool large)
1349 : : {
1350 : 0 : struct nlattr *nl_combis;
1351 : 0 : int i, j;
1352 : :
1353 : 0 : nl_combis = nla_nest_start_noflag(msg,
1354 : : NL80211_ATTR_INTERFACE_COMBINATIONS);
1355 [ # # ]: 0 : if (!nl_combis)
1356 : 0 : goto nla_put_failure;
1357 : :
1358 [ # # ]: 0 : for (i = 0; i < wiphy->n_iface_combinations; i++) {
1359 : 0 : const struct ieee80211_iface_combination *c;
1360 : 0 : struct nlattr *nl_combi, *nl_limits;
1361 : :
1362 : 0 : c = &wiphy->iface_combinations[i];
1363 : :
1364 : 0 : nl_combi = nla_nest_start_noflag(msg, i + 1);
1365 [ # # ]: 0 : if (!nl_combi)
1366 : 0 : goto nla_put_failure;
1367 : :
1368 : 0 : nl_limits = nla_nest_start_noflag(msg,
1369 : : NL80211_IFACE_COMB_LIMITS);
1370 [ # # ]: 0 : if (!nl_limits)
1371 : 0 : goto nla_put_failure;
1372 : :
1373 [ # # ]: 0 : for (j = 0; j < c->n_limits; j++) {
1374 : 0 : struct nlattr *nl_limit;
1375 : :
1376 : 0 : nl_limit = nla_nest_start_noflag(msg, j + 1);
1377 [ # # ]: 0 : if (!nl_limit)
1378 : 0 : goto nla_put_failure;
1379 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
1380 : 0 : c->limits[j].max))
1381 : 0 : goto nla_put_failure;
1382 [ # # ]: 0 : if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
1383 : 0 : c->limits[j].types))
1384 : 0 : goto nla_put_failure;
1385 : 0 : nla_nest_end(msg, nl_limit);
1386 : : }
1387 : :
1388 [ # # ]: 0 : nla_nest_end(msg, nl_limits);
1389 : :
1390 [ # # # # ]: 0 : if (c->beacon_int_infra_match &&
1391 : : nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
1392 : 0 : goto nla_put_failure;
1393 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
1394 [ # # ]: 0 : c->num_different_channels) ||
1395 : 0 : nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
1396 : 0 : c->max_interfaces))
1397 : 0 : goto nla_put_failure;
1398 [ # # # # ]: 0 : if (large &&
1399 : 0 : (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
1400 [ # # ]: 0 : c->radar_detect_widths) ||
1401 : 0 : nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
1402 : 0 : c->radar_detect_regions)))
1403 : 0 : goto nla_put_failure;
1404 [ # # # # ]: 0 : if (c->beacon_int_min_gcd &&
1405 : : nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
1406 : : c->beacon_int_min_gcd))
1407 : 0 : goto nla_put_failure;
1408 : :
1409 : 0 : nla_nest_end(msg, nl_combi);
1410 : : }
1411 : :
1412 : 0 : nla_nest_end(msg, nl_combis);
1413 : :
1414 : 0 : return 0;
1415 : : nla_put_failure:
1416 : : return -ENOBUFS;
1417 : : }
1418 : :
1419 : : #ifdef CONFIG_PM
1420 : : static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
1421 : : struct sk_buff *msg)
1422 : : {
1423 : : const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
1424 : : struct nlattr *nl_tcp;
1425 : :
1426 : : if (!tcp)
1427 : : return 0;
1428 : :
1429 : : nl_tcp = nla_nest_start_noflag(msg,
1430 : : NL80211_WOWLAN_TRIG_TCP_CONNECTION);
1431 : : if (!nl_tcp)
1432 : : return -ENOBUFS;
1433 : :
1434 : : if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1435 : : tcp->data_payload_max))
1436 : : return -ENOBUFS;
1437 : :
1438 : : if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1439 : : tcp->data_payload_max))
1440 : : return -ENOBUFS;
1441 : :
1442 : : if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
1443 : : return -ENOBUFS;
1444 : :
1445 : : if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
1446 : : sizeof(*tcp->tok), tcp->tok))
1447 : : return -ENOBUFS;
1448 : :
1449 : : if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
1450 : : tcp->data_interval_max))
1451 : : return -ENOBUFS;
1452 : :
1453 : : if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
1454 : : tcp->wake_payload_max))
1455 : : return -ENOBUFS;
1456 : :
1457 : : nla_nest_end(msg, nl_tcp);
1458 : : return 0;
1459 : : }
1460 : :
1461 : 0 : static int nl80211_send_wowlan(struct sk_buff *msg,
1462 : : struct cfg80211_registered_device *rdev,
1463 : : bool large)
1464 : : {
1465 : 0 : struct nlattr *nl_wowlan;
1466 : :
1467 [ # # ]: 0 : if (!rdev->wiphy.wowlan)
1468 : : return 0;
1469 : :
1470 : 0 : nl_wowlan = nla_nest_start_noflag(msg,
1471 : : NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
1472 [ # # ]: 0 : if (!nl_wowlan)
1473 : : return -ENOBUFS;
1474 : :
1475 [ # # # # ]: 0 : if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
1476 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
1477 [ # # # # ]: 0 : ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
1478 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
1479 [ # # # # ]: 0 : ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
1480 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
1481 [ # # # # ]: 0 : ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
1482 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
1483 [ # # # # ]: 0 : ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
1484 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
1485 [ # # # # ]: 0 : ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
1486 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
1487 [ # # # # ]: 0 : ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
1488 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
1489 [ # # # # ]: 0 : ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
1490 : : nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
1491 : 0 : return -ENOBUFS;
1492 : :
1493 [ # # ]: 0 : if (rdev->wiphy.wowlan->n_patterns) {
1494 : 0 : struct nl80211_pattern_support pat = {
1495 : 0 : .max_patterns = rdev->wiphy.wowlan->n_patterns,
1496 : 0 : .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
1497 : 0 : .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
1498 : 0 : .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
1499 : : };
1500 : :
1501 [ # # ]: 0 : if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
1502 : : sizeof(pat), &pat))
1503 : 0 : return -ENOBUFS;
1504 : : }
1505 : :
1506 [ # # # # ]: 0 : if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
1507 : 0 : nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
1508 : 0 : rdev->wiphy.wowlan->max_nd_match_sets))
1509 : : return -ENOBUFS;
1510 : :
1511 [ # # # # ]: 0 : if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
1512 : : return -ENOBUFS;
1513 : :
1514 : 0 : nla_nest_end(msg, nl_wowlan);
1515 : :
1516 : 0 : return 0;
1517 : : }
1518 : : #endif
1519 : :
1520 : : static int nl80211_send_coalesce(struct sk_buff *msg,
1521 : : struct cfg80211_registered_device *rdev)
1522 : : {
1523 : : struct nl80211_coalesce_rule_support rule;
1524 : :
1525 : : if (!rdev->wiphy.coalesce)
1526 : : return 0;
1527 : :
1528 : : rule.max_rules = rdev->wiphy.coalesce->n_rules;
1529 : : rule.max_delay = rdev->wiphy.coalesce->max_delay;
1530 : : rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
1531 : : rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
1532 : : rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
1533 : : rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;
1534 : :
1535 : : if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
1536 : : return -ENOBUFS;
1537 : :
1538 : : return 0;
1539 : : }
1540 : :
1541 : : static int
1542 : 0 : nl80211_send_iftype_data(struct sk_buff *msg,
1543 : : const struct ieee80211_sband_iftype_data *iftdata)
1544 : : {
1545 : 0 : const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap;
1546 : :
1547 [ # # ]: 0 : if (nl80211_put_iftypes(msg, NL80211_BAND_IFTYPE_ATTR_IFTYPES,
1548 : 0 : iftdata->types_mask))
1549 : : return -ENOBUFS;
1550 : :
1551 [ # # ]: 0 : if (he_cap->has_he) {
1552 [ # # ]: 0 : if (nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
1553 : : sizeof(he_cap->he_cap_elem.mac_cap_info),
1554 [ # # ]: 0 : he_cap->he_cap_elem.mac_cap_info) ||
1555 : 0 : nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
1556 : : sizeof(he_cap->he_cap_elem.phy_cap_info),
1557 [ # # ]: 0 : he_cap->he_cap_elem.phy_cap_info) ||
1558 : 0 : nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
1559 : : sizeof(he_cap->he_mcs_nss_supp),
1560 [ # # ]: 0 : &he_cap->he_mcs_nss_supp) ||
1561 : 0 : nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
1562 : 0 : sizeof(he_cap->ppe_thres), he_cap->ppe_thres))
1563 : 0 : return -ENOBUFS;
1564 : : }
1565 : :
1566 : : return 0;
1567 : : }
1568 : :
1569 : 0 : static int nl80211_send_band_rateinfo(struct sk_buff *msg,
1570 : : struct ieee80211_supported_band *sband)
1571 : : {
1572 : 0 : struct nlattr *nl_rates, *nl_rate;
1573 : 0 : struct ieee80211_rate *rate;
1574 : 0 : int i;
1575 : :
1576 : : /* add HT info */
1577 [ # # # # ]: 0 : if (sband->ht_cap.ht_supported &&
1578 : 0 : (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
1579 : : sizeof(sband->ht_cap.mcs),
1580 [ # # ]: 0 : &sband->ht_cap.mcs) ||
1581 : : nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
1582 [ # # ]: 0 : sband->ht_cap.cap) ||
1583 : : nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
1584 [ # # ]: 0 : sband->ht_cap.ampdu_factor) ||
1585 : : nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
1586 : 0 : sband->ht_cap.ampdu_density)))
1587 : 0 : return -ENOBUFS;
1588 : :
1589 : : /* add VHT info */
1590 [ # # # # ]: 0 : if (sband->vht_cap.vht_supported &&
1591 : 0 : (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
1592 : : sizeof(sband->vht_cap.vht_mcs),
1593 [ # # ]: 0 : &sband->vht_cap.vht_mcs) ||
1594 : 0 : nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
1595 : : sband->vht_cap.cap)))
1596 : 0 : return -ENOBUFS;
1597 : :
1598 [ # # ]: 0 : if (sband->n_iftype_data) {
1599 : 0 : struct nlattr *nl_iftype_data =
1600 : : nla_nest_start_noflag(msg,
1601 : : NL80211_BAND_ATTR_IFTYPE_DATA);
1602 : 0 : int err;
1603 : :
1604 [ # # ]: 0 : if (!nl_iftype_data)
1605 : : return -ENOBUFS;
1606 : :
1607 [ # # ]: 0 : for (i = 0; i < sband->n_iftype_data; i++) {
1608 : 0 : struct nlattr *iftdata;
1609 : :
1610 : 0 : iftdata = nla_nest_start_noflag(msg, i + 1);
1611 [ # # ]: 0 : if (!iftdata)
1612 : : return -ENOBUFS;
1613 : :
1614 : 0 : err = nl80211_send_iftype_data(msg,
1615 : 0 : &sband->iftype_data[i]);
1616 [ # # ]: 0 : if (err)
1617 : 0 : return err;
1618 : :
1619 : 0 : nla_nest_end(msg, iftdata);
1620 : : }
1621 : :
1622 : 0 : nla_nest_end(msg, nl_iftype_data);
1623 : : }
1624 : :
1625 : : /* add EDMG info */
1626 [ # # # # ]: 0 : if (sband->edmg_cap.channels &&
1627 : : (nla_put_u8(msg, NL80211_BAND_ATTR_EDMG_CHANNELS,
1628 [ # # ]: 0 : sband->edmg_cap.channels) ||
1629 : 0 : nla_put_u8(msg, NL80211_BAND_ATTR_EDMG_BW_CONFIG,
1630 : 0 : sband->edmg_cap.bw_config)))
1631 : :
1632 : 0 : return -ENOBUFS;
1633 : :
1634 : : /* add bitrates */
1635 : 0 : nl_rates = nla_nest_start_noflag(msg, NL80211_BAND_ATTR_RATES);
1636 [ # # ]: 0 : if (!nl_rates)
1637 : : return -ENOBUFS;
1638 : :
1639 [ # # ]: 0 : for (i = 0; i < sband->n_bitrates; i++) {
1640 : 0 : nl_rate = nla_nest_start_noflag(msg, i);
1641 [ # # ]: 0 : if (!nl_rate)
1642 : : return -ENOBUFS;
1643 : :
1644 : 0 : rate = &sband->bitrates[i];
1645 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
1646 : 0 : rate->bitrate))
1647 : : return -ENOBUFS;
1648 [ # # # # ]: 0 : if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
1649 : : nla_put_flag(msg,
1650 : : NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
1651 : : return -ENOBUFS;
1652 : :
1653 : 0 : nla_nest_end(msg, nl_rate);
1654 : : }
1655 : :
1656 : 0 : nla_nest_end(msg, nl_rates);
1657 : :
1658 : 0 : return 0;
1659 : : }
1660 : :
1661 : : static int
1662 : 0 : nl80211_send_mgmt_stypes(struct sk_buff *msg,
1663 : : const struct ieee80211_txrx_stypes *mgmt_stypes)
1664 : : {
1665 : 0 : u16 stypes;
1666 : 0 : struct nlattr *nl_ftypes, *nl_ifs;
1667 : 0 : enum nl80211_iftype ift;
1668 : 0 : int i;
1669 : :
1670 [ # # ]: 0 : if (!mgmt_stypes)
1671 : : return 0;
1672 : :
1673 : 0 : nl_ifs = nla_nest_start_noflag(msg, NL80211_ATTR_TX_FRAME_TYPES);
1674 [ # # ]: 0 : if (!nl_ifs)
1675 : : return -ENOBUFS;
1676 : :
1677 [ # # ]: 0 : for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1678 : 0 : nl_ftypes = nla_nest_start_noflag(msg, ift);
1679 [ # # ]: 0 : if (!nl_ftypes)
1680 : : return -ENOBUFS;
1681 : 0 : i = 0;
1682 : 0 : stypes = mgmt_stypes[ift].tx;
1683 [ # # ]: 0 : while (stypes) {
1684 [ # # # # ]: 0 : if ((stypes & 1) &&
1685 : : nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1686 : 0 : (i << 4) | IEEE80211_FTYPE_MGMT))
1687 : : return -ENOBUFS;
1688 : 0 : stypes >>= 1;
1689 : 0 : i++;
1690 : : }
1691 : 0 : nla_nest_end(msg, nl_ftypes);
1692 : : }
1693 : :
1694 : 0 : nla_nest_end(msg, nl_ifs);
1695 : :
1696 : 0 : nl_ifs = nla_nest_start_noflag(msg, NL80211_ATTR_RX_FRAME_TYPES);
1697 [ # # ]: 0 : if (!nl_ifs)
1698 : : return -ENOBUFS;
1699 : :
1700 [ # # ]: 0 : for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1701 : 0 : nl_ftypes = nla_nest_start_noflag(msg, ift);
1702 [ # # ]: 0 : if (!nl_ftypes)
1703 : : return -ENOBUFS;
1704 : 0 : i = 0;
1705 : 0 : stypes = mgmt_stypes[ift].rx;
1706 [ # # ]: 0 : while (stypes) {
1707 [ # # # # ]: 0 : if ((stypes & 1) &&
1708 : : nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1709 : 0 : (i << 4) | IEEE80211_FTYPE_MGMT))
1710 : : return -ENOBUFS;
1711 : 0 : stypes >>= 1;
1712 : 0 : i++;
1713 : : }
1714 : 0 : nla_nest_end(msg, nl_ftypes);
1715 : : }
1716 : 0 : nla_nest_end(msg, nl_ifs);
1717 : :
1718 : 0 : return 0;
1719 : : }
1720 : :
1721 : : #define CMD(op, n) \
1722 : : do { \
1723 : : if (rdev->ops->op) { \
1724 : : i++; \
1725 : : if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
1726 : : goto nla_put_failure; \
1727 : : } \
1728 : : } while (0)
1729 : :
1730 : 0 : static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
1731 : : struct sk_buff *msg)
1732 : : {
1733 : 0 : int i = 0;
1734 : :
1735 : : /*
1736 : : * do *NOT* add anything into this function, new things need to be
1737 : : * advertised only to new versions of userspace that can deal with
1738 : : * the split (and they can't possibly care about new features...
1739 : : */
1740 [ # # # # ]: 0 : CMD(add_virtual_intf, NEW_INTERFACE);
1741 [ # # # # ]: 0 : CMD(change_virtual_intf, SET_INTERFACE);
1742 [ # # # # ]: 0 : CMD(add_key, NEW_KEY);
1743 [ # # # # ]: 0 : CMD(start_ap, START_AP);
1744 [ # # # # ]: 0 : CMD(add_station, NEW_STATION);
1745 [ # # # # ]: 0 : CMD(add_mpath, NEW_MPATH);
1746 [ # # # # ]: 0 : CMD(update_mesh_config, SET_MESH_CONFIG);
1747 [ # # # # ]: 0 : CMD(change_bss, SET_BSS);
1748 [ # # # # ]: 0 : CMD(auth, AUTHENTICATE);
1749 [ # # # # ]: 0 : CMD(assoc, ASSOCIATE);
1750 [ # # # # ]: 0 : CMD(deauth, DEAUTHENTICATE);
1751 [ # # # # ]: 0 : CMD(disassoc, DISASSOCIATE);
1752 [ # # # # ]: 0 : CMD(join_ibss, JOIN_IBSS);
1753 [ # # # # ]: 0 : CMD(join_mesh, JOIN_MESH);
1754 [ # # # # ]: 0 : CMD(set_pmksa, SET_PMKSA);
1755 [ # # # # ]: 0 : CMD(del_pmksa, DEL_PMKSA);
1756 [ # # # # ]: 0 : CMD(flush_pmksa, FLUSH_PMKSA);
1757 [ # # ]: 0 : if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
1758 [ # # # # ]: 0 : CMD(remain_on_channel, REMAIN_ON_CHANNEL);
1759 [ # # # # ]: 0 : CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
1760 [ # # # # ]: 0 : CMD(mgmt_tx, FRAME);
1761 [ # # # # ]: 0 : CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
1762 [ # # ]: 0 : if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
1763 : 0 : i++;
1764 [ # # ]: 0 : if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
1765 : 0 : goto nla_put_failure;
1766 : : }
1767 [ # # # # ]: 0 : if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
1768 [ # # ]: 0 : rdev->ops->join_mesh) {
1769 : 0 : i++;
1770 [ # # ]: 0 : if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
1771 : 0 : goto nla_put_failure;
1772 : : }
1773 [ # # # # ]: 0 : CMD(set_wds_peer, SET_WDS_PEER);
1774 [ # # ]: 0 : if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
1775 [ # # # # ]: 0 : CMD(tdls_mgmt, TDLS_MGMT);
1776 [ # # # # ]: 0 : CMD(tdls_oper, TDLS_OPER);
1777 : : }
1778 [ # # ]: 0 : if (rdev->wiphy.max_sched_scan_reqs)
1779 [ # # # # ]: 0 : CMD(sched_scan_start, START_SCHED_SCAN);
1780 [ # # # # ]: 0 : CMD(probe_client, PROBE_CLIENT);
1781 [ # # # # ]: 0 : CMD(set_noack_map, SET_NOACK_MAP);
1782 [ # # ]: 0 : if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
1783 : 0 : i++;
1784 [ # # ]: 0 : if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1785 : 0 : goto nla_put_failure;
1786 : : }
1787 [ # # # # ]: 0 : CMD(start_p2p_device, START_P2P_DEVICE);
1788 [ # # # # ]: 0 : CMD(set_mcast_rate, SET_MCAST_RATE);
1789 : : #ifdef CONFIG_NL80211_TESTMODE
1790 : : CMD(testmode_cmd, TESTMODE);
1791 : : #endif
1792 : :
1793 [ # # # # ]: 0 : if (rdev->ops->connect || rdev->ops->auth) {
1794 : 0 : i++;
1795 [ # # ]: 0 : if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
1796 : 0 : goto nla_put_failure;
1797 : : }
1798 : :
1799 [ # # # # ]: 0 : if (rdev->ops->disconnect || rdev->ops->deauth) {
1800 : 0 : i++;
1801 [ # # ]: 0 : if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
1802 : 0 : goto nla_put_failure;
1803 : : }
1804 : :
1805 : : return i;
1806 : : nla_put_failure:
1807 : : return -ENOBUFS;
1808 : : }
1809 : :
1810 : : static int
1811 : 0 : nl80211_send_pmsr_ftm_capa(const struct cfg80211_pmsr_capabilities *cap,
1812 : : struct sk_buff *msg)
1813 : : {
1814 : 0 : struct nlattr *ftm;
1815 : :
1816 [ # # ]: 0 : if (!cap->ftm.supported)
1817 : : return 0;
1818 : :
1819 : 0 : ftm = nla_nest_start_noflag(msg, NL80211_PMSR_TYPE_FTM);
1820 [ # # ]: 0 : if (!ftm)
1821 : : return -ENOBUFS;
1822 : :
1823 [ # # # # ]: 0 : if (cap->ftm.asap && nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_ASAP))
1824 : : return -ENOBUFS;
1825 [ # # # # ]: 0 : if (cap->ftm.non_asap &&
1826 : : nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP))
1827 : : return -ENOBUFS;
1828 [ # # # # ]: 0 : if (cap->ftm.request_lci &&
1829 : : nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI))
1830 : : return -ENOBUFS;
1831 [ # # # # ]: 0 : if (cap->ftm.request_civicloc &&
1832 : : nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC))
1833 : : return -ENOBUFS;
1834 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES,
1835 : : cap->ftm.preambles))
1836 : : return -ENOBUFS;
1837 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
1838 : : cap->ftm.bandwidths))
1839 : : return -ENOBUFS;
1840 [ # # # # ]: 0 : if (cap->ftm.max_bursts_exponent >= 0 &&
1841 : 0 : nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
1842 : : cap->ftm.max_bursts_exponent))
1843 : : return -ENOBUFS;
1844 [ # # # # ]: 0 : if (cap->ftm.max_ftms_per_burst &&
1845 : 0 : nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
1846 : : cap->ftm.max_ftms_per_burst))
1847 : : return -ENOBUFS;
1848 : :
1849 : 0 : nla_nest_end(msg, ftm);
1850 : 0 : return 0;
1851 : : }
1852 : :
1853 : : static int nl80211_send_pmsr_capa(struct cfg80211_registered_device *rdev,
1854 : : struct sk_buff *msg)
1855 : : {
1856 : : const struct cfg80211_pmsr_capabilities *cap = rdev->wiphy.pmsr_capa;
1857 : : struct nlattr *pmsr, *caps;
1858 : :
1859 : : if (!cap)
1860 : : return 0;
1861 : :
1862 : : /*
1863 : : * we don't need to clean up anything here since the caller
1864 : : * will genlmsg_cancel() if we fail
1865 : : */
1866 : :
1867 : : pmsr = nla_nest_start_noflag(msg, NL80211_ATTR_PEER_MEASUREMENTS);
1868 : : if (!pmsr)
1869 : : return -ENOBUFS;
1870 : :
1871 : : if (nla_put_u32(msg, NL80211_PMSR_ATTR_MAX_PEERS, cap->max_peers))
1872 : : return -ENOBUFS;
1873 : :
1874 : : if (cap->report_ap_tsf &&
1875 : : nla_put_flag(msg, NL80211_PMSR_ATTR_REPORT_AP_TSF))
1876 : : return -ENOBUFS;
1877 : :
1878 : : if (cap->randomize_mac_addr &&
1879 : : nla_put_flag(msg, NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR))
1880 : : return -ENOBUFS;
1881 : :
1882 : : caps = nla_nest_start_noflag(msg, NL80211_PMSR_ATTR_TYPE_CAPA);
1883 : : if (!caps)
1884 : : return -ENOBUFS;
1885 : :
1886 : : if (nl80211_send_pmsr_ftm_capa(cap, msg))
1887 : : return -ENOBUFS;
1888 : :
1889 : : nla_nest_end(msg, caps);
1890 : : nla_nest_end(msg, pmsr);
1891 : :
1892 : : return 0;
1893 : : }
1894 : :
1895 : : struct nl80211_dump_wiphy_state {
1896 : : s64 filter_wiphy;
1897 : : long start;
1898 : : long split_start, band_start, chan_start, capa_start;
1899 : : bool split;
1900 : : };
1901 : :
1902 : 0 : static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
1903 : : enum nl80211_commands cmd,
1904 : : struct sk_buff *msg, u32 portid, u32 seq,
1905 : : int flags, struct nl80211_dump_wiphy_state *state)
1906 : : {
1907 : 0 : void *hdr;
1908 : 0 : struct nlattr *nl_bands, *nl_band;
1909 : 0 : struct nlattr *nl_freqs, *nl_freq;
1910 : 0 : struct nlattr *nl_cmds;
1911 : 0 : enum nl80211_band band;
1912 : 0 : struct ieee80211_channel *chan;
1913 : 0 : int i;
1914 : 0 : const struct ieee80211_txrx_stypes *mgmt_stypes =
1915 : : rdev->wiphy.mgmt_stypes;
1916 : 0 : u32 features;
1917 : :
1918 : 0 : hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
1919 [ # # ]: 0 : if (!hdr)
1920 : : return -ENOBUFS;
1921 : :
1922 [ # # # # ]: 0 : if (WARN_ON(!state))
1923 : : return -EINVAL;
1924 : :
1925 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
1926 : 0 : nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
1927 [ # # ]: 0 : wiphy_name(&rdev->wiphy)) ||
1928 : 0 : nla_put_u32(msg, NL80211_ATTR_GENERATION,
1929 : : cfg80211_rdev_list_generation))
1930 : 0 : goto nla_put_failure;
1931 : :
1932 [ # # ]: 0 : if (cmd != NL80211_CMD_NEW_WIPHY)
1933 : 0 : goto finish;
1934 : :
1935 [ # # # # : 0 : switch (state->split_start) {
# # # # #
# # # # #
# # # ]
1936 : 0 : case 0:
1937 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
1938 [ # # ]: 0 : rdev->wiphy.retry_short) ||
1939 : : nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
1940 [ # # ]: 0 : rdev->wiphy.retry_long) ||
1941 : 0 : nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
1942 [ # # ]: 0 : rdev->wiphy.frag_threshold) ||
1943 : 0 : nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
1944 [ # # ]: 0 : rdev->wiphy.rts_threshold) ||
1945 : : nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
1946 [ # # ]: 0 : rdev->wiphy.coverage_class) ||
1947 : : nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
1948 [ # # ]: 0 : rdev->wiphy.max_scan_ssids) ||
1949 : : nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
1950 [ # # ]: 0 : rdev->wiphy.max_sched_scan_ssids) ||
1951 : : nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
1952 [ # # ]: 0 : rdev->wiphy.max_scan_ie_len) ||
1953 : : nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
1954 [ # # ]: 0 : rdev->wiphy.max_sched_scan_ie_len) ||
1955 : : nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
1956 [ # # ]: 0 : rdev->wiphy.max_match_sets) ||
1957 : 0 : nla_put_u32(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
1958 [ # # ]: 0 : rdev->wiphy.max_sched_scan_plans) ||
1959 : 0 : nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
1960 [ # # ]: 0 : rdev->wiphy.max_sched_scan_plan_interval) ||
1961 : 0 : nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
1962 : : rdev->wiphy.max_sched_scan_plan_iterations))
1963 : 0 : goto nla_put_failure;
1964 : :
1965 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
1966 : : nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
1967 : 0 : goto nla_put_failure;
1968 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
1969 : : nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
1970 : 0 : goto nla_put_failure;
1971 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
1972 : : nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
1973 : 0 : goto nla_put_failure;
1974 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
1975 : : nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
1976 : 0 : goto nla_put_failure;
1977 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
1978 : : nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
1979 : 0 : goto nla_put_failure;
1980 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
1981 : : nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
1982 : 0 : goto nla_put_failure;
1983 : 0 : state->split_start++;
1984 [ # # ]: 0 : if (state->split)
1985 : : break;
1986 : : /* fall through */
1987 : : case 1:
1988 [ # # ]: 0 : if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
1989 : 0 : sizeof(u32) * rdev->wiphy.n_cipher_suites,
1990 : 0 : rdev->wiphy.cipher_suites))
1991 : 0 : goto nla_put_failure;
1992 : :
1993 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
1994 : 0 : rdev->wiphy.max_num_pmkids))
1995 : 0 : goto nla_put_failure;
1996 : :
1997 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
1998 : : nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
1999 : 0 : goto nla_put_failure;
2000 : :
2001 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
2002 [ # # ]: 0 : rdev->wiphy.available_antennas_tx) ||
2003 : 0 : nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
2004 : : rdev->wiphy.available_antennas_rx))
2005 : 0 : goto nla_put_failure;
2006 : :
2007 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
2008 : 0 : nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
2009 : : rdev->wiphy.probe_resp_offload))
2010 : 0 : goto nla_put_failure;
2011 : :
2012 [ # # ]: 0 : if ((rdev->wiphy.available_antennas_tx ||
2013 [ # # ]: 0 : rdev->wiphy.available_antennas_rx) &&
2014 [ # # ]: 0 : rdev->ops->get_antenna) {
2015 : 0 : u32 tx_ant = 0, rx_ant = 0;
2016 : 0 : int res;
2017 : :
2018 : 0 : res = rdev_get_antenna(rdev, &tx_ant, &rx_ant);
2019 [ # # ]: 0 : if (!res) {
2020 [ # # ]: 0 : if (nla_put_u32(msg,
2021 : : NL80211_ATTR_WIPHY_ANTENNA_TX,
2022 [ # # ]: 0 : tx_ant) ||
2023 : 0 : nla_put_u32(msg,
2024 : : NL80211_ATTR_WIPHY_ANTENNA_RX,
2025 : : rx_ant))
2026 : 0 : goto nla_put_failure;
2027 : : }
2028 : : }
2029 : :
2030 : 0 : state->split_start++;
2031 [ # # ]: 0 : if (state->split)
2032 : : break;
2033 : : /* fall through */
2034 : : case 2:
2035 [ # # ]: 0 : if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
2036 : 0 : rdev->wiphy.interface_modes))
2037 : 0 : goto nla_put_failure;
2038 : 0 : state->split_start++;
2039 [ # # ]: 0 : if (state->split)
2040 : : break;
2041 : : /* fall through */
2042 : : case 3:
2043 : 0 : nl_bands = nla_nest_start_noflag(msg,
2044 : : NL80211_ATTR_WIPHY_BANDS);
2045 [ # # ]: 0 : if (!nl_bands)
2046 : 0 : goto nla_put_failure;
2047 : :
2048 : 0 : for (band = state->band_start;
2049 [ # # ]: 0 : band < NUM_NL80211_BANDS; band++) {
2050 : 0 : struct ieee80211_supported_band *sband;
2051 : :
2052 : 0 : sband = rdev->wiphy.bands[band];
2053 : :
2054 [ # # ]: 0 : if (!sband)
2055 : 0 : continue;
2056 : :
2057 : 0 : nl_band = nla_nest_start_noflag(msg, band);
2058 [ # # ]: 0 : if (!nl_band)
2059 : 0 : goto nla_put_failure;
2060 : :
2061 [ # # ]: 0 : switch (state->chan_start) {
2062 : 0 : case 0:
2063 [ # # ]: 0 : if (nl80211_send_band_rateinfo(msg, sband))
2064 : 0 : goto nla_put_failure;
2065 : 0 : state->chan_start++;
2066 [ # # ]: 0 : if (state->split)
2067 : : break;
2068 : : /* fall through */
2069 : : default:
2070 : : /* add frequencies */
2071 : 0 : nl_freqs = nla_nest_start_noflag(msg,
2072 : : NL80211_BAND_ATTR_FREQS);
2073 [ # # ]: 0 : if (!nl_freqs)
2074 : 0 : goto nla_put_failure;
2075 : :
2076 : 0 : for (i = state->chan_start - 1;
2077 [ # # ]: 0 : i < sband->n_channels;
2078 : 0 : i++) {
2079 : 0 : nl_freq = nla_nest_start_noflag(msg,
2080 : : i);
2081 [ # # ]: 0 : if (!nl_freq)
2082 : 0 : goto nla_put_failure;
2083 : :
2084 : 0 : chan = &sband->channels[i];
2085 : :
2086 [ # # ]: 0 : if (nl80211_msg_put_channel(
2087 : : msg, &rdev->wiphy, chan,
2088 : 0 : state->split))
2089 : 0 : goto nla_put_failure;
2090 : :
2091 [ # # ]: 0 : nla_nest_end(msg, nl_freq);
2092 [ # # ]: 0 : if (state->split)
2093 : : break;
2094 : : }
2095 [ # # ]: 0 : if (i < sband->n_channels)
2096 : 0 : state->chan_start = i + 2;
2097 : : else
2098 : 0 : state->chan_start = 0;
2099 : 0 : nla_nest_end(msg, nl_freqs);
2100 : : }
2101 : :
2102 [ # # ]: 0 : nla_nest_end(msg, nl_band);
2103 : :
2104 [ # # ]: 0 : if (state->split) {
2105 : : /* start again here */
2106 [ # # ]: 0 : if (state->chan_start)
2107 : 0 : band--;
2108 : : break;
2109 : : }
2110 : : }
2111 [ # # ]: 0 : nla_nest_end(msg, nl_bands);
2112 : :
2113 [ # # ]: 0 : if (band < NUM_NL80211_BANDS)
2114 : 0 : state->band_start = band + 1;
2115 : : else
2116 : 0 : state->band_start = 0;
2117 : :
2118 : : /* if bands & channels are done, continue outside */
2119 [ # # # # ]: 0 : if (state->band_start == 0 && state->chan_start == 0)
2120 : 0 : state->split_start++;
2121 [ # # ]: 0 : if (state->split)
2122 : : break;
2123 : : /* fall through */
2124 : : case 4:
2125 : 0 : nl_cmds = nla_nest_start_noflag(msg,
2126 : : NL80211_ATTR_SUPPORTED_COMMANDS);
2127 [ # # ]: 0 : if (!nl_cmds)
2128 : 0 : goto nla_put_failure;
2129 : :
2130 : 0 : i = nl80211_add_commands_unsplit(rdev, msg);
2131 [ # # ]: 0 : if (i < 0)
2132 : 0 : goto nla_put_failure;
2133 [ # # ]: 0 : if (state->split) {
2134 [ # # # # ]: 0 : CMD(crit_proto_start, CRIT_PROTOCOL_START);
2135 [ # # # # ]: 0 : CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
2136 [ # # ]: 0 : if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
2137 [ # # # # ]: 0 : CMD(channel_switch, CHANNEL_SWITCH);
2138 [ # # # # ]: 0 : CMD(set_qos_map, SET_QOS_MAP);
2139 [ # # ]: 0 : if (rdev->wiphy.features &
2140 : : NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
2141 [ # # # # ]: 0 : CMD(add_tx_ts, ADD_TX_TS);
2142 [ # # # # ]: 0 : CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
2143 [ # # # # ]: 0 : CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
2144 [ # # # # ]: 0 : CMD(update_ft_ies, UPDATE_FT_IES);
2145 : : }
2146 : : #undef CMD
2147 : :
2148 [ # # ]: 0 : nla_nest_end(msg, nl_cmds);
2149 : 0 : state->split_start++;
2150 [ # # ]: 0 : if (state->split)
2151 : : break;
2152 : : /* fall through */
2153 : : case 5:
2154 [ # # ]: 0 : if (rdev->ops->remain_on_channel &&
2155 [ # # # # ]: 0 : (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
2156 : 0 : nla_put_u32(msg,
2157 : : NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
2158 : 0 : rdev->wiphy.max_remain_on_channel_duration))
2159 : 0 : goto nla_put_failure;
2160 : :
2161 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
2162 : : nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
2163 : 0 : goto nla_put_failure;
2164 : :
2165 [ # # ]: 0 : if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
2166 : 0 : goto nla_put_failure;
2167 : 0 : state->split_start++;
2168 [ # # ]: 0 : if (state->split)
2169 : : break;
2170 : : /* fall through */
2171 : : case 6:
2172 : : #ifdef CONFIG_PM
2173 [ # # ]: 0 : if (nl80211_send_wowlan(msg, rdev, state->split))
2174 : 0 : goto nla_put_failure;
2175 : 0 : state->split_start++;
2176 [ # # ]: 0 : if (state->split)
2177 : : break;
2178 : : #else
2179 : : state->split_start++;
2180 : : #endif
2181 : : /* fall through */
2182 : : case 7:
2183 [ # # ]: 0 : if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
2184 : 0 : rdev->wiphy.software_iftypes))
2185 : 0 : goto nla_put_failure;
2186 : :
2187 [ # # ]: 0 : if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
2188 : 0 : state->split))
2189 : 0 : goto nla_put_failure;
2190 : :
2191 : 0 : state->split_start++;
2192 [ # # ]: 0 : if (state->split)
2193 : : break;
2194 : : /* fall through */
2195 : : case 8:
2196 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
2197 : 0 : nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
2198 : : rdev->wiphy.ap_sme_capa))
2199 : 0 : goto nla_put_failure;
2200 : :
2201 : 0 : features = rdev->wiphy.features;
2202 : : /*
2203 : : * We can only add the per-channel limit information if the
2204 : : * dump is split, otherwise it makes it too big. Therefore
2205 : : * only advertise it in that case.
2206 : : */
2207 [ # # ]: 0 : if (state->split)
2208 : 0 : features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
2209 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
2210 : 0 : goto nla_put_failure;
2211 : :
2212 [ # # # # ]: 0 : if (rdev->wiphy.ht_capa_mod_mask &&
2213 : 0 : nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
2214 : : sizeof(*rdev->wiphy.ht_capa_mod_mask),
2215 : : rdev->wiphy.ht_capa_mod_mask))
2216 : 0 : goto nla_put_failure;
2217 : :
2218 [ # # ]: 0 : if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
2219 [ # # # # ]: 0 : rdev->wiphy.max_acl_mac_addrs &&
2220 : 0 : nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
2221 : : rdev->wiphy.max_acl_mac_addrs))
2222 : 0 : goto nla_put_failure;
2223 : :
2224 : : /*
2225 : : * Any information below this point is only available to
2226 : : * applications that can deal with it being split. This
2227 : : * helps ensure that newly added capabilities don't break
2228 : : * older tools by overrunning their buffers.
2229 : : *
2230 : : * We still increment split_start so that in the split
2231 : : * case we'll continue with more data in the next round,
2232 : : * but break unconditionally so unsplit data stops here.
2233 : : */
2234 : 0 : state->split_start++;
2235 : 0 : break;
2236 : 0 : case 9:
2237 [ # # # # ]: 0 : if (rdev->wiphy.extended_capabilities &&
2238 : 0 : (nla_put(msg, NL80211_ATTR_EXT_CAPA,
2239 : 0 : rdev->wiphy.extended_capabilities_len,
2240 [ # # ]: 0 : rdev->wiphy.extended_capabilities) ||
2241 : 0 : nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
2242 : 0 : rdev->wiphy.extended_capabilities_len,
2243 : 0 : rdev->wiphy.extended_capabilities_mask)))
2244 : 0 : goto nla_put_failure;
2245 : :
2246 [ # # # # ]: 0 : if (rdev->wiphy.vht_capa_mod_mask &&
2247 : 0 : nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
2248 : : sizeof(*rdev->wiphy.vht_capa_mod_mask),
2249 : : rdev->wiphy.vht_capa_mod_mask))
2250 : 0 : goto nla_put_failure;
2251 : :
2252 [ # # ]: 0 : if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
2253 : 0 : rdev->wiphy.perm_addr))
2254 : 0 : goto nla_put_failure;
2255 : :
2256 [ # # # # ]: 0 : if (!is_zero_ether_addr(rdev->wiphy.addr_mask) &&
2257 : 0 : nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
2258 : 0 : rdev->wiphy.addr_mask))
2259 : 0 : goto nla_put_failure;
2260 : :
2261 [ # # ]: 0 : if (rdev->wiphy.n_addresses > 1) {
2262 : 0 : void *attr;
2263 : :
2264 : 0 : attr = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
2265 [ # # ]: 0 : if (!attr)
2266 : 0 : goto nla_put_failure;
2267 : :
2268 [ # # ]: 0 : for (i = 0; i < rdev->wiphy.n_addresses; i++)
2269 [ # # ]: 0 : if (nla_put(msg, i + 1, ETH_ALEN,
2270 : 0 : rdev->wiphy.addresses[i].addr))
2271 : 0 : goto nla_put_failure;
2272 : :
2273 : 0 : nla_nest_end(msg, attr);
2274 : : }
2275 : :
2276 : 0 : state->split_start++;
2277 : 0 : break;
2278 : 0 : case 10:
2279 [ # # ]: 0 : if (nl80211_send_coalesce(msg, rdev))
2280 : 0 : goto nla_put_failure;
2281 : :
2282 [ # # # # ]: 0 : if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
2283 [ # # ]: 0 : (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
2284 : : nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
2285 : 0 : goto nla_put_failure;
2286 : :
2287 [ # # # # ]: 0 : if (rdev->wiphy.max_ap_assoc_sta &&
2288 : 0 : nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
2289 : : rdev->wiphy.max_ap_assoc_sta))
2290 : 0 : goto nla_put_failure;
2291 : :
2292 : 0 : state->split_start++;
2293 : 0 : break;
2294 : 0 : case 11:
2295 [ # # ]: 0 : if (rdev->wiphy.n_vendor_commands) {
2296 : 0 : const struct nl80211_vendor_cmd_info *info;
2297 : 0 : struct nlattr *nested;
2298 : :
2299 : 0 : nested = nla_nest_start_noflag(msg,
2300 : : NL80211_ATTR_VENDOR_DATA);
2301 [ # # ]: 0 : if (!nested)
2302 : 0 : goto nla_put_failure;
2303 : :
2304 [ # # ]: 0 : for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
2305 : 0 : info = &rdev->wiphy.vendor_commands[i].info;
2306 [ # # ]: 0 : if (nla_put(msg, i + 1, sizeof(*info), info))
2307 : 0 : goto nla_put_failure;
2308 : : }
2309 : 0 : nla_nest_end(msg, nested);
2310 : : }
2311 : :
2312 [ # # ]: 0 : if (rdev->wiphy.n_vendor_events) {
2313 : 0 : const struct nl80211_vendor_cmd_info *info;
2314 : 0 : struct nlattr *nested;
2315 : :
2316 : 0 : nested = nla_nest_start_noflag(msg,
2317 : : NL80211_ATTR_VENDOR_EVENTS);
2318 [ # # ]: 0 : if (!nested)
2319 : 0 : goto nla_put_failure;
2320 : :
2321 [ # # ]: 0 : for (i = 0; i < rdev->wiphy.n_vendor_events; i++) {
2322 : 0 : info = &rdev->wiphy.vendor_events[i];
2323 [ # # ]: 0 : if (nla_put(msg, i + 1, sizeof(*info), info))
2324 : 0 : goto nla_put_failure;
2325 : : }
2326 : 0 : nla_nest_end(msg, nested);
2327 : : }
2328 : 0 : state->split_start++;
2329 : 0 : break;
2330 : 0 : case 12:
2331 [ # # # # ]: 0 : if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
2332 : : nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
2333 : 0 : rdev->wiphy.max_num_csa_counters))
2334 : 0 : goto nla_put_failure;
2335 : :
2336 [ # # # # ]: 0 : if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
2337 : : nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
2338 : 0 : goto nla_put_failure;
2339 : :
2340 [ # # # # ]: 0 : if (rdev->wiphy.max_sched_scan_reqs &&
2341 : 0 : nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_MAX_REQS,
2342 : : rdev->wiphy.max_sched_scan_reqs))
2343 : 0 : goto nla_put_failure;
2344 : :
2345 [ # # ]: 0 : if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
2346 : : sizeof(rdev->wiphy.ext_features),
2347 : 0 : rdev->wiphy.ext_features))
2348 : 0 : goto nla_put_failure;
2349 : :
2350 [ # # ]: 0 : if (rdev->wiphy.bss_select_support) {
2351 : 0 : struct nlattr *nested;
2352 : 0 : u32 bss_select_support = rdev->wiphy.bss_select_support;
2353 : :
2354 : 0 : nested = nla_nest_start_noflag(msg,
2355 : : NL80211_ATTR_BSS_SELECT);
2356 [ # # ]: 0 : if (!nested)
2357 : 0 : goto nla_put_failure;
2358 : :
2359 : : i = 0;
2360 [ # # ]: 0 : while (bss_select_support) {
2361 [ # # # # ]: 0 : if ((bss_select_support & 1) &&
2362 : : nla_put_flag(msg, i))
2363 : 0 : goto nla_put_failure;
2364 : 0 : i++;
2365 : 0 : bss_select_support >>= 1;
2366 : : }
2367 : 0 : nla_nest_end(msg, nested);
2368 : : }
2369 : :
2370 : 0 : state->split_start++;
2371 : 0 : break;
2372 : 0 : case 13:
2373 [ # # ]: 0 : if (rdev->wiphy.num_iftype_ext_capab &&
2374 [ # # ]: 0 : rdev->wiphy.iftype_ext_capab) {
2375 : 0 : struct nlattr *nested_ext_capab, *nested;
2376 : :
2377 : 0 : nested = nla_nest_start_noflag(msg,
2378 : : NL80211_ATTR_IFTYPE_EXT_CAPA);
2379 [ # # ]: 0 : if (!nested)
2380 : 0 : goto nla_put_failure;
2381 : :
2382 : 0 : for (i = state->capa_start;
2383 [ # # ]: 0 : i < rdev->wiphy.num_iftype_ext_capab; i++) {
2384 : 0 : const struct wiphy_iftype_ext_capab *capab;
2385 : :
2386 : 0 : capab = &rdev->wiphy.iftype_ext_capab[i];
2387 : :
2388 : 0 : nested_ext_capab = nla_nest_start_noflag(msg,
2389 : : i);
2390 [ # # # # ]: 0 : if (!nested_ext_capab ||
2391 : : nla_put_u32(msg, NL80211_ATTR_IFTYPE,
2392 [ # # ]: 0 : capab->iftype) ||
2393 : 0 : nla_put(msg, NL80211_ATTR_EXT_CAPA,
2394 : 0 : capab->extended_capabilities_len,
2395 [ # # ]: 0 : capab->extended_capabilities) ||
2396 : 0 : nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
2397 : 0 : capab->extended_capabilities_len,
2398 : 0 : capab->extended_capabilities_mask))
2399 : 0 : goto nla_put_failure;
2400 : :
2401 [ # # ]: 0 : nla_nest_end(msg, nested_ext_capab);
2402 [ # # ]: 0 : if (state->split)
2403 : : break;
2404 : : }
2405 [ # # ]: 0 : nla_nest_end(msg, nested);
2406 [ # # ]: 0 : if (i < rdev->wiphy.num_iftype_ext_capab) {
2407 : 0 : state->capa_start = i + 1;
2408 : 0 : break;
2409 : : }
2410 : : }
2411 : :
2412 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_BANDS,
2413 : 0 : rdev->wiphy.nan_supported_bands))
2414 : 0 : goto nla_put_failure;
2415 : :
2416 [ # # ]: 0 : if (wiphy_ext_feature_isset(&rdev->wiphy,
2417 : : NL80211_EXT_FEATURE_TXQS)) {
2418 : 0 : struct cfg80211_txq_stats txqstats = {};
2419 : 0 : int res;
2420 : :
2421 : 0 : res = rdev_get_txq_stats(rdev, NULL, &txqstats);
2422 [ # # # # ]: 0 : if (!res &&
2423 : 0 : !nl80211_put_txq_stats(msg, &txqstats,
2424 : : NL80211_ATTR_TXQ_STATS))
2425 : 0 : goto nla_put_failure;
2426 : :
2427 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_TXQ_LIMIT,
2428 : : rdev->wiphy.txq_limit))
2429 : 0 : goto nla_put_failure;
2430 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT,
2431 : : rdev->wiphy.txq_memory_limit))
2432 : 0 : goto nla_put_failure;
2433 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_TXQ_QUANTUM,
2434 : : rdev->wiphy.txq_quantum))
2435 : 0 : goto nla_put_failure;
2436 : : }
2437 : :
2438 : 0 : state->split_start++;
2439 : 0 : break;
2440 : 0 : case 14:
2441 [ # # ]: 0 : if (nl80211_send_pmsr_capa(rdev, msg))
2442 : 0 : goto nla_put_failure;
2443 : :
2444 : 0 : state->split_start++;
2445 : 0 : break;
2446 : 0 : case 15:
2447 [ # # # # ]: 0 : if (rdev->wiphy.akm_suites &&
2448 : 0 : nla_put(msg, NL80211_ATTR_AKM_SUITES,
2449 : 0 : sizeof(u32) * rdev->wiphy.n_akm_suites,
2450 : : rdev->wiphy.akm_suites))
2451 : 0 : goto nla_put_failure;
2452 : :
2453 : : /* done */
2454 : 0 : state->split_start = 0;
2455 : 0 : break;
2456 : : }
2457 : 0 : finish:
2458 : 0 : genlmsg_end(msg, hdr);
2459 : 0 : return 0;
2460 : :
2461 : 0 : nla_put_failure:
2462 : 0 : genlmsg_cancel(msg, hdr);
2463 : 0 : return -EMSGSIZE;
2464 : : }
2465 : :
2466 : : static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
2467 : : struct netlink_callback *cb,
2468 : : struct nl80211_dump_wiphy_state *state)
2469 : : {
2470 : : struct nlattr **tb = kcalloc(NUM_NL80211_ATTR, sizeof(*tb), GFP_KERNEL);
2471 : : int ret;
2472 : :
2473 : : if (!tb)
2474 : : return -ENOMEM;
2475 : :
2476 : : ret = nlmsg_parse_deprecated(cb->nlh,
2477 : : GENL_HDRLEN + nl80211_fam.hdrsize,
2478 : : tb, nl80211_fam.maxattr,
2479 : : nl80211_policy, NULL);
2480 : : /* ignore parse errors for backward compatibility */
2481 : : if (ret) {
2482 : : ret = 0;
2483 : : goto out;
2484 : : }
2485 : :
2486 : : state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
2487 : : if (tb[NL80211_ATTR_WIPHY])
2488 : : state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
2489 : : if (tb[NL80211_ATTR_WDEV])
2490 : : state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
2491 : : if (tb[NL80211_ATTR_IFINDEX]) {
2492 : : struct net_device *netdev;
2493 : : struct cfg80211_registered_device *rdev;
2494 : : int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2495 : :
2496 : : netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
2497 : : if (!netdev) {
2498 : : ret = -ENODEV;
2499 : : goto out;
2500 : : }
2501 : : if (netdev->ieee80211_ptr) {
2502 : : rdev = wiphy_to_rdev(
2503 : : netdev->ieee80211_ptr->wiphy);
2504 : : state->filter_wiphy = rdev->wiphy_idx;
2505 : : }
2506 : : }
2507 : :
2508 : : ret = 0;
2509 : : out:
2510 : : kfree(tb);
2511 : : return ret;
2512 : : }
2513 : :
2514 : 0 : static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
2515 : : {
2516 : 0 : int idx = 0, ret;
2517 : 0 : struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
2518 : 0 : struct cfg80211_registered_device *rdev;
2519 : :
2520 : 0 : rtnl_lock();
2521 [ # # ]: 0 : if (!state) {
2522 : 0 : state = kzalloc(sizeof(*state), GFP_KERNEL);
2523 [ # # ]: 0 : if (!state) {
2524 : 0 : rtnl_unlock();
2525 : 0 : return -ENOMEM;
2526 : : }
2527 : 0 : state->filter_wiphy = -1;
2528 : 0 : ret = nl80211_dump_wiphy_parse(skb, cb, state);
2529 [ # # ]: 0 : if (ret) {
2530 : 0 : kfree(state);
2531 : 0 : rtnl_unlock();
2532 : 0 : return ret;
2533 : : }
2534 : 0 : cb->args[0] = (long)state;
2535 : : }
2536 : :
2537 [ # # ]: 0 : list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2538 [ # # ]: 0 : if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
2539 : 0 : continue;
2540 [ # # ]: 0 : if (++idx <= state->start)
2541 : 0 : continue;
2542 [ # # ]: 0 : if (state->filter_wiphy != -1 &&
2543 [ # # ]: 0 : state->filter_wiphy != rdev->wiphy_idx)
2544 : 0 : continue;
2545 : : /* attempt to fit multiple wiphy data chunks into the skb */
2546 : 0 : do {
2547 : 0 : ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY,
2548 : : skb,
2549 : 0 : NETLINK_CB(cb->skb).portid,
2550 : 0 : cb->nlh->nlmsg_seq,
2551 : : NLM_F_MULTI, state);
2552 [ # # ]: 0 : if (ret < 0) {
2553 : : /*
2554 : : * If sending the wiphy data didn't fit (ENOBUFS
2555 : : * or EMSGSIZE returned), this SKB is still
2556 : : * empty (so it's not too big because another
2557 : : * wiphy dataset is already in the skb) and
2558 : : * we've not tried to adjust the dump allocation
2559 : : * yet ... then adjust the alloc size to be
2560 : : * bigger, and return 1 but with the empty skb.
2561 : : * This results in an empty message being RX'ed
2562 : : * in userspace, but that is ignored.
2563 : : *
2564 : : * We can then retry with the larger buffer.
2565 : : */
2566 [ # # ]: 0 : if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
2567 [ # # # # ]: 0 : !skb->len && !state->split &&
2568 [ # # ]: 0 : cb->min_dump_alloc < 4096) {
2569 : 0 : cb->min_dump_alloc = 4096;
2570 : 0 : state->split_start = 0;
2571 : 0 : rtnl_unlock();
2572 : 0 : return 1;
2573 : : }
2574 : : idx--;
2575 : : break;
2576 : : }
2577 [ # # ]: 0 : } while (state->split_start > 0);
2578 : : break;
2579 : : }
2580 : 0 : rtnl_unlock();
2581 : :
2582 : 0 : state->start = idx;
2583 : :
2584 : 0 : return skb->len;
2585 : : }
2586 : :
2587 : 0 : static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
2588 : : {
2589 : 0 : kfree((void *)cb->args[0]);
2590 : 0 : return 0;
2591 : : }
2592 : :
2593 : 0 : static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
2594 : : {
2595 : 0 : struct sk_buff *msg;
2596 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
2597 : 0 : struct nl80211_dump_wiphy_state state = {};
2598 : :
2599 : 0 : msg = nlmsg_new(4096, GFP_KERNEL);
2600 [ # # ]: 0 : if (!msg)
2601 : : return -ENOMEM;
2602 : :
2603 [ # # ]: 0 : if (nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY, msg,
2604 : : info->snd_portid, info->snd_seq, 0,
2605 : : &state) < 0) {
2606 : 0 : nlmsg_free(msg);
2607 : 0 : return -ENOBUFS;
2608 : : }
2609 : :
2610 : 0 : return genlmsg_reply(msg, info);
2611 : : }
2612 : :
2613 : : static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
2614 : : [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 },
2615 : : [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 },
2616 : : [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 },
2617 : : [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 },
2618 : : [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 },
2619 : : };
2620 : :
2621 : 0 : static int parse_txq_params(struct nlattr *tb[],
2622 : : struct ieee80211_txq_params *txq_params)
2623 : : {
2624 : 0 : u8 ac;
2625 : :
2626 [ # # # # ]: 0 : if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
2627 [ # # # # ]: 0 : !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
2628 [ # # ]: 0 : !tb[NL80211_TXQ_ATTR_AIFS])
2629 : : return -EINVAL;
2630 : :
2631 [ # # ]: 0 : ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
2632 [ # # ]: 0 : txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
2633 : 0 : txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
2634 : 0 : txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
2635 : 0 : txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
2636 : :
2637 [ # # ]: 0 : if (ac >= NL80211_NUM_ACS)
2638 : : return -EINVAL;
2639 : 0 : txq_params->ac = array_index_nospec(ac, NL80211_NUM_ACS);
2640 : 0 : return 0;
2641 : : }
2642 : :
2643 : 0 : static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
2644 : : {
2645 : : /*
2646 : : * You can only set the channel explicitly for WDS interfaces,
2647 : : * all others have their channel managed via their respective
2648 : : * "establish a connection" command (connect, join, ...)
2649 : : *
2650 : : * For AP/GO and mesh mode, the channel can be set with the
2651 : : * channel userspace API, but is only stored and passed to the
2652 : : * low-level driver when the AP starts or the mesh is joined.
2653 : : * This is for backward compatibility, userspace can also give
2654 : : * the channel in the start-ap or join-mesh commands instead.
2655 : : *
2656 : : * Monitors are special as they are normally slaved to
2657 : : * whatever else is going on, so they have their own special
2658 : : * operation to set the monitor channel if possible.
2659 : : */
2660 : 0 : return !wdev ||
2661 [ # # # # : 0 : wdev->iftype == NL80211_IFTYPE_AP ||
# # # # ]
2662 [ # # # # ]: 0 : wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
2663 [ # # # # ]: 0 : wdev->iftype == NL80211_IFTYPE_MONITOR ||
2664 : : wdev->iftype == NL80211_IFTYPE_P2P_GO;
2665 : : }
2666 : :
2667 : 0 : int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
2668 : : struct genl_info *info,
2669 : : struct cfg80211_chan_def *chandef)
2670 : : {
2671 : 0 : struct netlink_ext_ack *extack = info->extack;
2672 : 0 : struct nlattr **attrs = info->attrs;
2673 : 0 : u32 control_freq;
2674 : :
2675 [ # # ]: 0 : if (!attrs[NL80211_ATTR_WIPHY_FREQ])
2676 : : return -EINVAL;
2677 : :
2678 : 0 : control_freq = nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ]);
2679 : :
2680 : 0 : memset(chandef, 0, sizeof(*chandef));
2681 : :
2682 : 0 : chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
2683 : 0 : chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
2684 : 0 : chandef->center_freq1 = control_freq;
2685 : 0 : chandef->center_freq2 = 0;
2686 : :
2687 : : /* Primary channel not allowed */
2688 [ # # # # ]: 0 : if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) {
2689 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, attrs[NL80211_ATTR_WIPHY_FREQ],
2690 : : "Channel is disabled");
2691 : 0 : return -EINVAL;
2692 : : }
2693 : :
2694 [ # # ]: 0 : if (attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
2695 : 0 : enum nl80211_channel_type chantype;
2696 : :
2697 [ # # ]: 0 : chantype = nla_get_u32(attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
2698 : :
2699 [ # # ]: 0 : switch (chantype) {
2700 : 0 : case NL80211_CHAN_NO_HT:
2701 : : case NL80211_CHAN_HT20:
2702 : : case NL80211_CHAN_HT40PLUS:
2703 : : case NL80211_CHAN_HT40MINUS:
2704 : 0 : cfg80211_chandef_create(chandef, chandef->chan,
2705 : : chantype);
2706 : : /* user input for center_freq is incorrect */
2707 [ # # # # ]: 0 : if (attrs[NL80211_ATTR_CENTER_FREQ1] &&
2708 [ # # ]: 0 : chandef->center_freq1 != nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1])) {
2709 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack,
2710 : : attrs[NL80211_ATTR_CENTER_FREQ1],
2711 : : "bad center frequency 1");
2712 : 0 : return -EINVAL;
2713 : : }
2714 : : /* center_freq2 must be zero */
2715 [ # # # # ]: 0 : if (attrs[NL80211_ATTR_CENTER_FREQ2] &&
2716 : : nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2])) {
2717 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack,
2718 : : attrs[NL80211_ATTR_CENTER_FREQ2],
2719 : : "center frequency 2 can't be used");
2720 : 0 : return -EINVAL;
2721 : : }
2722 : : break;
2723 : 0 : default:
2724 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack,
2725 : : attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
2726 : : "invalid channel type");
2727 : 0 : return -EINVAL;
2728 : : }
2729 [ # # ]: 0 : } else if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
2730 [ # # ]: 0 : chandef->width =
2731 : : nla_get_u32(attrs[NL80211_ATTR_CHANNEL_WIDTH]);
2732 [ # # ]: 0 : if (attrs[NL80211_ATTR_CENTER_FREQ1])
2733 : 0 : chandef->center_freq1 =
2734 : : nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1]);
2735 [ # # ]: 0 : if (attrs[NL80211_ATTR_CENTER_FREQ2])
2736 : 0 : chandef->center_freq2 =
2737 : : nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2]);
2738 : : }
2739 : :
2740 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]) {
2741 [ # # ]: 0 : chandef->edmg.channels =
2742 : : nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]);
2743 : :
2744 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG])
2745 : 0 : chandef->edmg.bw_config =
2746 : 0 : nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG]);
2747 : : } else {
2748 : 0 : chandef->edmg.bw_config = 0;
2749 : 0 : chandef->edmg.channels = 0;
2750 : : }
2751 : :
2752 [ # # ]: 0 : if (!cfg80211_chandef_valid(chandef)) {
2753 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "invalid channel definition");
2754 : 0 : return -EINVAL;
2755 : : }
2756 : :
2757 [ # # ]: 0 : if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
2758 : : IEEE80211_CHAN_DISABLED)) {
2759 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "(extension) channel is disabled");
2760 : 0 : return -EINVAL;
2761 : : }
2762 : :
2763 [ # # ]: 0 : if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
2764 : 0 : chandef->width == NL80211_CHAN_WIDTH_10) &&
2765 [ # # ]: 0 : !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ)) {
2766 [ # # ]: 0 : NL_SET_ERR_MSG(extack, "5/10 MHz not supported");
2767 : 0 : return -EINVAL;
2768 : : }
2769 : :
2770 : : return 0;
2771 : : }
2772 : :
2773 : 0 : static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
2774 : : struct net_device *dev,
2775 : : struct genl_info *info)
2776 : : {
2777 : 0 : struct cfg80211_chan_def chandef;
2778 : 0 : int result;
2779 : 0 : enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
2780 : 0 : struct wireless_dev *wdev = NULL;
2781 : :
2782 [ # # ]: 0 : if (dev)
2783 : 0 : wdev = dev->ieee80211_ptr;
2784 [ # # # # ]: 0 : if (!nl80211_can_set_dev_channel(wdev))
2785 : : return -EOPNOTSUPP;
2786 [ # # ]: 0 : if (wdev)
2787 : 0 : iftype = wdev->iftype;
2788 : :
2789 : 0 : result = nl80211_parse_chandef(rdev, info, &chandef);
2790 [ # # ]: 0 : if (result)
2791 : : return result;
2792 : :
2793 [ # # # # ]: 0 : switch (iftype) {
2794 : 0 : case NL80211_IFTYPE_AP:
2795 : : case NL80211_IFTYPE_P2P_GO:
2796 [ # # ]: 0 : if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
2797 : : iftype)) {
2798 : : result = -EINVAL;
2799 : : break;
2800 : : }
2801 [ # # ]: 0 : if (wdev->beacon_interval) {
2802 [ # # # # ]: 0 : if (!dev || !rdev->ops->set_ap_chanwidth ||
2803 [ # # ]: 0 : !(rdev->wiphy.features &
2804 : : NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
2805 : : result = -EBUSY;
2806 : : break;
2807 : : }
2808 : :
2809 : : /* Only allow dynamic channel width changes */
2810 [ # # ]: 0 : if (chandef.chan != wdev->preset_chandef.chan) {
2811 : : result = -EBUSY;
2812 : : break;
2813 : : }
2814 : 0 : result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
2815 [ # # ]: 0 : if (result)
2816 : : break;
2817 : : }
2818 : 0 : wdev->preset_chandef = chandef;
2819 : 0 : result = 0;
2820 : 0 : break;
2821 : 0 : case NL80211_IFTYPE_MESH_POINT:
2822 : 0 : result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
2823 : 0 : break;
2824 : 0 : case NL80211_IFTYPE_MONITOR:
2825 : 0 : result = cfg80211_set_monitor_channel(rdev, &chandef);
2826 : 0 : break;
2827 : : default:
2828 : : result = -EINVAL;
2829 : : }
2830 : :
2831 : 0 : return result;
2832 : : }
2833 : :
2834 : 0 : static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
2835 : : {
2836 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
2837 : 0 : struct net_device *netdev = info->user_ptr[1];
2838 : :
2839 : 0 : return __nl80211_set_channel(rdev, netdev, info);
2840 : : }
2841 : :
2842 : 0 : static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
2843 : : {
2844 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
2845 : 0 : struct net_device *dev = info->user_ptr[1];
2846 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
2847 : 0 : const u8 *bssid;
2848 : :
2849 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
2850 : : return -EINVAL;
2851 : :
2852 [ # # ]: 0 : if (netif_running(dev))
2853 : : return -EBUSY;
2854 : :
2855 [ # # ]: 0 : if (!rdev->ops->set_wds_peer)
2856 : : return -EOPNOTSUPP;
2857 : :
2858 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_WDS)
2859 : : return -EOPNOTSUPP;
2860 : :
2861 : 0 : bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
2862 : 0 : return rdev_set_wds_peer(rdev, dev, bssid);
2863 : : }
2864 : :
2865 : 0 : static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
2866 : : {
2867 : 0 : struct cfg80211_registered_device *rdev;
2868 : 0 : struct net_device *netdev = NULL;
2869 : 0 : struct wireless_dev *wdev;
2870 : 0 : int result = 0, rem_txq_params = 0;
2871 : 0 : struct nlattr *nl_txq_params;
2872 : 0 : u32 changed;
2873 : 0 : u8 retry_short = 0, retry_long = 0;
2874 : 0 : u32 frag_threshold = 0, rts_threshold = 0;
2875 : 0 : u8 coverage_class = 0;
2876 : 0 : u32 txq_limit = 0, txq_memory_limit = 0, txq_quantum = 0;
2877 : :
2878 [ # # # # ]: 0 : ASSERT_RTNL();
2879 : :
2880 : : /*
2881 : : * Try to find the wiphy and netdev. Normally this
2882 : : * function shouldn't need the netdev, but this is
2883 : : * done for backward compatibility -- previously
2884 : : * setting the channel was done per wiphy, but now
2885 : : * it is per netdev. Previous userland like hostapd
2886 : : * also passed a netdev to set_wiphy, so that it is
2887 : : * possible to let that go to the right netdev!
2888 : : */
2889 : :
2890 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IFINDEX]) {
2891 : 0 : int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
2892 : :
2893 : 0 : netdev = __dev_get_by_index(genl_info_net(info), ifindex);
2894 [ # # # # ]: 0 : if (netdev && netdev->ieee80211_ptr)
2895 [ # # ]: 0 : rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
2896 : : else
2897 : : netdev = NULL;
2898 : : }
2899 : :
2900 : 0 : if (!netdev) {
2901 : 0 : rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
2902 : : info->attrs);
2903 [ # # ]: 0 : if (IS_ERR(rdev))
2904 : 0 : return PTR_ERR(rdev);
2905 : : wdev = NULL;
2906 : : netdev = NULL;
2907 : : result = 0;
2908 : : } else
2909 : 0 : wdev = netdev->ieee80211_ptr;
2910 : :
2911 : : /*
2912 : : * end workaround code, by now the rdev is available
2913 : : * and locked, and wdev may or may not be NULL.
2914 : : */
2915 : :
2916 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_NAME])
2917 : 0 : result = cfg80211_dev_rename(
2918 : : rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
2919 : :
2920 [ # # ]: 0 : if (result)
2921 : : return result;
2922 : :
2923 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
2924 : 0 : struct ieee80211_txq_params txq_params;
2925 : 0 : struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
2926 : :
2927 [ # # ]: 0 : if (!rdev->ops->set_txq_params)
2928 : 0 : return -EOPNOTSUPP;
2929 : :
2930 [ # # ]: 0 : if (!netdev)
2931 : : return -EINVAL;
2932 : :
2933 [ # # ]: 0 : if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2934 : : netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2935 : : return -EINVAL;
2936 : :
2937 [ # # ]: 0 : if (!netif_running(netdev))
2938 : : return -ENETDOWN;
2939 : :
2940 [ # # ]: 0 : nla_for_each_nested(nl_txq_params,
2941 : : info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
2942 : : rem_txq_params) {
2943 : 0 : result = nla_parse_nested_deprecated(tb,
2944 : : NL80211_TXQ_ATTR_MAX,
2945 : : nl_txq_params,
2946 : : txq_params_policy,
2947 : : info->extack);
2948 [ # # ]: 0 : if (result)
2949 : 0 : return result;
2950 : 0 : result = parse_txq_params(tb, &txq_params);
2951 [ # # ]: 0 : if (result)
2952 : 0 : return result;
2953 : :
2954 : 0 : result = rdev_set_txq_params(rdev, netdev,
2955 : : &txq_params);
2956 [ # # ]: 0 : if (result)
2957 : 0 : return result;
2958 : : }
2959 : : }
2960 : :
2961 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
2962 [ # # # # ]: 0 : result = __nl80211_set_channel(
2963 : : rdev,
2964 : : nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
2965 : : info);
2966 [ # # ]: 0 : if (result)
2967 : : return result;
2968 : : }
2969 : :
2970 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
2971 : 0 : struct wireless_dev *txp_wdev = wdev;
2972 : 0 : enum nl80211_tx_power_setting type;
2973 : 0 : int idx, mbm = 0;
2974 : :
2975 [ # # ]: 0 : if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
2976 : 0 : txp_wdev = NULL;
2977 : :
2978 [ # # ]: 0 : if (!rdev->ops->set_tx_power)
2979 : : return -EOPNOTSUPP;
2980 : :
2981 : 0 : idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
2982 [ # # ]: 0 : type = nla_get_u32(info->attrs[idx]);
2983 : :
2984 [ # # # # ]: 0 : if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
2985 : : (type != NL80211_TX_POWER_AUTOMATIC))
2986 : : return -EINVAL;
2987 : :
2988 [ # # ]: 0 : if (type != NL80211_TX_POWER_AUTOMATIC) {
2989 : 0 : idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
2990 : 0 : mbm = nla_get_u32(info->attrs[idx]);
2991 : : }
2992 : :
2993 : 0 : result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
2994 [ # # ]: 0 : if (result)
2995 : : return result;
2996 : : }
2997 : :
2998 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
2999 [ # # ]: 0 : info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
3000 : 0 : u32 tx_ant, rx_ant;
3001 : :
3002 [ # # ]: 0 : if ((!rdev->wiphy.available_antennas_tx &&
3003 [ # # ]: 0 : !rdev->wiphy.available_antennas_rx) ||
3004 [ # # ]: 0 : !rdev->ops->set_antenna)
3005 : : return -EOPNOTSUPP;
3006 : :
3007 [ # # ]: 0 : tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
3008 : 0 : rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
3009 : :
3010 : : /* reject antenna configurations which don't match the
3011 : : * available antenna masks, except for the "all" mask */
3012 [ # # # # : 0 : if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
# # ]
3013 [ # # ]: 0 : (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
3014 : : return -EINVAL;
3015 : :
3016 : 0 : tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
3017 : 0 : rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
3018 : :
3019 : 0 : result = rdev_set_antenna(rdev, tx_ant, rx_ant);
3020 [ # # ]: 0 : if (result)
3021 : : return result;
3022 : : }
3023 : :
3024 : 0 : changed = 0;
3025 : :
3026 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
3027 : 0 : retry_short = nla_get_u8(
3028 : : info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
3029 : :
3030 : 0 : changed |= WIPHY_PARAM_RETRY_SHORT;
3031 : : }
3032 : :
3033 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
3034 : 0 : retry_long = nla_get_u8(
3035 : : info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
3036 : :
3037 : 0 : changed |= WIPHY_PARAM_RETRY_LONG;
3038 : : }
3039 : :
3040 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
3041 [ # # ]: 0 : frag_threshold = nla_get_u32(
3042 : : info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
3043 [ # # ]: 0 : if (frag_threshold < 256)
3044 : : return -EINVAL;
3045 : :
3046 [ # # ]: 0 : if (frag_threshold != (u32) -1) {
3047 : : /*
3048 : : * Fragments (apart from the last one) are required to
3049 : : * have even length. Make the fragmentation code
3050 : : * simpler by stripping LSB should someone try to use
3051 : : * odd threshold value.
3052 : : */
3053 : 0 : frag_threshold &= ~0x1;
3054 : : }
3055 : 0 : changed |= WIPHY_PARAM_FRAG_THRESHOLD;
3056 : : }
3057 : :
3058 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
3059 : 0 : rts_threshold = nla_get_u32(
3060 : : info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
3061 : 0 : changed |= WIPHY_PARAM_RTS_THRESHOLD;
3062 : : }
3063 : :
3064 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
3065 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK])
3066 : : return -EINVAL;
3067 : :
3068 : 0 : coverage_class = nla_get_u8(
3069 : : info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
3070 : 0 : changed |= WIPHY_PARAM_COVERAGE_CLASS;
3071 : : }
3072 : :
3073 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
3074 [ # # ]: 0 : if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION))
3075 : : return -EOPNOTSUPP;
3076 : :
3077 : 0 : changed |= WIPHY_PARAM_DYN_ACK;
3078 : : }
3079 : :
3080 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_TXQ_LIMIT]) {
3081 [ # # ]: 0 : if (!wiphy_ext_feature_isset(&rdev->wiphy,
3082 : : NL80211_EXT_FEATURE_TXQS))
3083 : : return -EOPNOTSUPP;
3084 : 0 : txq_limit = nla_get_u32(
3085 : : info->attrs[NL80211_ATTR_TXQ_LIMIT]);
3086 : 0 : changed |= WIPHY_PARAM_TXQ_LIMIT;
3087 : : }
3088 : :
3089 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]) {
3090 [ # # ]: 0 : if (!wiphy_ext_feature_isset(&rdev->wiphy,
3091 : : NL80211_EXT_FEATURE_TXQS))
3092 : : return -EOPNOTSUPP;
3093 : 0 : txq_memory_limit = nla_get_u32(
3094 : : info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]);
3095 : 0 : changed |= WIPHY_PARAM_TXQ_MEMORY_LIMIT;
3096 : : }
3097 : :
3098 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_TXQ_QUANTUM]) {
3099 [ # # ]: 0 : if (!wiphy_ext_feature_isset(&rdev->wiphy,
3100 : : NL80211_EXT_FEATURE_TXQS))
3101 : : return -EOPNOTSUPP;
3102 : 0 : txq_quantum = nla_get_u32(
3103 : : info->attrs[NL80211_ATTR_TXQ_QUANTUM]);
3104 : 0 : changed |= WIPHY_PARAM_TXQ_QUANTUM;
3105 : : }
3106 : :
3107 [ # # ]: 0 : if (changed) {
3108 : 0 : u8 old_retry_short, old_retry_long;
3109 : 0 : u32 old_frag_threshold, old_rts_threshold;
3110 : 0 : u8 old_coverage_class;
3111 : 0 : u32 old_txq_limit, old_txq_memory_limit, old_txq_quantum;
3112 : :
3113 [ # # ]: 0 : if (!rdev->ops->set_wiphy_params)
3114 : : return -EOPNOTSUPP;
3115 : :
3116 : 0 : old_retry_short = rdev->wiphy.retry_short;
3117 : 0 : old_retry_long = rdev->wiphy.retry_long;
3118 : 0 : old_frag_threshold = rdev->wiphy.frag_threshold;
3119 : 0 : old_rts_threshold = rdev->wiphy.rts_threshold;
3120 : 0 : old_coverage_class = rdev->wiphy.coverage_class;
3121 : 0 : old_txq_limit = rdev->wiphy.txq_limit;
3122 : 0 : old_txq_memory_limit = rdev->wiphy.txq_memory_limit;
3123 : 0 : old_txq_quantum = rdev->wiphy.txq_quantum;
3124 : :
3125 [ # # ]: 0 : if (changed & WIPHY_PARAM_RETRY_SHORT)
3126 : 0 : rdev->wiphy.retry_short = retry_short;
3127 [ # # ]: 0 : if (changed & WIPHY_PARAM_RETRY_LONG)
3128 : 0 : rdev->wiphy.retry_long = retry_long;
3129 [ # # ]: 0 : if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
3130 : 0 : rdev->wiphy.frag_threshold = frag_threshold;
3131 [ # # ]: 0 : if (changed & WIPHY_PARAM_RTS_THRESHOLD)
3132 : 0 : rdev->wiphy.rts_threshold = rts_threshold;
3133 [ # # ]: 0 : if (changed & WIPHY_PARAM_COVERAGE_CLASS)
3134 : 0 : rdev->wiphy.coverage_class = coverage_class;
3135 [ # # ]: 0 : if (changed & WIPHY_PARAM_TXQ_LIMIT)
3136 : 0 : rdev->wiphy.txq_limit = txq_limit;
3137 [ # # ]: 0 : if (changed & WIPHY_PARAM_TXQ_MEMORY_LIMIT)
3138 : 0 : rdev->wiphy.txq_memory_limit = txq_memory_limit;
3139 [ # # ]: 0 : if (changed & WIPHY_PARAM_TXQ_QUANTUM)
3140 : 0 : rdev->wiphy.txq_quantum = txq_quantum;
3141 : :
3142 : 0 : result = rdev_set_wiphy_params(rdev, changed);
3143 [ # # ]: 0 : if (result) {
3144 : 0 : rdev->wiphy.retry_short = old_retry_short;
3145 : 0 : rdev->wiphy.retry_long = old_retry_long;
3146 : 0 : rdev->wiphy.frag_threshold = old_frag_threshold;
3147 : 0 : rdev->wiphy.rts_threshold = old_rts_threshold;
3148 : 0 : rdev->wiphy.coverage_class = old_coverage_class;
3149 : 0 : rdev->wiphy.txq_limit = old_txq_limit;
3150 : 0 : rdev->wiphy.txq_memory_limit = old_txq_memory_limit;
3151 : 0 : rdev->wiphy.txq_quantum = old_txq_quantum;
3152 : 0 : return result;
3153 : : }
3154 : : }
3155 : : return 0;
3156 : : }
3157 : :
3158 : 0 : static int nl80211_send_chandef(struct sk_buff *msg,
3159 : : const struct cfg80211_chan_def *chandef)
3160 : : {
3161 [ # # # # ]: 0 : if (WARN_ON(!cfg80211_chandef_valid(chandef)))
3162 : : return -EINVAL;
3163 : :
3164 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
3165 : 0 : chandef->chan->center_freq))
3166 : : return -ENOBUFS;
3167 [ # # ]: 0 : switch (chandef->width) {
3168 : 0 : case NL80211_CHAN_WIDTH_20_NOHT:
3169 : : case NL80211_CHAN_WIDTH_20:
3170 : : case NL80211_CHAN_WIDTH_40:
3171 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
3172 : 0 : cfg80211_get_chandef_type(chandef)))
3173 : : return -ENOBUFS;
3174 : : break;
3175 : : default:
3176 : : break;
3177 : : }
3178 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
3179 : : return -ENOBUFS;
3180 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
3181 : : return -ENOBUFS;
3182 [ # # # # ]: 0 : if (chandef->center_freq2 &&
3183 : : nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
3184 : 0 : return -ENOBUFS;
3185 : : return 0;
3186 : : }
3187 : :
3188 : 0 : static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
3189 : : struct cfg80211_registered_device *rdev,
3190 : : struct wireless_dev *wdev,
3191 : : enum nl80211_commands cmd)
3192 : : {
3193 : 0 : struct net_device *dev = wdev->netdev;
3194 : 0 : void *hdr;
3195 : :
3196 [ # # ]: 0 : WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
3197 : : cmd != NL80211_CMD_DEL_INTERFACE &&
3198 : : cmd != NL80211_CMD_SET_INTERFACE);
3199 : :
3200 : 0 : hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
3201 [ # # ]: 0 : if (!hdr)
3202 : : return -1;
3203 : :
3204 [ # # # # ]: 0 : if (dev &&
3205 [ # # ]: 0 : (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
3206 : 0 : nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
3207 : 0 : goto nla_put_failure;
3208 : :
3209 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
3210 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
3211 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
3212 [ # # ]: 0 : NL80211_ATTR_PAD) ||
3213 [ # # ]: 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
3214 : 0 : nla_put_u32(msg, NL80211_ATTR_GENERATION,
3215 : 0 : rdev->devlist_generation ^
3216 [ # # ]: 0 : (cfg80211_rdev_list_generation << 2)) ||
3217 : 0 : nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr))
3218 : 0 : goto nla_put_failure;
3219 : :
3220 [ # # ]: 0 : if (rdev->ops->get_channel) {
3221 : 0 : int ret;
3222 : 0 : struct cfg80211_chan_def chandef = {};
3223 : :
3224 : 0 : ret = rdev_get_channel(rdev, wdev, &chandef);
3225 [ # # ]: 0 : if (ret == 0) {
3226 [ # # ]: 0 : if (nl80211_send_chandef(msg, &chandef))
3227 : 0 : goto nla_put_failure;
3228 : : }
3229 : : }
3230 : :
3231 [ # # ]: 0 : if (rdev->ops->get_tx_power) {
3232 : 0 : int dbm, ret;
3233 : :
3234 : 0 : ret = rdev_get_tx_power(rdev, wdev, &dbm);
3235 [ # # # # ]: 0 : if (ret == 0 &&
3236 : 0 : nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
3237 : 0 : DBM_TO_MBM(dbm)))
3238 : 0 : goto nla_put_failure;
3239 : : }
3240 : :
3241 : 0 : wdev_lock(wdev);
3242 [ # # # ]: 0 : switch (wdev->iftype) {
3243 : 0 : case NL80211_IFTYPE_AP:
3244 [ # # # # ]: 0 : if (wdev->ssid_len &&
3245 : 0 : nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
3246 : 0 : goto nla_put_failure_locked;
3247 : : break;
3248 : 0 : case NL80211_IFTYPE_STATION:
3249 : : case NL80211_IFTYPE_P2P_CLIENT:
3250 : : case NL80211_IFTYPE_ADHOC: {
3251 : 0 : const u8 *ssid_ie;
3252 [ # # ]: 0 : if (!wdev->current_bss)
3253 : : break;
3254 : 0 : rcu_read_lock();
3255 : 0 : ssid_ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
3256 : : WLAN_EID_SSID);
3257 [ # # # # ]: 0 : if (ssid_ie &&
3258 : 0 : nla_put(msg, NL80211_ATTR_SSID, ssid_ie[1], ssid_ie + 2))
3259 : 0 : goto nla_put_failure_rcu_locked;
3260 : 0 : rcu_read_unlock();
3261 : : break;
3262 : : }
3263 : : default:
3264 : : /* nothing */
3265 : : break;
3266 : : }
3267 : 0 : wdev_unlock(wdev);
3268 : :
3269 [ # # ]: 0 : if (rdev->ops->get_txq_stats) {
3270 : 0 : struct cfg80211_txq_stats txqstats = {};
3271 : 0 : int ret = rdev_get_txq_stats(rdev, wdev, &txqstats);
3272 : :
3273 [ # # # # ]: 0 : if (ret == 0 &&
3274 : 0 : !nl80211_put_txq_stats(msg, &txqstats,
3275 : : NL80211_ATTR_TXQ_STATS))
3276 : 0 : goto nla_put_failure;
3277 : : }
3278 : :
3279 : 0 : genlmsg_end(msg, hdr);
3280 : 0 : return 0;
3281 : :
3282 : : nla_put_failure_rcu_locked:
3283 : 0 : rcu_read_unlock();
3284 : 0 : nla_put_failure_locked:
3285 : 0 : wdev_unlock(wdev);
3286 : 0 : nla_put_failure:
3287 : 0 : genlmsg_cancel(msg, hdr);
3288 : 0 : return -EMSGSIZE;
3289 : : }
3290 : :
3291 : 0 : static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
3292 : : {
3293 : 0 : int wp_idx = 0;
3294 : 0 : int if_idx = 0;
3295 : 0 : int wp_start = cb->args[0];
3296 : 0 : int if_start = cb->args[1];
3297 : 0 : int filter_wiphy = -1;
3298 : 0 : struct cfg80211_registered_device *rdev;
3299 : 0 : struct wireless_dev *wdev;
3300 : 0 : int ret;
3301 : :
3302 : 0 : rtnl_lock();
3303 [ # # ]: 0 : if (!cb->args[2]) {
3304 : 0 : struct nl80211_dump_wiphy_state state = {
3305 : : .filter_wiphy = -1,
3306 : : };
3307 : :
3308 : 0 : ret = nl80211_dump_wiphy_parse(skb, cb, &state);
3309 [ # # ]: 0 : if (ret)
3310 : 0 : goto out_unlock;
3311 : :
3312 : 0 : filter_wiphy = state.filter_wiphy;
3313 : :
3314 : : /*
3315 : : * if filtering, set cb->args[2] to +1 since 0 is the default
3316 : : * value needed to determine that parsing is necessary.
3317 : : */
3318 [ # # ]: 0 : if (filter_wiphy >= 0)
3319 : 0 : cb->args[2] = filter_wiphy + 1;
3320 : : else
3321 : 0 : cb->args[2] = -1;
3322 [ # # ]: 0 : } else if (cb->args[2] > 0) {
3323 : 0 : filter_wiphy = cb->args[2] - 1;
3324 : : }
3325 : :
3326 [ # # ]: 0 : list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
3327 [ # # ]: 0 : if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
3328 : 0 : continue;
3329 [ # # ]: 0 : if (wp_idx < wp_start) {
3330 : 0 : wp_idx++;
3331 : 0 : continue;
3332 : : }
3333 : :
3334 [ # # # # ]: 0 : if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx)
3335 : 0 : continue;
3336 : :
3337 : 0 : if_idx = 0;
3338 : :
3339 [ # # ]: 0 : list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
3340 [ # # ]: 0 : if (if_idx < if_start) {
3341 : 0 : if_idx++;
3342 : 0 : continue;
3343 : : }
3344 [ # # ]: 0 : if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
3345 : 0 : cb->nlh->nlmsg_seq, NLM_F_MULTI,
3346 : : rdev, wdev,
3347 : : NL80211_CMD_NEW_INTERFACE) < 0) {
3348 : 0 : goto out;
3349 : : }
3350 : 0 : if_idx++;
3351 : : }
3352 : :
3353 : 0 : wp_idx++;
3354 : : }
3355 : 0 : out:
3356 : 0 : cb->args[0] = wp_idx;
3357 : 0 : cb->args[1] = if_idx;
3358 : :
3359 : 0 : ret = skb->len;
3360 : 0 : out_unlock:
3361 : 0 : rtnl_unlock();
3362 : :
3363 : 0 : return ret;
3364 : : }
3365 : :
3366 : 0 : static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
3367 : : {
3368 : 0 : struct sk_buff *msg;
3369 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
3370 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
3371 : :
3372 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3373 [ # # ]: 0 : if (!msg)
3374 : : return -ENOMEM;
3375 : :
3376 [ # # ]: 0 : if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
3377 : : rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
3378 : 0 : nlmsg_free(msg);
3379 : 0 : return -ENOBUFS;
3380 : : }
3381 : :
3382 : 0 : return genlmsg_reply(msg, info);
3383 : : }
3384 : :
3385 : : static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
3386 : : [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
3387 : : [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
3388 : : [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
3389 : : [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
3390 : : [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
3391 : : [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
3392 : : };
3393 : :
3394 : 0 : static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
3395 : : {
3396 : 0 : struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
3397 : 0 : int flag;
3398 : :
3399 : 0 : *mntrflags = 0;
3400 : :
3401 [ # # ]: 0 : if (!nla)
3402 : : return -EINVAL;
3403 : :
3404 [ # # ]: 0 : if (nla_parse_nested_deprecated(flags, NL80211_MNTR_FLAG_MAX, nla, mntr_flags_policy, NULL))
3405 : : return -EINVAL;
3406 : :
3407 [ # # ]: 0 : for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
3408 [ # # ]: 0 : if (flags[flag])
3409 : 0 : *mntrflags |= (1<<flag);
3410 : :
3411 : 0 : *mntrflags |= MONITOR_FLAG_CHANGED;
3412 : :
3413 : 0 : return 0;
3414 : : }
3415 : :
3416 : : static int nl80211_parse_mon_options(struct cfg80211_registered_device *rdev,
3417 : : enum nl80211_iftype type,
3418 : : struct genl_info *info,
3419 : : struct vif_params *params)
3420 : : {
3421 : : bool change = false;
3422 : : int err;
3423 : :
3424 : : if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
3425 : : if (type != NL80211_IFTYPE_MONITOR)
3426 : : return -EINVAL;
3427 : :
3428 : : err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
3429 : : ¶ms->flags);
3430 : : if (err)
3431 : : return err;
3432 : :
3433 : : change = true;
3434 : : }
3435 : :
3436 : : if (params->flags & MONITOR_FLAG_ACTIVE &&
3437 : : !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
3438 : : return -EOPNOTSUPP;
3439 : :
3440 : : if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
3441 : : const u8 *mumimo_groups;
3442 : : u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
3443 : :
3444 : : if (type != NL80211_IFTYPE_MONITOR)
3445 : : return -EINVAL;
3446 : :
3447 : : if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
3448 : : return -EOPNOTSUPP;
3449 : :
3450 : : mumimo_groups =
3451 : : nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
3452 : :
3453 : : /* bits 0 and 63 are reserved and must be zero */
3454 : : if ((mumimo_groups[0] & BIT(0)) ||
3455 : : (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(7)))
3456 : : return -EINVAL;
3457 : :
3458 : : params->vht_mumimo_groups = mumimo_groups;
3459 : : change = true;
3460 : : }
3461 : :
3462 : : if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
3463 : : u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
3464 : :
3465 : : if (type != NL80211_IFTYPE_MONITOR)
3466 : : return -EINVAL;
3467 : :
3468 : : if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
3469 : : return -EOPNOTSUPP;
3470 : :
3471 : : params->vht_mumimo_follow_addr =
3472 : : nla_data(info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]);
3473 : : change = true;
3474 : : }
3475 : :
3476 : : return change ? 1 : 0;
3477 : : }
3478 : :
3479 : 0 : static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
3480 : : struct net_device *netdev, u8 use_4addr,
3481 : : enum nl80211_iftype iftype)
3482 : : {
3483 [ # # ]: 0 : if (!use_4addr) {
3484 [ # # # # ]: 0 : if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
3485 : : return -EBUSY;
3486 : 0 : return 0;
3487 : : }
3488 : :
3489 [ # # # # : 0 : switch (iftype) {
# # ]
3490 : 0 : case NL80211_IFTYPE_AP_VLAN:
3491 [ # # # # ]: 0 : if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
3492 : 0 : return 0;
3493 : : break;
3494 : 0 : case NL80211_IFTYPE_STATION:
3495 [ # # # # ]: 0 : if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
3496 : 0 : return 0;
3497 : : break;
3498 : : default:
3499 : : break;
3500 : : }
3501 : :
3502 : : return -EOPNOTSUPP;
3503 : : }
3504 : :
3505 : 0 : static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
3506 : : {
3507 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
3508 : 0 : struct vif_params params;
3509 : 0 : int err;
3510 : 0 : enum nl80211_iftype otype, ntype;
3511 : 0 : struct net_device *dev = info->user_ptr[1];
3512 : 0 : bool change = false;
3513 : :
3514 : 0 : memset(¶ms, 0, sizeof(params));
3515 : :
3516 : 0 : otype = ntype = dev->ieee80211_ptr->iftype;
3517 : :
3518 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IFTYPE]) {
3519 [ # # ]: 0 : ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
3520 [ # # ]: 0 : if (otype != ntype)
3521 : 0 : change = true;
3522 : : }
3523 : :
3524 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MESH_ID]) {
3525 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
3526 : :
3527 [ # # ]: 0 : if (ntype != NL80211_IFTYPE_MESH_POINT)
3528 : : return -EINVAL;
3529 [ # # ]: 0 : if (netif_running(dev))
3530 : : return -EBUSY;
3531 : :
3532 : 0 : wdev_lock(wdev);
3533 : 0 : BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
3534 : : IEEE80211_MAX_MESH_ID_LEN);
3535 : 0 : wdev->mesh_id_up_len =
3536 : 0 : nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
3537 : 0 : memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
3538 : : wdev->mesh_id_up_len);
3539 : 0 : wdev_unlock(wdev);
3540 : : }
3541 : :
3542 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_4ADDR]) {
3543 [ # # ]: 0 : params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
3544 : 0 : change = true;
3545 : 0 : err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
3546 [ # # ]: 0 : if (err)
3547 : : return err;
3548 : : } else {
3549 : 0 : params.use_4addr = -1;
3550 : : }
3551 : :
3552 : 0 : err = nl80211_parse_mon_options(rdev, ntype, info, ¶ms);
3553 [ # # ]: 0 : if (err < 0)
3554 : : return err;
3555 [ # # ]: 0 : if (err > 0)
3556 : : change = true;
3557 : :
3558 [ # # ]: 0 : if (change)
3559 : 0 : err = cfg80211_change_iface(rdev, dev, ntype, ¶ms);
3560 : : else
3561 : : err = 0;
3562 : :
3563 [ # # # # ]: 0 : if (!err && params.use_4addr != -1)
3564 : 0 : dev->ieee80211_ptr->use_4addr = params.use_4addr;
3565 : :
3566 [ # # ]: 0 : if (change && !err) {
3567 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
3568 : :
3569 : 0 : nl80211_notify_iface(rdev, wdev, NL80211_CMD_SET_INTERFACE);
3570 : : }
3571 : :
3572 : : return err;
3573 : : }
3574 : :
3575 : 0 : static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
3576 : : {
3577 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
3578 : 0 : struct vif_params params;
3579 : 0 : struct wireless_dev *wdev;
3580 : 0 : struct sk_buff *msg;
3581 : 0 : int err;
3582 : 0 : enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
3583 : :
3584 : : /* to avoid failing a new interface creation due to pending removal */
3585 : 0 : cfg80211_destroy_ifaces(rdev);
3586 : :
3587 : 0 : memset(¶ms, 0, sizeof(params));
3588 : :
3589 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_IFNAME])
3590 : : return -EINVAL;
3591 : :
3592 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IFTYPE])
3593 : 0 : type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
3594 : :
3595 [ # # ]: 0 : if (!rdev->ops->add_virtual_intf)
3596 : : return -EOPNOTSUPP;
3597 : :
3598 [ # # ]: 0 : if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
3599 [ # # ]: 0 : rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
3600 [ # # ]: 0 : info->attrs[NL80211_ATTR_MAC]) {
3601 : 0 : nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
3602 : : ETH_ALEN);
3603 [ # # # # ]: 0 : if (!is_valid_ether_addr(params.macaddr))
3604 : : return -EADDRNOTAVAIL;
3605 : : }
3606 : :
3607 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_4ADDR]) {
3608 [ # # ]: 0 : params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
3609 [ # # ]: 0 : err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
3610 : : if (err)
3611 : : return err;
3612 : : }
3613 : :
3614 [ # # ]: 0 : if (!cfg80211_iftype_allowed(&rdev->wiphy, type, params.use_4addr, 0))
3615 : : return -EOPNOTSUPP;
3616 : :
3617 : 0 : err = nl80211_parse_mon_options(rdev, type, info, ¶ms);
3618 [ # # ]: 0 : if (err < 0)
3619 : : return err;
3620 : :
3621 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3622 [ # # ]: 0 : if (!msg)
3623 : : return -ENOMEM;
3624 : :
3625 : 0 : wdev = rdev_add_virtual_intf(rdev,
3626 : 0 : nla_data(info->attrs[NL80211_ATTR_IFNAME]),
3627 : : NET_NAME_USER, type, ¶ms);
3628 [ # # # # ]: 0 : if (WARN_ON(!wdev)) {
3629 : 0 : nlmsg_free(msg);
3630 : 0 : return -EPROTO;
3631 [ # # ]: 0 : } else if (IS_ERR(wdev)) {
3632 : 0 : nlmsg_free(msg);
3633 : 0 : return PTR_ERR(wdev);
3634 : : }
3635 : :
3636 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
3637 : 0 : wdev->owner_nlportid = info->snd_portid;
3638 : :
3639 [ # # # ]: 0 : switch (type) {
3640 : 0 : case NL80211_IFTYPE_MESH_POINT:
3641 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MESH_ID])
3642 : : break;
3643 : 0 : wdev_lock(wdev);
3644 : 0 : BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
3645 : : IEEE80211_MAX_MESH_ID_LEN);
3646 : 0 : wdev->mesh_id_up_len =
3647 : 0 : nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
3648 : 0 : memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
3649 : : wdev->mesh_id_up_len);
3650 : 0 : wdev_unlock(wdev);
3651 : : break;
3652 : 0 : case NL80211_IFTYPE_NAN:
3653 : : case NL80211_IFTYPE_P2P_DEVICE:
3654 : : /*
3655 : : * P2P Device and NAN do not have a netdev, so don't go
3656 : : * through the netdev notifier and must be added here
3657 : : */
3658 : 0 : cfg80211_init_wdev(rdev, wdev);
3659 : 0 : break;
3660 : : default:
3661 : : break;
3662 : : }
3663 : :
3664 [ # # ]: 0 : if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
3665 : : rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
3666 : 0 : nlmsg_free(msg);
3667 : 0 : return -ENOBUFS;
3668 : : }
3669 : :
3670 : 0 : return genlmsg_reply(msg, info);
3671 : : }
3672 : :
3673 : 0 : static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
3674 : : {
3675 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
3676 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
3677 : :
3678 [ # # ]: 0 : if (!rdev->ops->del_virtual_intf)
3679 : : return -EOPNOTSUPP;
3680 : :
3681 : : /*
3682 : : * If we remove a wireless device without a netdev then clear
3683 : : * user_ptr[1] so that nl80211_post_doit won't dereference it
3684 : : * to check if it needs to do dev_put(). Otherwise it crashes
3685 : : * since the wdev has been freed, unlike with a netdev where
3686 : : * we need the dev_put() for the netdev to really be freed.
3687 : : */
3688 [ # # ]: 0 : if (!wdev->netdev)
3689 : 0 : info->user_ptr[1] = NULL;
3690 : :
3691 : 0 : return rdev_del_virtual_intf(rdev, wdev);
3692 : : }
3693 : :
3694 : 0 : static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
3695 : : {
3696 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
3697 : 0 : struct net_device *dev = info->user_ptr[1];
3698 : 0 : u16 noack_map;
3699 : :
3700 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_NOACK_MAP])
3701 : : return -EINVAL;
3702 : :
3703 [ # # ]: 0 : if (!rdev->ops->set_noack_map)
3704 : : return -EOPNOTSUPP;
3705 : :
3706 : 0 : noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
3707 : :
3708 : 0 : return rdev_set_noack_map(rdev, dev, noack_map);
3709 : : }
3710 : :
3711 : : struct get_key_cookie {
3712 : : struct sk_buff *msg;
3713 : : int error;
3714 : : int idx;
3715 : : };
3716 : :
3717 : 0 : static void get_key_callback(void *c, struct key_params *params)
3718 : : {
3719 : 0 : struct nlattr *key;
3720 : 0 : struct get_key_cookie *cookie = c;
3721 : :
3722 [ # # # # ]: 0 : if ((params->key &&
3723 : 0 : nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
3724 : 0 : params->key_len, params->key)) ||
3725 [ # # # # ]: 0 : (params->seq &&
3726 : 0 : nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
3727 : 0 : params->seq_len, params->seq)) ||
3728 [ # # # # ]: 0 : (params->cipher &&
3729 : 0 : nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
3730 : : params->cipher)))
3731 : 0 : goto nla_put_failure;
3732 : :
3733 : 0 : key = nla_nest_start_noflag(cookie->msg, NL80211_ATTR_KEY);
3734 [ # # ]: 0 : if (!key)
3735 : 0 : goto nla_put_failure;
3736 : :
3737 [ # # # # ]: 0 : if ((params->key &&
3738 : 0 : nla_put(cookie->msg, NL80211_KEY_DATA,
3739 : 0 : params->key_len, params->key)) ||
3740 [ # # # # ]: 0 : (params->seq &&
3741 : 0 : nla_put(cookie->msg, NL80211_KEY_SEQ,
3742 : 0 : params->seq_len, params->seq)) ||
3743 [ # # # # ]: 0 : (params->cipher &&
3744 : 0 : nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
3745 : : params->cipher)))
3746 : 0 : goto nla_put_failure;
3747 : :
3748 [ # # ]: 0 : if (nla_put_u8(cookie->msg, NL80211_KEY_IDX, cookie->idx))
3749 : 0 : goto nla_put_failure;
3750 : :
3751 : 0 : nla_nest_end(cookie->msg, key);
3752 : :
3753 : : return;
3754 : 0 : nla_put_failure:
3755 : 0 : cookie->error = 1;
3756 : : }
3757 : :
3758 : 0 : static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
3759 : : {
3760 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
3761 : 0 : int err;
3762 : 0 : struct net_device *dev = info->user_ptr[1];
3763 : 0 : u8 key_idx = 0;
3764 : 0 : const u8 *mac_addr = NULL;
3765 : 0 : bool pairwise;
3766 : 0 : struct get_key_cookie cookie = {
3767 : : .error = 0,
3768 : : };
3769 : 0 : void *hdr;
3770 : 0 : struct sk_buff *msg;
3771 : :
3772 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_KEY_IDX])
3773 : 0 : key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
3774 : :
3775 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MAC])
3776 : 0 : mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3777 : :
3778 : 0 : pairwise = !!mac_addr;
3779 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
3780 [ # # ]: 0 : u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
3781 : :
3782 [ # # ]: 0 : if (kt != NL80211_KEYTYPE_GROUP &&
3783 : : kt != NL80211_KEYTYPE_PAIRWISE)
3784 : : return -EINVAL;
3785 : 0 : pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
3786 : : }
3787 : :
3788 [ # # ]: 0 : if (!rdev->ops->get_key)
3789 : : return -EOPNOTSUPP;
3790 : :
3791 [ # # # # ]: 0 : if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3792 : : return -ENOENT;
3793 : :
3794 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3795 [ # # ]: 0 : if (!msg)
3796 : : return -ENOMEM;
3797 : :
3798 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
3799 : : NL80211_CMD_NEW_KEY);
3800 [ # # ]: 0 : if (!hdr)
3801 : 0 : goto nla_put_failure;
3802 : :
3803 : 0 : cookie.msg = msg;
3804 : 0 : cookie.idx = key_idx;
3805 : :
3806 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
3807 : : nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
3808 : 0 : goto nla_put_failure;
3809 [ # # # # ]: 0 : if (mac_addr &&
3810 : 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
3811 : 0 : goto nla_put_failure;
3812 : :
3813 : 0 : err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
3814 : : get_key_callback);
3815 : :
3816 [ # # ]: 0 : if (err)
3817 : 0 : goto free_msg;
3818 : :
3819 [ # # ]: 0 : if (cookie.error)
3820 : 0 : goto nla_put_failure;
3821 : :
3822 : 0 : genlmsg_end(msg, hdr);
3823 : 0 : return genlmsg_reply(msg, info);
3824 : :
3825 : : nla_put_failure:
3826 : : err = -ENOBUFS;
3827 : 0 : free_msg:
3828 : 0 : nlmsg_free(msg);
3829 : 0 : return err;
3830 : : }
3831 : :
3832 : 0 : static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
3833 : : {
3834 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
3835 : 0 : struct key_parse key;
3836 : 0 : int err;
3837 : 0 : struct net_device *dev = info->user_ptr[1];
3838 : :
3839 : 0 : err = nl80211_parse_key(info, &key);
3840 [ # # ]: 0 : if (err)
3841 : : return err;
3842 : :
3843 [ # # ]: 0 : if (key.idx < 0)
3844 : : return -EINVAL;
3845 : :
3846 : : /* Only support setting default key and
3847 : : * Extended Key ID action NL80211_KEY_SET_TX.
3848 : : */
3849 [ # # # # ]: 0 : if (!key.def && !key.defmgmt &&
3850 [ # # ]: 0 : !(key.p.mode == NL80211_KEY_SET_TX))
3851 : : return -EINVAL;
3852 : :
3853 : 0 : wdev_lock(dev->ieee80211_ptr);
3854 : :
3855 [ # # ]: 0 : if (key.def) {
3856 [ # # ]: 0 : if (!rdev->ops->set_default_key) {
3857 : 0 : err = -EOPNOTSUPP;
3858 : 0 : goto out;
3859 : : }
3860 : :
3861 [ # # # ]: 0 : err = nl80211_key_allowed(dev->ieee80211_ptr);
3862 : 0 : if (err)
3863 : 0 : goto out;
3864 : :
3865 : 0 : err = rdev_set_default_key(rdev, dev, key.idx,
3866 : 0 : key.def_uni, key.def_multi);
3867 : :
3868 [ # # ]: 0 : if (err)
3869 : 0 : goto out;
3870 : :
3871 : : #ifdef CONFIG_CFG80211_WEXT
3872 : 0 : dev->ieee80211_ptr->wext.default_key = key.idx;
3873 : : #endif
3874 [ # # ]: 0 : } else if (key.defmgmt) {
3875 [ # # # # ]: 0 : if (key.def_uni || !key.def_multi) {
3876 : 0 : err = -EINVAL;
3877 : 0 : goto out;
3878 : : }
3879 : :
3880 [ # # ]: 0 : if (!rdev->ops->set_default_mgmt_key) {
3881 : 0 : err = -EOPNOTSUPP;
3882 : 0 : goto out;
3883 : : }
3884 : :
3885 [ # # # ]: 0 : err = nl80211_key_allowed(dev->ieee80211_ptr);
3886 : 0 : if (err)
3887 : 0 : goto out;
3888 : :
3889 : 0 : err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
3890 [ # # ]: 0 : if (err)
3891 : 0 : goto out;
3892 : :
3893 : : #ifdef CONFIG_CFG80211_WEXT
3894 : 0 : dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
3895 : : #endif
3896 [ # # # # ]: 0 : } else if (key.p.mode == NL80211_KEY_SET_TX &&
3897 : : wiphy_ext_feature_isset(&rdev->wiphy,
3898 : 0 : NL80211_EXT_FEATURE_EXT_KEY_ID)) {
3899 : 0 : u8 *mac_addr = NULL;
3900 : :
3901 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MAC])
3902 [ # # ]: 0 : mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3903 : :
3904 [ # # # # : 0 : if (!mac_addr || key.idx < 0 || key.idx > 1) {
# # ]
3905 : 0 : err = -EINVAL;
3906 : 0 : goto out;
3907 : : }
3908 : :
3909 : 0 : err = rdev_add_key(rdev, dev, key.idx,
3910 : : NL80211_KEYTYPE_PAIRWISE,
3911 : : mac_addr, &key.p);
3912 : : } else {
3913 : : err = -EINVAL;
3914 : : }
3915 : 0 : out:
3916 : 0 : wdev_unlock(dev->ieee80211_ptr);
3917 : :
3918 : 0 : return err;
3919 : : }
3920 : :
3921 : 0 : static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
3922 : : {
3923 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
3924 : 0 : int err;
3925 : 0 : struct net_device *dev = info->user_ptr[1];
3926 : 0 : struct key_parse key;
3927 : 0 : const u8 *mac_addr = NULL;
3928 : :
3929 : 0 : err = nl80211_parse_key(info, &key);
3930 [ # # ]: 0 : if (err)
3931 : : return err;
3932 : :
3933 [ # # ]: 0 : if (!key.p.key)
3934 : : return -EINVAL;
3935 : :
3936 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MAC])
3937 : 0 : mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3938 : :
3939 [ # # ]: 0 : if (key.type == -1) {
3940 [ # # ]: 0 : if (mac_addr)
3941 : 0 : key.type = NL80211_KEYTYPE_PAIRWISE;
3942 : : else
3943 : 0 : key.type = NL80211_KEYTYPE_GROUP;
3944 : : }
3945 : :
3946 : : /* for now */
3947 [ # # ]: 0 : if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3948 : : key.type != NL80211_KEYTYPE_GROUP)
3949 : : return -EINVAL;
3950 : :
3951 [ # # ]: 0 : if (key.type == NL80211_KEYTYPE_GROUP &&
3952 [ # # ]: 0 : info->attrs[NL80211_ATTR_VLAN_ID])
3953 : 0 : key.p.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);
3954 : :
3955 [ # # ]: 0 : if (!rdev->ops->add_key)
3956 : : return -EOPNOTSUPP;
3957 : :
3958 [ # # ]: 0 : if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
3959 : : key.type == NL80211_KEYTYPE_PAIRWISE,
3960 : : mac_addr))
3961 : : return -EINVAL;
3962 : :
3963 : 0 : wdev_lock(dev->ieee80211_ptr);
3964 [ # # # ]: 0 : err = nl80211_key_allowed(dev->ieee80211_ptr);
3965 : 0 : if (!err)
3966 : 0 : err = rdev_add_key(rdev, dev, key.idx,
3967 : 0 : key.type == NL80211_KEYTYPE_PAIRWISE,
3968 : : mac_addr, &key.p);
3969 : 0 : wdev_unlock(dev->ieee80211_ptr);
3970 : :
3971 : 0 : return err;
3972 : : }
3973 : :
3974 : 0 : static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
3975 : : {
3976 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
3977 : 0 : int err;
3978 : 0 : struct net_device *dev = info->user_ptr[1];
3979 : 0 : u8 *mac_addr = NULL;
3980 : 0 : struct key_parse key;
3981 : :
3982 : 0 : err = nl80211_parse_key(info, &key);
3983 [ # # ]: 0 : if (err)
3984 : : return err;
3985 : :
3986 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MAC])
3987 : 0 : mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3988 : :
3989 [ # # ]: 0 : if (key.type == -1) {
3990 [ # # ]: 0 : if (mac_addr)
3991 : 0 : key.type = NL80211_KEYTYPE_PAIRWISE;
3992 : : else
3993 : 0 : key.type = NL80211_KEYTYPE_GROUP;
3994 : : }
3995 : :
3996 : : /* for now */
3997 [ # # ]: 0 : if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3998 : : key.type != NL80211_KEYTYPE_GROUP)
3999 : : return -EINVAL;
4000 : :
4001 [ # # ]: 0 : if (!rdev->ops->del_key)
4002 : : return -EOPNOTSUPP;
4003 : :
4004 : 0 : wdev_lock(dev->ieee80211_ptr);
4005 [ # # # ]: 0 : err = nl80211_key_allowed(dev->ieee80211_ptr);
4006 : :
4007 [ # # # # ]: 0 : if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
4008 [ # # ]: 0 : !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
4009 : : err = -ENOENT;
4010 : :
4011 [ # # ]: 0 : if (!err)
4012 : 0 : err = rdev_del_key(rdev, dev, key.idx,
4013 : : key.type == NL80211_KEYTYPE_PAIRWISE,
4014 : : mac_addr);
4015 : :
4016 : : #ifdef CONFIG_CFG80211_WEXT
4017 [ # # ]: 0 : if (!err) {
4018 [ # # ]: 0 : if (key.idx == dev->ieee80211_ptr->wext.default_key)
4019 : 0 : dev->ieee80211_ptr->wext.default_key = -1;
4020 [ # # ]: 0 : else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
4021 : 0 : dev->ieee80211_ptr->wext.default_mgmt_key = -1;
4022 : : }
4023 : : #endif
4024 : 0 : wdev_unlock(dev->ieee80211_ptr);
4025 : :
4026 : 0 : return err;
4027 : : }
4028 : :
4029 : : /* This function returns an error or the number of nested attributes */
4030 : 0 : static int validate_acl_mac_addrs(struct nlattr *nl_attr)
4031 : : {
4032 : 0 : struct nlattr *attr;
4033 : 0 : int n_entries = 0, tmp;
4034 : :
4035 [ # # ]: 0 : nla_for_each_nested(attr, nl_attr, tmp) {
4036 [ # # ]: 0 : if (nla_len(attr) != ETH_ALEN)
4037 : : return -EINVAL;
4038 : :
4039 : 0 : n_entries++;
4040 : : }
4041 : :
4042 : : return n_entries;
4043 : : }
4044 : :
4045 : : /*
4046 : : * This function parses ACL information and allocates memory for ACL data.
4047 : : * On successful return, the calling function is responsible to free the
4048 : : * ACL buffer returned by this function.
4049 : : */
4050 : : static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
4051 : : struct genl_info *info)
4052 : : {
4053 : : enum nl80211_acl_policy acl_policy;
4054 : : struct nlattr *attr;
4055 : : struct cfg80211_acl_data *acl;
4056 : : int i = 0, n_entries, tmp;
4057 : :
4058 : : if (!wiphy->max_acl_mac_addrs)
4059 : : return ERR_PTR(-EOPNOTSUPP);
4060 : :
4061 : : if (!info->attrs[NL80211_ATTR_ACL_POLICY])
4062 : : return ERR_PTR(-EINVAL);
4063 : :
4064 : : acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
4065 : : if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
4066 : : acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
4067 : : return ERR_PTR(-EINVAL);
4068 : :
4069 : : if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
4070 : : return ERR_PTR(-EINVAL);
4071 : :
4072 : : n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
4073 : : if (n_entries < 0)
4074 : : return ERR_PTR(n_entries);
4075 : :
4076 : : if (n_entries > wiphy->max_acl_mac_addrs)
4077 : : return ERR_PTR(-ENOTSUPP);
4078 : :
4079 : : acl = kzalloc(struct_size(acl, mac_addrs, n_entries), GFP_KERNEL);
4080 : : if (!acl)
4081 : : return ERR_PTR(-ENOMEM);
4082 : :
4083 : : nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
4084 : : memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
4085 : : i++;
4086 : : }
4087 : :
4088 : : acl->n_acl_entries = n_entries;
4089 : : acl->acl_policy = acl_policy;
4090 : :
4091 : : return acl;
4092 : : }
4093 : :
4094 : 0 : static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
4095 : : {
4096 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
4097 : 0 : struct net_device *dev = info->user_ptr[1];
4098 : 0 : struct cfg80211_acl_data *acl;
4099 : 0 : int err;
4100 : :
4101 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4102 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4103 : : return -EOPNOTSUPP;
4104 : :
4105 [ # # ]: 0 : if (!dev->ieee80211_ptr->beacon_interval)
4106 : : return -EINVAL;
4107 : :
4108 : 0 : acl = parse_acl_data(&rdev->wiphy, info);
4109 [ # # ]: 0 : if (IS_ERR(acl))
4110 : 0 : return PTR_ERR(acl);
4111 : :
4112 : 0 : err = rdev_set_mac_acl(rdev, dev, acl);
4113 : :
4114 : 0 : kfree(acl);
4115 : :
4116 : 0 : return err;
4117 : : }
4118 : :
4119 : 0 : static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
4120 : : u8 *rates, u8 rates_len)
4121 : : {
4122 : 0 : u8 i;
4123 : 0 : u32 mask = 0;
4124 : :
4125 [ # # ]: 0 : for (i = 0; i < rates_len; i++) {
4126 : 0 : int rate = (rates[i] & 0x7f) * 5;
4127 : 0 : int ridx;
4128 : :
4129 [ # # ]: 0 : for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
4130 : 0 : struct ieee80211_rate *srate =
4131 : 0 : &sband->bitrates[ridx];
4132 [ # # ]: 0 : if (rate == srate->bitrate) {
4133 : 0 : mask |= 1 << ridx;
4134 : 0 : break;
4135 : : }
4136 : : }
4137 [ # # ]: 0 : if (ridx == sband->n_bitrates)
4138 : : return 0; /* rate not found */
4139 : : }
4140 : :
4141 : : return mask;
4142 : : }
4143 : :
4144 : 0 : static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
4145 : : u8 *rates, u8 rates_len,
4146 : : u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
4147 : : {
4148 : 0 : u8 i;
4149 : :
4150 : 0 : memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
4151 : :
4152 [ # # ]: 0 : for (i = 0; i < rates_len; i++) {
4153 : 0 : int ridx, rbit;
4154 : :
4155 : 0 : ridx = rates[i] / 8;
4156 : 0 : rbit = BIT(rates[i] % 8);
4157 : :
4158 : : /* check validity */
4159 [ # # ]: 0 : if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
4160 : : return false;
4161 : :
4162 : : /* check availability */
4163 : 0 : ridx = array_index_nospec(ridx, IEEE80211_HT_MCS_MASK_LEN);
4164 [ # # ]: 0 : if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
4165 : 0 : mcs[ridx] |= rbit;
4166 : : else
4167 : : return false;
4168 : : }
4169 : :
4170 : : return true;
4171 : : }
4172 : :
4173 : 0 : static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
4174 : : {
4175 : 0 : u16 mcs_mask = 0;
4176 : :
4177 : 0 : switch (vht_mcs_map) {
4178 : : case IEEE80211_VHT_MCS_NOT_SUPPORTED:
4179 : : break;
4180 : : case IEEE80211_VHT_MCS_SUPPORT_0_7:
4181 : : mcs_mask = 0x00FF;
4182 : : break;
4183 : : case IEEE80211_VHT_MCS_SUPPORT_0_8:
4184 : : mcs_mask = 0x01FF;
4185 : : break;
4186 : : case IEEE80211_VHT_MCS_SUPPORT_0_9:
4187 : : mcs_mask = 0x03FF;
4188 : : break;
4189 : : default:
4190 : : break;
4191 : : }
4192 : :
4193 : 0 : return mcs_mask;
4194 : : }
4195 : :
4196 : 0 : static void vht_build_mcs_mask(u16 vht_mcs_map,
4197 : : u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
4198 : : {
4199 : 0 : u8 nss;
4200 : :
4201 [ # # ]: 0 : for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
4202 [ # # ]: 0 : vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
4203 : 0 : vht_mcs_map >>= 2;
4204 : : }
4205 : : }
4206 : :
4207 : : static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
4208 : : struct nl80211_txrate_vht *txrate,
4209 : : u16 mcs[NL80211_VHT_NSS_MAX])
4210 : : {
4211 : : u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
4212 : : u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
4213 : : u8 i;
4214 : :
4215 : : if (!sband->vht_cap.vht_supported)
4216 : : return false;
4217 : :
4218 : : memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
4219 : :
4220 : : /* Build vht_mcs_mask from VHT capabilities */
4221 : : vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
4222 : :
4223 : : for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
4224 : : if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
4225 : : mcs[i] = txrate->mcs[i];
4226 : : else
4227 : : return false;
4228 : : }
4229 : :
4230 : : return true;
4231 : : }
4232 : :
4233 : : static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
4234 : : [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
4235 : : .len = NL80211_MAX_SUPP_RATES },
4236 : : [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
4237 : : .len = NL80211_MAX_SUPP_HT_RATES },
4238 : : [NL80211_TXRATE_VHT] = {
4239 : : .type = NLA_EXACT_LEN_WARN,
4240 : : .len = sizeof(struct nl80211_txrate_vht),
4241 : : },
4242 : : [NL80211_TXRATE_GI] = { .type = NLA_U8 },
4243 : : };
4244 : :
4245 : 0 : static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
4246 : : struct cfg80211_bitrate_mask *mask)
4247 : : {
4248 : 0 : struct nlattr *tb[NL80211_TXRATE_MAX + 1];
4249 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
4250 : 0 : int rem, i;
4251 : 0 : struct nlattr *tx_rates;
4252 : 0 : struct ieee80211_supported_band *sband;
4253 : 0 : u16 vht_tx_mcs_map;
4254 : :
4255 : 0 : memset(mask, 0, sizeof(*mask));
4256 : : /* Default to all rates enabled */
4257 [ # # ]: 0 : for (i = 0; i < NUM_NL80211_BANDS; i++) {
4258 : 0 : sband = rdev->wiphy.bands[i];
4259 : :
4260 [ # # ]: 0 : if (!sband)
4261 : 0 : continue;
4262 : :
4263 : 0 : mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
4264 : 0 : memcpy(mask->control[i].ht_mcs,
4265 : 0 : sband->ht_cap.mcs.rx_mask,
4266 : : sizeof(mask->control[i].ht_mcs));
4267 : :
4268 [ # # ]: 0 : if (!sband->vht_cap.vht_supported)
4269 : 0 : continue;
4270 : :
4271 : 0 : vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
4272 : 0 : vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
4273 : : }
4274 : :
4275 : : /* if no rates are given set it back to the defaults */
4276 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_TX_RATES])
4277 : 0 : goto out;
4278 : :
4279 : : /* The nested attribute uses enum nl80211_band as the index. This maps
4280 : : * directly to the enum nl80211_band values used in cfg80211.
4281 : : */
4282 : 0 : BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
4283 [ # # ]: 0 : nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
4284 [ # # ]: 0 : enum nl80211_band band = nla_type(tx_rates);
4285 : 0 : int err;
4286 : :
4287 [ # # ]: 0 : if (band < 0 || band >= NUM_NL80211_BANDS)
4288 : : return -EINVAL;
4289 : 0 : sband = rdev->wiphy.bands[band];
4290 [ # # ]: 0 : if (sband == NULL)
4291 : : return -EINVAL;
4292 : 0 : err = nla_parse_nested_deprecated(tb, NL80211_TXRATE_MAX,
4293 : : tx_rates,
4294 : : nl80211_txattr_policy,
4295 : : info->extack);
4296 [ # # ]: 0 : if (err)
4297 : 0 : return err;
4298 [ # # ]: 0 : if (tb[NL80211_TXRATE_LEGACY]) {
4299 : 0 : mask->control[band].legacy = rateset_to_mask(
4300 : : sband,
4301 : : nla_data(tb[NL80211_TXRATE_LEGACY]),
4302 : 0 : nla_len(tb[NL80211_TXRATE_LEGACY]));
4303 [ # # # # ]: 0 : if ((mask->control[band].legacy == 0) &&
4304 [ # # ]: 0 : nla_len(tb[NL80211_TXRATE_LEGACY]))
4305 : : return -EINVAL;
4306 : : }
4307 [ # # ]: 0 : if (tb[NL80211_TXRATE_HT]) {
4308 [ # # ]: 0 : if (!ht_rateset_to_mask(
4309 : : sband,
4310 : : nla_data(tb[NL80211_TXRATE_HT]),
4311 : 0 : nla_len(tb[NL80211_TXRATE_HT]),
4312 : 0 : mask->control[band].ht_mcs))
4313 : : return -EINVAL;
4314 : : }
4315 [ # # ]: 0 : if (tb[NL80211_TXRATE_VHT]) {
4316 [ # # ]: 0 : if (!vht_set_mcs_mask(
4317 : : sband,
4318 : : nla_data(tb[NL80211_TXRATE_VHT]),
4319 : 0 : mask->control[band].vht_mcs))
4320 : : return -EINVAL;
4321 : : }
4322 [ # # ]: 0 : if (tb[NL80211_TXRATE_GI]) {
4323 [ # # ]: 0 : mask->control[band].gi =
4324 : 0 : nla_get_u8(tb[NL80211_TXRATE_GI]);
4325 [ # # ]: 0 : if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
4326 : : return -EINVAL;
4327 : : }
4328 : :
4329 [ # # ]: 0 : if (mask->control[band].legacy == 0) {
4330 : : /* don't allow empty legacy rates if HT or VHT
4331 : : * are not even supported.
4332 : : */
4333 [ # # ]: 0 : if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
4334 [ # # ]: 0 : rdev->wiphy.bands[band]->vht_cap.vht_supported))
4335 : : return -EINVAL;
4336 : :
4337 [ # # ]: 0 : for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
4338 [ # # ]: 0 : if (mask->control[band].ht_mcs[i])
4339 : 0 : goto out;
4340 : :
4341 [ # # ]: 0 : for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
4342 [ # # ]: 0 : if (mask->control[band].vht_mcs[i])
4343 : 0 : goto out;
4344 : :
4345 : : /* legacy and mcs rates may not be both empty */
4346 : : return -EINVAL;
4347 : : }
4348 : : }
4349 : :
4350 : : out:
4351 : : return 0;
4352 : : }
4353 : :
4354 : 0 : static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
4355 : : enum nl80211_band band,
4356 : : struct cfg80211_bitrate_mask *beacon_rate)
4357 : : {
4358 : 0 : u32 count_ht, count_vht, i;
4359 : 0 : u32 rate = beacon_rate->control[band].legacy;
4360 : :
4361 : : /* Allow only one rate */
4362 [ # # # # ]: 0 : if (hweight32(rate) > 1)
4363 : : return -EINVAL;
4364 : :
4365 : : count_ht = 0;
4366 [ # # ]: 0 : for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
4367 [ # # # # ]: 0 : if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
4368 : : return -EINVAL;
4369 [ # # ]: 0 : } else if (beacon_rate->control[band].ht_mcs[i]) {
4370 : 0 : count_ht++;
4371 [ # # ]: 0 : if (count_ht > 1)
4372 : : return -EINVAL;
4373 : : }
4374 [ # # ]: 0 : if (count_ht && rate)
4375 : : return -EINVAL;
4376 : : }
4377 : :
4378 : : count_vht = 0;
4379 [ # # ]: 0 : for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
4380 [ # # # # ]: 0 : if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) {
4381 : : return -EINVAL;
4382 [ # # ]: 0 : } else if (beacon_rate->control[band].vht_mcs[i]) {
4383 : 0 : count_vht++;
4384 [ # # ]: 0 : if (count_vht > 1)
4385 : : return -EINVAL;
4386 : : }
4387 [ # # ]: 0 : if (count_vht && rate)
4388 : : return -EINVAL;
4389 : : }
4390 : :
4391 [ # # # # ]: 0 : if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
4392 : : return -EINVAL;
4393 : :
4394 [ # # # # ]: 0 : if (rate &&
4395 : : !wiphy_ext_feature_isset(&rdev->wiphy,
4396 : : NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
4397 : : return -EINVAL;
4398 [ # # # # ]: 0 : if (count_ht &&
4399 : : !wiphy_ext_feature_isset(&rdev->wiphy,
4400 : : NL80211_EXT_FEATURE_BEACON_RATE_HT))
4401 : : return -EINVAL;
4402 [ # # # # ]: 0 : if (count_vht &&
4403 : : !wiphy_ext_feature_isset(&rdev->wiphy,
4404 : : NL80211_EXT_FEATURE_BEACON_RATE_VHT))
4405 : 0 : return -EINVAL;
4406 : :
4407 : : return 0;
4408 : : }
4409 : :
4410 : 0 : static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
4411 : : struct nlattr *attrs[],
4412 : : struct cfg80211_beacon_data *bcn)
4413 : : {
4414 : 0 : bool haveinfo = false;
4415 : 0 : int err;
4416 : :
4417 : 0 : memset(bcn, 0, sizeof(*bcn));
4418 : :
4419 [ # # ]: 0 : if (attrs[NL80211_ATTR_BEACON_HEAD]) {
4420 [ # # ]: 0 : bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
4421 [ # # ]: 0 : bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
4422 [ # # ]: 0 : if (!bcn->head_len)
4423 : : return -EINVAL;
4424 : : haveinfo = true;
4425 : : }
4426 : :
4427 [ # # ]: 0 : if (attrs[NL80211_ATTR_BEACON_TAIL]) {
4428 : 0 : bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
4429 : 0 : bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
4430 : 0 : haveinfo = true;
4431 : : }
4432 : :
4433 [ # # ]: 0 : if (!haveinfo)
4434 : : return -EINVAL;
4435 : :
4436 [ # # ]: 0 : if (attrs[NL80211_ATTR_IE]) {
4437 : 0 : bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
4438 : 0 : bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
4439 : : }
4440 : :
4441 [ # # ]: 0 : if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
4442 : 0 : bcn->proberesp_ies =
4443 : : nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
4444 : 0 : bcn->proberesp_ies_len =
4445 : 0 : nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
4446 : : }
4447 : :
4448 [ # # ]: 0 : if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
4449 : 0 : bcn->assocresp_ies =
4450 : : nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
4451 : 0 : bcn->assocresp_ies_len =
4452 : 0 : nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
4453 : : }
4454 : :
4455 [ # # ]: 0 : if (attrs[NL80211_ATTR_PROBE_RESP]) {
4456 : 0 : bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
4457 : 0 : bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
4458 : : }
4459 : :
4460 [ # # ]: 0 : if (attrs[NL80211_ATTR_FTM_RESPONDER]) {
4461 : 0 : struct nlattr *tb[NL80211_FTM_RESP_ATTR_MAX + 1];
4462 : :
4463 : 0 : err = nla_parse_nested_deprecated(tb,
4464 : : NL80211_FTM_RESP_ATTR_MAX,
4465 : : attrs[NL80211_ATTR_FTM_RESPONDER],
4466 : : NULL, NULL);
4467 [ # # ]: 0 : if (err)
4468 : 0 : return err;
4469 : :
4470 [ # # # # ]: 0 : if (tb[NL80211_FTM_RESP_ATTR_ENABLED] &&
4471 : : wiphy_ext_feature_isset(&rdev->wiphy,
4472 : : NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
4473 : 0 : bcn->ftm_responder = 1;
4474 : : else
4475 : : return -EOPNOTSUPP;
4476 : :
4477 [ # # ]: 0 : if (tb[NL80211_FTM_RESP_ATTR_LCI]) {
4478 : 0 : bcn->lci = nla_data(tb[NL80211_FTM_RESP_ATTR_LCI]);
4479 : 0 : bcn->lci_len = nla_len(tb[NL80211_FTM_RESP_ATTR_LCI]);
4480 : : }
4481 : :
4482 [ # # ]: 0 : if (tb[NL80211_FTM_RESP_ATTR_CIVICLOC]) {
4483 : 0 : bcn->civicloc = nla_data(tb[NL80211_FTM_RESP_ATTR_CIVICLOC]);
4484 : 0 : bcn->civicloc_len = nla_len(tb[NL80211_FTM_RESP_ATTR_CIVICLOC]);
4485 : : }
4486 : : } else {
4487 : 0 : bcn->ftm_responder = -1;
4488 : : }
4489 : :
4490 : : return 0;
4491 : : }
4492 : :
4493 : 0 : static int nl80211_parse_he_obss_pd(struct nlattr *attrs,
4494 : : struct ieee80211_he_obss_pd *he_obss_pd)
4495 : : {
4496 : 0 : struct nlattr *tb[NL80211_HE_OBSS_PD_ATTR_MAX + 1];
4497 : 0 : int err;
4498 : :
4499 [ # # ]: 0 : err = nla_parse_nested(tb, NL80211_HE_OBSS_PD_ATTR_MAX, attrs,
4500 : : he_obss_pd_policy, NULL);
4501 [ # # ]: 0 : if (err)
4502 : 0 : return err;
4503 : :
4504 [ # # ]: 0 : if (!tb[NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET] ||
4505 [ # # ]: 0 : !tb[NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET])
4506 : : return -EINVAL;
4507 : :
4508 [ # # ]: 0 : he_obss_pd->min_offset =
4509 : : nla_get_u32(tb[NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET]);
4510 : 0 : he_obss_pd->max_offset =
4511 : : nla_get_u32(tb[NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET]);
4512 : :
4513 [ # # ]: 0 : if (he_obss_pd->min_offset >= he_obss_pd->max_offset)
4514 : : return -EINVAL;
4515 : :
4516 : 0 : he_obss_pd->enable = true;
4517 : :
4518 : 0 : return 0;
4519 : : }
4520 : :
4521 : 0 : static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
4522 : : const u8 *rates)
4523 : : {
4524 : 0 : int i;
4525 : :
4526 : 0 : if (!rates)
4527 : : return;
4528 : :
4529 [ # # # # ]: 0 : for (i = 0; i < rates[1]; i++) {
4530 [ # # # # ]: 0 : if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
4531 : 0 : params->ht_required = true;
4532 [ # # # # ]: 0 : if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
4533 : 0 : params->vht_required = true;
4534 : : }
4535 : : }
4536 : :
4537 : : /*
4538 : : * Since the nl80211 API didn't include, from the beginning, attributes about
4539 : : * HT/VHT requirements/capabilities, we parse them out of the IEs for the
4540 : : * benefit of drivers that rebuild IEs in the firmware.
4541 : : */
4542 : 0 : static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
4543 : : {
4544 : 0 : const struct cfg80211_beacon_data *bcn = ¶ms->beacon;
4545 : 0 : size_t ies_len = bcn->tail_len;
4546 : 0 : const u8 *ies = bcn->tail;
4547 : 0 : const u8 *rates;
4548 : 0 : const u8 *cap;
4549 : :
4550 : 0 : rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
4551 [ # # ]: 0 : nl80211_check_ap_rate_selectors(params, rates);
4552 : :
4553 : 0 : rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
4554 [ # # ]: 0 : nl80211_check_ap_rate_selectors(params, rates);
4555 : :
4556 : 0 : cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
4557 [ # # # # ]: 0 : if (cap && cap[1] >= sizeof(*params->ht_cap))
4558 : 0 : params->ht_cap = (void *)(cap + 2);
4559 : 0 : cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
4560 [ # # # # ]: 0 : if (cap && cap[1] >= sizeof(*params->vht_cap))
4561 : 0 : params->vht_cap = (void *)(cap + 2);
4562 : 0 : cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
4563 [ # # # # ]: 0 : if (cap && cap[1] >= sizeof(*params->he_cap) + 1)
4564 : 0 : params->he_cap = (void *)(cap + 3);
4565 : 0 : }
4566 : :
4567 : 0 : static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
4568 : : struct cfg80211_ap_settings *params)
4569 : : {
4570 : 0 : struct wireless_dev *wdev;
4571 : 0 : bool ret = false;
4572 : :
4573 [ # # ]: 0 : list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
4574 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_AP &&
4575 : : wdev->iftype != NL80211_IFTYPE_P2P_GO)
4576 : 0 : continue;
4577 : :
4578 [ # # ]: 0 : if (!wdev->preset_chandef.chan)
4579 : 0 : continue;
4580 : :
4581 : 0 : params->chandef = wdev->preset_chandef;
4582 : 0 : ret = true;
4583 : 0 : break;
4584 : : }
4585 : :
4586 : 0 : return ret;
4587 : : }
4588 : :
4589 : 0 : static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
4590 : : enum nl80211_auth_type auth_type,
4591 : : enum nl80211_commands cmd)
4592 : : {
4593 [ # # ]: 0 : if (auth_type > NL80211_AUTHTYPE_MAX)
4594 : : return false;
4595 : :
4596 [ # # # # ]: 0 : switch (cmd) {
4597 : 0 : case NL80211_CMD_AUTHENTICATE:
4598 [ # # # # : 0 : if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
# # # # ]
4599 : : auth_type == NL80211_AUTHTYPE_SAE)
4600 : : return false;
4601 [ # # # # ]: 0 : if (!wiphy_ext_feature_isset(&rdev->wiphy,
4602 : 0 : NL80211_EXT_FEATURE_FILS_STA) &&
4603 : : (auth_type == NL80211_AUTHTYPE_FILS_SK ||
4604 [ # # # # ]: 0 : auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
4605 : : auth_type == NL80211_AUTHTYPE_FILS_PK))
4606 : 0 : return false;
4607 : : return true;
4608 : 0 : case NL80211_CMD_CONNECT:
4609 [ # # # # ]: 0 : if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
4610 : : !wiphy_ext_feature_isset(&rdev->wiphy,
4611 [ # # ]: 0 : NL80211_EXT_FEATURE_SAE_OFFLOAD) &&
4612 : : auth_type == NL80211_AUTHTYPE_SAE)
4613 : : return false;
4614 : :
4615 : : /* FILS with SK PFS or PK not supported yet */
4616 [ # # ]: 0 : if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
4617 : : auth_type == NL80211_AUTHTYPE_FILS_PK)
4618 : : return false;
4619 [ # # ]: 0 : if (!wiphy_ext_feature_isset(
4620 : : &rdev->wiphy,
4621 [ # # ]: 0 : NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
4622 : : auth_type == NL80211_AUTHTYPE_FILS_SK)
4623 : 0 : return false;
4624 : : return true;
4625 : 0 : case NL80211_CMD_START_AP:
4626 : : /* SAE not supported yet */
4627 [ # # # # ]: 0 : if (auth_type == NL80211_AUTHTYPE_SAE)
4628 : : return false;
4629 : : /* FILS not supported yet */
4630 : 0 : if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
4631 [ # # # # ]: 0 : auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
4632 : : auth_type == NL80211_AUTHTYPE_FILS_PK)
4633 : 0 : return false;
4634 : : return true;
4635 : : default:
4636 : : return false;
4637 : : }
4638 : : }
4639 : :
4640 : 0 : static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
4641 : : {
4642 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
4643 : 0 : struct net_device *dev = info->user_ptr[1];
4644 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
4645 : 0 : struct cfg80211_ap_settings params;
4646 : 0 : int err;
4647 : :
4648 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4649 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4650 : : return -EOPNOTSUPP;
4651 : :
4652 [ # # ]: 0 : if (!rdev->ops->start_ap)
4653 : : return -EOPNOTSUPP;
4654 : :
4655 [ # # ]: 0 : if (wdev->beacon_interval)
4656 : : return -EALREADY;
4657 : :
4658 : 0 : memset(¶ms, 0, sizeof(params));
4659 : :
4660 : : /* these are required for START_AP */
4661 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
4662 [ # # ]: 0 : !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
4663 [ # # ]: 0 : !info->attrs[NL80211_ATTR_BEACON_HEAD])
4664 : : return -EINVAL;
4665 : :
4666 : 0 : err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon);
4667 [ # # ]: 0 : if (err)
4668 : : return err;
4669 : :
4670 : 0 : params.beacon_interval =
4671 : 0 : nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
4672 : 0 : params.dtim_period =
4673 : 0 : nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
4674 : :
4675 : 0 : err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
4676 : : params.beacon_interval);
4677 [ # # ]: 0 : if (err)
4678 : : return err;
4679 : :
4680 : : /*
4681 : : * In theory, some of these attributes should be required here
4682 : : * but since they were not used when the command was originally
4683 : : * added, keep them optional for old user space programs to let
4684 : : * them continue to work with drivers that do not need the
4685 : : * additional information -- drivers must check!
4686 : : */
4687 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SSID]) {
4688 [ # # ]: 0 : params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
4689 : 0 : params.ssid_len =
4690 [ # # ]: 0 : nla_len(info->attrs[NL80211_ATTR_SSID]);
4691 [ # # ]: 0 : if (params.ssid_len == 0 ||
4692 : : params.ssid_len > IEEE80211_MAX_SSID_LEN)
4693 : : return -EINVAL;
4694 : : }
4695 : :
4696 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HIDDEN_SSID])
4697 : 0 : params.hidden_ssid = nla_get_u32(
4698 : : info->attrs[NL80211_ATTR_HIDDEN_SSID]);
4699 : :
4700 : 0 : params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
4701 : :
4702 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
4703 [ # # ]: 0 : params.auth_type = nla_get_u32(
4704 : : info->attrs[NL80211_ATTR_AUTH_TYPE]);
4705 [ # # ]: 0 : if (!nl80211_valid_auth_type(rdev, params.auth_type,
4706 : : NL80211_CMD_START_AP))
4707 : : return -EINVAL;
4708 : : } else
4709 : 0 : params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
4710 : :
4711 : 0 : err = nl80211_crypto_settings(rdev, info, ¶ms.crypto,
4712 : : NL80211_MAX_NR_CIPHER_SUITES);
4713 [ # # ]: 0 : if (err)
4714 : : return err;
4715 : :
4716 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
4717 [ # # ]: 0 : if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
4718 : : return -EOPNOTSUPP;
4719 : 0 : params.inactivity_timeout = nla_get_u16(
4720 : : info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
4721 : : }
4722 : :
4723 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
4724 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4725 : : return -EINVAL;
4726 [ # # ]: 0 : params.p2p_ctwindow =
4727 : : nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
4728 [ # # ]: 0 : if (params.p2p_ctwindow != 0 &&
4729 [ # # ]: 0 : !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
4730 : : return -EINVAL;
4731 : : }
4732 : :
4733 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
4734 : 0 : u8 tmp;
4735 : :
4736 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4737 : : return -EINVAL;
4738 [ # # ]: 0 : tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
4739 : 0 : params.p2p_opp_ps = tmp;
4740 [ # # ]: 0 : if (params.p2p_opp_ps != 0 &&
4741 [ # # ]: 0 : !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
4742 : : return -EINVAL;
4743 : : }
4744 : :
4745 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
4746 : 0 : err = nl80211_parse_chandef(rdev, info, ¶ms.chandef);
4747 [ # # ]: 0 : if (err)
4748 : : return err;
4749 [ # # ]: 0 : } else if (wdev->preset_chandef.chan) {
4750 : 0 : params.chandef = wdev->preset_chandef;
4751 [ # # ]: 0 : } else if (!nl80211_get_ap_channel(rdev, ¶ms))
4752 : : return -EINVAL;
4753 : :
4754 [ # # ]: 0 : if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
4755 : : wdev->iftype))
4756 : : return -EINVAL;
4757 : :
4758 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_TX_RATES]) {
4759 : 0 : err = nl80211_parse_tx_bitrate_mask(info, ¶ms.beacon_rate);
4760 [ # # ]: 0 : if (err)
4761 : : return err;
4762 : :
4763 : 0 : err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
4764 : : ¶ms.beacon_rate);
4765 [ # # ]: 0 : if (err)
4766 : : return err;
4767 : : }
4768 : :
4769 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
4770 [ # # # # ]: 0 : params.smps_mode =
4771 : 0 : nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
4772 [ # # # # ]: 0 : switch (params.smps_mode) {
4773 : : case NL80211_SMPS_OFF:
4774 : : break;
4775 : 0 : case NL80211_SMPS_STATIC:
4776 [ # # ]: 0 : if (!(rdev->wiphy.features &
4777 : : NL80211_FEATURE_STATIC_SMPS))
4778 : : return -EINVAL;
4779 : : break;
4780 : 0 : case NL80211_SMPS_DYNAMIC:
4781 [ # # ]: 0 : if (!(rdev->wiphy.features &
4782 : : NL80211_FEATURE_DYNAMIC_SMPS))
4783 : : return -EINVAL;
4784 : : break;
4785 : : default:
4786 : : return -EINVAL;
4787 : : }
4788 : : } else {
4789 : 0 : params.smps_mode = NL80211_SMPS_OFF;
4790 : : }
4791 : :
4792 [ # # ]: 0 : params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
4793 [ # # # # ]: 0 : if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
4794 : : return -EOPNOTSUPP;
4795 : :
4796 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
4797 : 0 : params.acl = parse_acl_data(&rdev->wiphy, info);
4798 [ # # ]: 0 : if (IS_ERR(params.acl))
4799 : 0 : return PTR_ERR(params.acl);
4800 : : }
4801 : :
4802 : 0 : params.twt_responder =
4803 [ # # ]: 0 : nla_get_flag(info->attrs[NL80211_ATTR_TWT_RESPONDER]);
4804 : :
4805 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HE_OBSS_PD]) {
4806 : 0 : err = nl80211_parse_he_obss_pd(
4807 : : info->attrs[NL80211_ATTR_HE_OBSS_PD],
4808 : : ¶ms.he_obss_pd);
4809 : 0 : goto out;
4810 : : }
4811 : :
4812 : 0 : nl80211_calculate_ap_params(¶ms);
4813 : :
4814 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
4815 : 0 : params.flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
4816 : :
4817 : 0 : wdev_lock(wdev);
4818 : 0 : err = rdev_start_ap(rdev, dev, ¶ms);
4819 [ # # ]: 0 : if (!err) {
4820 : 0 : wdev->preset_chandef = params.chandef;
4821 : 0 : wdev->beacon_interval = params.beacon_interval;
4822 : 0 : wdev->chandef = params.chandef;
4823 : 0 : wdev->ssid_len = params.ssid_len;
4824 : 0 : memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
4825 : :
4826 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
4827 : 0 : wdev->conn_owner_nlportid = info->snd_portid;
4828 : : }
4829 : 0 : wdev_unlock(wdev);
4830 : :
4831 : 0 : out:
4832 : 0 : kfree(params.acl);
4833 : :
4834 : 0 : return err;
4835 : : }
4836 : :
4837 : 0 : static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
4838 : : {
4839 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
4840 : 0 : struct net_device *dev = info->user_ptr[1];
4841 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
4842 : 0 : struct cfg80211_beacon_data params;
4843 : 0 : int err;
4844 : :
4845 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4846 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4847 : : return -EOPNOTSUPP;
4848 : :
4849 [ # # ]: 0 : if (!rdev->ops->change_beacon)
4850 : : return -EOPNOTSUPP;
4851 : :
4852 [ # # ]: 0 : if (!wdev->beacon_interval)
4853 : : return -EINVAL;
4854 : :
4855 : 0 : err = nl80211_parse_beacon(rdev, info->attrs, ¶ms);
4856 [ # # ]: 0 : if (err)
4857 : : return err;
4858 : :
4859 : 0 : wdev_lock(wdev);
4860 : 0 : err = rdev_change_beacon(rdev, dev, ¶ms);
4861 : 0 : wdev_unlock(wdev);
4862 : :
4863 : 0 : return err;
4864 : : }
4865 : :
4866 : 0 : static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
4867 : : {
4868 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
4869 : 0 : struct net_device *dev = info->user_ptr[1];
4870 : :
4871 : 0 : return cfg80211_stop_ap(rdev, dev, false);
4872 : : }
4873 : :
4874 : : static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
4875 : : [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
4876 : : [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
4877 : : [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
4878 : : [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
4879 : : [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
4880 : : [NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },
4881 : : };
4882 : :
4883 : : static int parse_station_flags(struct genl_info *info,
4884 : : enum nl80211_iftype iftype,
4885 : : struct station_parameters *params)
4886 : : {
4887 : : struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
4888 : : struct nlattr *nla;
4889 : : int flag;
4890 : :
4891 : : /*
4892 : : * Try parsing the new attribute first so userspace
4893 : : * can specify both for older kernels.
4894 : : */
4895 : : nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
4896 : : if (nla) {
4897 : : struct nl80211_sta_flag_update *sta_flags;
4898 : :
4899 : : sta_flags = nla_data(nla);
4900 : : params->sta_flags_mask = sta_flags->mask;
4901 : : params->sta_flags_set = sta_flags->set;
4902 : : params->sta_flags_set &= params->sta_flags_mask;
4903 : : if ((params->sta_flags_mask |
4904 : : params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
4905 : : return -EINVAL;
4906 : : return 0;
4907 : : }
4908 : :
4909 : : /* if present, parse the old attribute */
4910 : :
4911 : : nla = info->attrs[NL80211_ATTR_STA_FLAGS];
4912 : : if (!nla)
4913 : : return 0;
4914 : :
4915 : : if (nla_parse_nested_deprecated(flags, NL80211_STA_FLAG_MAX, nla, sta_flags_policy, info->extack))
4916 : : return -EINVAL;
4917 : :
4918 : : /*
4919 : : * Only allow certain flags for interface types so that
4920 : : * other attributes are silently ignored. Remember that
4921 : : * this is backward compatibility code with old userspace
4922 : : * and shouldn't be hit in other cases anyway.
4923 : : */
4924 : : switch (iftype) {
4925 : : case NL80211_IFTYPE_AP:
4926 : : case NL80211_IFTYPE_AP_VLAN:
4927 : : case NL80211_IFTYPE_P2P_GO:
4928 : : params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4929 : : BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4930 : : BIT(NL80211_STA_FLAG_WME) |
4931 : : BIT(NL80211_STA_FLAG_MFP);
4932 : : break;
4933 : : case NL80211_IFTYPE_P2P_CLIENT:
4934 : : case NL80211_IFTYPE_STATION:
4935 : : params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4936 : : BIT(NL80211_STA_FLAG_TDLS_PEER);
4937 : : break;
4938 : : case NL80211_IFTYPE_MESH_POINT:
4939 : : params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4940 : : BIT(NL80211_STA_FLAG_MFP) |
4941 : : BIT(NL80211_STA_FLAG_AUTHORIZED);
4942 : : break;
4943 : : default:
4944 : : return -EINVAL;
4945 : : }
4946 : :
4947 : : for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
4948 : : if (flags[flag]) {
4949 : : params->sta_flags_set |= (1<<flag);
4950 : :
4951 : : /* no longer support new API additions in old API */
4952 : : if (flag > NL80211_STA_FLAG_MAX_OLD_API)
4953 : : return -EINVAL;
4954 : : }
4955 : : }
4956 : :
4957 : : return 0;
4958 : : }
4959 : :
4960 : 0 : bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
4961 : : {
4962 : 0 : struct nlattr *rate;
4963 : 0 : u32 bitrate;
4964 : 0 : u16 bitrate_compat;
4965 : 0 : enum nl80211_rate_info rate_flg;
4966 : :
4967 : 0 : rate = nla_nest_start_noflag(msg, attr);
4968 [ # # ]: 0 : if (!rate)
4969 : : return false;
4970 : :
4971 : : /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
4972 : 0 : bitrate = cfg80211_calculate_bitrate(info);
4973 : : /* report 16-bit bitrate only if we can */
4974 [ # # ]: 0 : bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
4975 [ # # # # ]: 0 : if (bitrate > 0 &&
4976 : : nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
4977 : : return false;
4978 [ # # # # ]: 0 : if (bitrate_compat > 0 &&
4979 : : nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
4980 : : return false;
4981 : :
4982 [ # # # # : 0 : switch (info->bw) {
# # # # ]
4983 : : case RATE_INFO_BW_5:
4984 : : rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
4985 : : break;
4986 : : case RATE_INFO_BW_10:
4987 : 0 : rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
4988 : 0 : break;
4989 : : default:
4990 : 0 : WARN_ON(1);
4991 : : /* fall through */
4992 : : case RATE_INFO_BW_20:
4993 : : rate_flg = 0;
4994 : : break;
4995 : : case RATE_INFO_BW_40:
4996 : 0 : rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
4997 : 0 : break;
4998 : : case RATE_INFO_BW_80:
4999 : 0 : rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
5000 : 0 : break;
5001 : : case RATE_INFO_BW_160:
5002 : : rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
5003 : : break;
5004 : 0 : case RATE_INFO_BW_HE_RU:
5005 : 0 : rate_flg = 0;
5006 [ # # ]: 0 : WARN_ON(!(info->flags & RATE_INFO_FLAGS_HE_MCS));
5007 : : }
5008 : :
5009 [ # # ]: 0 : if (rate_flg && nla_put_flag(msg, rate_flg))
5010 : : return false;
5011 : :
5012 [ # # ]: 0 : if (info->flags & RATE_INFO_FLAGS_MCS) {
5013 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
5014 : : return false;
5015 [ # # # # ]: 0 : if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
5016 : : nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
5017 : : return false;
5018 [ # # ]: 0 : } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
5019 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
5020 : : return false;
5021 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
5022 : : return false;
5023 [ # # # # ]: 0 : if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
5024 : : nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
5025 : : return false;
5026 [ # # ]: 0 : } else if (info->flags & RATE_INFO_FLAGS_HE_MCS) {
5027 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_RATE_INFO_HE_MCS, info->mcs))
5028 : : return false;
5029 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_RATE_INFO_HE_NSS, info->nss))
5030 : : return false;
5031 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_RATE_INFO_HE_GI, info->he_gi))
5032 : : return false;
5033 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_RATE_INFO_HE_DCM, info->he_dcm))
5034 : : return false;
5035 [ # # # # ]: 0 : if (info->bw == RATE_INFO_BW_HE_RU &&
5036 : : nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
5037 : 0 : info->he_ru_alloc))
5038 : : return false;
5039 : : }
5040 : :
5041 : 0 : nla_nest_end(msg, rate);
5042 : 0 : return true;
5043 : : }
5044 : :
5045 : 0 : static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
5046 : : int id)
5047 : : {
5048 : 0 : void *attr;
5049 : 0 : int i = 0;
5050 : :
5051 [ # # ]: 0 : if (!mask)
5052 : : return true;
5053 : :
5054 : 0 : attr = nla_nest_start_noflag(msg, id);
5055 [ # # ]: 0 : if (!attr)
5056 : : return false;
5057 : :
5058 [ # # ]: 0 : for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
5059 [ # # ]: 0 : if (!(mask & BIT(i)))
5060 : 0 : continue;
5061 : :
5062 [ # # ]: 0 : if (nla_put_u8(msg, i, signal[i]))
5063 : : return false;
5064 : : }
5065 : :
5066 : 0 : nla_nest_end(msg, attr);
5067 : :
5068 : 0 : return true;
5069 : : }
5070 : :
5071 : : static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
5072 : : u32 seq, int flags,
5073 : : struct cfg80211_registered_device *rdev,
5074 : : struct net_device *dev,
5075 : : const u8 *mac_addr, struct station_info *sinfo)
5076 : : {
5077 : : void *hdr;
5078 : : struct nlattr *sinfoattr, *bss_param;
5079 : :
5080 : : hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
5081 : : if (!hdr) {
5082 : : cfg80211_sinfo_release_content(sinfo);
5083 : : return -1;
5084 : : }
5085 : :
5086 : : if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5087 : : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
5088 : : nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
5089 : : goto nla_put_failure;
5090 : :
5091 : : sinfoattr = nla_nest_start_noflag(msg, NL80211_ATTR_STA_INFO);
5092 : : if (!sinfoattr)
5093 : : goto nla_put_failure;
5094 : :
5095 : : #define PUT_SINFO(attr, memb, type) do { \
5096 : : BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
5097 : : if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
5098 : : nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
5099 : : sinfo->memb)) \
5100 : : goto nla_put_failure; \
5101 : : } while (0)
5102 : : #define PUT_SINFO_U64(attr, memb) do { \
5103 : : if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
5104 : : nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
5105 : : sinfo->memb, NL80211_STA_INFO_PAD)) \
5106 : : goto nla_put_failure; \
5107 : : } while (0)
5108 : :
5109 : : PUT_SINFO(CONNECTED_TIME, connected_time, u32);
5110 : : PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
5111 : : PUT_SINFO_U64(ASSOC_AT_BOOTTIME, assoc_at);
5112 : :
5113 : : if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES) |
5114 : : BIT_ULL(NL80211_STA_INFO_RX_BYTES64)) &&
5115 : : nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
5116 : : (u32)sinfo->rx_bytes))
5117 : : goto nla_put_failure;
5118 : :
5119 : : if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES) |
5120 : : BIT_ULL(NL80211_STA_INFO_TX_BYTES64)) &&
5121 : : nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
5122 : : (u32)sinfo->tx_bytes))
5123 : : goto nla_put_failure;
5124 : :
5125 : : PUT_SINFO_U64(RX_BYTES64, rx_bytes);
5126 : : PUT_SINFO_U64(TX_BYTES64, tx_bytes);
5127 : : PUT_SINFO(LLID, llid, u16);
5128 : : PUT_SINFO(PLID, plid, u16);
5129 : : PUT_SINFO(PLINK_STATE, plink_state, u8);
5130 : : PUT_SINFO_U64(RX_DURATION, rx_duration);
5131 : : PUT_SINFO_U64(TX_DURATION, tx_duration);
5132 : :
5133 : : if (wiphy_ext_feature_isset(&rdev->wiphy,
5134 : : NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
5135 : : PUT_SINFO(AIRTIME_WEIGHT, airtime_weight, u16);
5136 : :
5137 : : switch (rdev->wiphy.signal_type) {
5138 : : case CFG80211_SIGNAL_TYPE_MBM:
5139 : : PUT_SINFO(SIGNAL, signal, u8);
5140 : : PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
5141 : : break;
5142 : : default:
5143 : : break;
5144 : : }
5145 : : if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) {
5146 : : if (!nl80211_put_signal(msg, sinfo->chains,
5147 : : sinfo->chain_signal,
5148 : : NL80211_STA_INFO_CHAIN_SIGNAL))
5149 : : goto nla_put_failure;
5150 : : }
5151 : : if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
5152 : : if (!nl80211_put_signal(msg, sinfo->chains,
5153 : : sinfo->chain_signal_avg,
5154 : : NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
5155 : : goto nla_put_failure;
5156 : : }
5157 : : if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) {
5158 : : if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
5159 : : NL80211_STA_INFO_TX_BITRATE))
5160 : : goto nla_put_failure;
5161 : : }
5162 : : if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) {
5163 : : if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
5164 : : NL80211_STA_INFO_RX_BITRATE))
5165 : : goto nla_put_failure;
5166 : : }
5167 : :
5168 : : PUT_SINFO(RX_PACKETS, rx_packets, u32);
5169 : : PUT_SINFO(TX_PACKETS, tx_packets, u32);
5170 : : PUT_SINFO(TX_RETRIES, tx_retries, u32);
5171 : : PUT_SINFO(TX_FAILED, tx_failed, u32);
5172 : : PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
5173 : : PUT_SINFO(AIRTIME_LINK_METRIC, airtime_link_metric, u32);
5174 : : PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
5175 : : PUT_SINFO(LOCAL_PM, local_pm, u32);
5176 : : PUT_SINFO(PEER_PM, peer_pm, u32);
5177 : : PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
5178 : : PUT_SINFO(CONNECTED_TO_GATE, connected_to_gate, u8);
5179 : :
5180 : : if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM)) {
5181 : : bss_param = nla_nest_start_noflag(msg,
5182 : : NL80211_STA_INFO_BSS_PARAM);
5183 : : if (!bss_param)
5184 : : goto nla_put_failure;
5185 : :
5186 : : if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
5187 : : nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
5188 : : ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
5189 : : nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
5190 : : ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
5191 : : nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
5192 : : nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
5193 : : sinfo->bss_param.dtim_period) ||
5194 : : nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
5195 : : sinfo->bss_param.beacon_interval))
5196 : : goto nla_put_failure;
5197 : :
5198 : : nla_nest_end(msg, bss_param);
5199 : : }
5200 : : if ((sinfo->filled & BIT_ULL(NL80211_STA_INFO_STA_FLAGS)) &&
5201 : : nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
5202 : : sizeof(struct nl80211_sta_flag_update),
5203 : : &sinfo->sta_flags))
5204 : : goto nla_put_failure;
5205 : :
5206 : : PUT_SINFO_U64(T_OFFSET, t_offset);
5207 : : PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
5208 : : PUT_SINFO_U64(BEACON_RX, rx_beacon);
5209 : : PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
5210 : : PUT_SINFO(RX_MPDUS, rx_mpdu_count, u32);
5211 : : PUT_SINFO(FCS_ERROR_COUNT, fcs_err_count, u32);
5212 : : if (wiphy_ext_feature_isset(&rdev->wiphy,
5213 : : NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT)) {
5214 : : PUT_SINFO(ACK_SIGNAL, ack_signal, u8);
5215 : : PUT_SINFO(ACK_SIGNAL_AVG, avg_ack_signal, s8);
5216 : : }
5217 : :
5218 : : #undef PUT_SINFO
5219 : : #undef PUT_SINFO_U64
5220 : :
5221 : : if (sinfo->pertid) {
5222 : : struct nlattr *tidsattr;
5223 : : int tid;
5224 : :
5225 : : tidsattr = nla_nest_start_noflag(msg,
5226 : : NL80211_STA_INFO_TID_STATS);
5227 : : if (!tidsattr)
5228 : : goto nla_put_failure;
5229 : :
5230 : : for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
5231 : : struct cfg80211_tid_stats *tidstats;
5232 : : struct nlattr *tidattr;
5233 : :
5234 : : tidstats = &sinfo->pertid[tid];
5235 : :
5236 : : if (!tidstats->filled)
5237 : : continue;
5238 : :
5239 : : tidattr = nla_nest_start_noflag(msg, tid + 1);
5240 : : if (!tidattr)
5241 : : goto nla_put_failure;
5242 : :
5243 : : #define PUT_TIDVAL_U64(attr, memb) do { \
5244 : : if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
5245 : : nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
5246 : : tidstats->memb, NL80211_TID_STATS_PAD)) \
5247 : : goto nla_put_failure; \
5248 : : } while (0)
5249 : :
5250 : : PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
5251 : : PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
5252 : : PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
5253 : : PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
5254 : :
5255 : : #undef PUT_TIDVAL_U64
5256 : : if ((tidstats->filled &
5257 : : BIT(NL80211_TID_STATS_TXQ_STATS)) &&
5258 : : !nl80211_put_txq_stats(msg, &tidstats->txq_stats,
5259 : : NL80211_TID_STATS_TXQ_STATS))
5260 : : goto nla_put_failure;
5261 : :
5262 : : nla_nest_end(msg, tidattr);
5263 : : }
5264 : :
5265 : : nla_nest_end(msg, tidsattr);
5266 : : }
5267 : :
5268 : : nla_nest_end(msg, sinfoattr);
5269 : :
5270 : : if (sinfo->assoc_req_ies_len &&
5271 : : nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
5272 : : sinfo->assoc_req_ies))
5273 : : goto nla_put_failure;
5274 : :
5275 : : cfg80211_sinfo_release_content(sinfo);
5276 : : genlmsg_end(msg, hdr);
5277 : : return 0;
5278 : :
5279 : : nla_put_failure:
5280 : : cfg80211_sinfo_release_content(sinfo);
5281 : : genlmsg_cancel(msg, hdr);
5282 : : return -EMSGSIZE;
5283 : : }
5284 : :
5285 : 0 : static int nl80211_dump_station(struct sk_buff *skb,
5286 : : struct netlink_callback *cb)
5287 : : {
5288 : 0 : struct station_info sinfo;
5289 : 0 : struct cfg80211_registered_device *rdev;
5290 : 0 : struct wireless_dev *wdev;
5291 : 0 : u8 mac_addr[ETH_ALEN];
5292 : 0 : int sta_idx = cb->args[2];
5293 : 0 : int err;
5294 : :
5295 : 0 : rtnl_lock();
5296 : 0 : err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
5297 [ # # ]: 0 : if (err)
5298 : 0 : goto out_err;
5299 : :
5300 [ # # ]: 0 : if (!wdev->netdev) {
5301 : 0 : err = -EINVAL;
5302 : 0 : goto out_err;
5303 : : }
5304 : :
5305 [ # # ]: 0 : if (!rdev->ops->dump_station) {
5306 : 0 : err = -EOPNOTSUPP;
5307 : 0 : goto out_err;
5308 : : }
5309 : :
5310 : 0 : while (1) {
5311 : 0 : memset(&sinfo, 0, sizeof(sinfo));
5312 : 0 : err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
5313 : : mac_addr, &sinfo);
5314 [ # # ]: 0 : if (err == -ENOENT)
5315 : : break;
5316 [ # # ]: 0 : if (err)
5317 : 0 : goto out_err;
5318 : :
5319 [ # # ]: 0 : if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
5320 : 0 : NETLINK_CB(cb->skb).portid,
5321 : 0 : cb->nlh->nlmsg_seq, NLM_F_MULTI,
5322 : 0 : rdev, wdev->netdev, mac_addr,
5323 : : &sinfo) < 0)
5324 : 0 : goto out;
5325 : :
5326 : 0 : sta_idx++;
5327 : : }
5328 : :
5329 : 0 : out:
5330 : 0 : cb->args[2] = sta_idx;
5331 : 0 : err = skb->len;
5332 : 0 : out_err:
5333 : 0 : rtnl_unlock();
5334 : :
5335 : 0 : return err;
5336 : : }
5337 : :
5338 : 0 : static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
5339 : : {
5340 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
5341 : 0 : struct net_device *dev = info->user_ptr[1];
5342 : 0 : struct station_info sinfo;
5343 : 0 : struct sk_buff *msg;
5344 : 0 : u8 *mac_addr = NULL;
5345 : 0 : int err;
5346 : :
5347 : 0 : memset(&sinfo, 0, sizeof(sinfo));
5348 : :
5349 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
5350 : : return -EINVAL;
5351 : :
5352 [ # # ]: 0 : mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
5353 : :
5354 [ # # ]: 0 : if (!rdev->ops->get_station)
5355 : : return -EOPNOTSUPP;
5356 : :
5357 : 0 : err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
5358 [ # # ]: 0 : if (err)
5359 : : return err;
5360 : :
5361 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5362 [ # # ]: 0 : if (!msg) {
5363 : 0 : cfg80211_sinfo_release_content(&sinfo);
5364 : 0 : return -ENOMEM;
5365 : : }
5366 : :
5367 [ # # ]: 0 : if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
5368 : : info->snd_portid, info->snd_seq, 0,
5369 : : rdev, dev, mac_addr, &sinfo) < 0) {
5370 : 0 : nlmsg_free(msg);
5371 : 0 : return -ENOBUFS;
5372 : : }
5373 : :
5374 : 0 : return genlmsg_reply(msg, info);
5375 : : }
5376 : :
5377 : 0 : int cfg80211_check_station_change(struct wiphy *wiphy,
5378 : : struct station_parameters *params,
5379 : : enum cfg80211_station_type statype)
5380 : : {
5381 [ # # # # ]: 0 : if (params->listen_interval != -1 &&
5382 : : statype != CFG80211_STA_AP_CLIENT_UNASSOC)
5383 : : return -EINVAL;
5384 : :
5385 [ # # # # ]: 0 : if (params->support_p2p_ps != -1 &&
5386 : : statype != CFG80211_STA_AP_CLIENT_UNASSOC)
5387 : : return -EINVAL;
5388 : :
5389 [ # # ]: 0 : if (params->aid &&
5390 [ # # # # ]: 0 : !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
5391 : : statype != CFG80211_STA_AP_CLIENT_UNASSOC)
5392 : : return -EINVAL;
5393 : :
5394 : : /* When you run into this, adjust the code below for the new flag */
5395 : 0 : BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
5396 : :
5397 [ # # # ]: 0 : switch (statype) {
5398 : 0 : case CFG80211_STA_MESH_PEER_KERNEL:
5399 : : case CFG80211_STA_MESH_PEER_USER:
5400 : : /*
5401 : : * No ignoring the TDLS flag here -- the userspace mesh
5402 : : * code doesn't have the bug of including TDLS in the
5403 : : * mask everywhere.
5404 : : */
5405 [ # # ]: 0 : if (params->sta_flags_mask &
5406 : : ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5407 : : BIT(NL80211_STA_FLAG_MFP) |
5408 : : BIT(NL80211_STA_FLAG_AUTHORIZED)))
5409 : : return -EINVAL;
5410 : : break;
5411 : 0 : case CFG80211_STA_TDLS_PEER_SETUP:
5412 : : case CFG80211_STA_TDLS_PEER_ACTIVE:
5413 [ # # ]: 0 : if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
5414 : : return -EINVAL;
5415 : : /* ignore since it can't change */
5416 : 0 : params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
5417 : 0 : break;
5418 : 0 : default:
5419 : : /* disallow mesh-specific things */
5420 [ # # ]: 0 : if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
5421 : : return -EINVAL;
5422 [ # # ]: 0 : if (params->local_pm)
5423 : : return -EINVAL;
5424 [ # # ]: 0 : if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
5425 : : return -EINVAL;
5426 : : }
5427 : :
5428 [ # # ]: 0 : if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
5429 : : statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
5430 : : /* TDLS can't be set, ... */
5431 [ # # ]: 0 : if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
5432 : : return -EINVAL;
5433 : : /*
5434 : : * ... but don't bother the driver with it. This works around
5435 : : * a hostapd/wpa_supplicant issue -- it always includes the
5436 : : * TLDS_PEER flag in the mask even for AP mode.
5437 : : */
5438 : 0 : params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
5439 : : }
5440 : :
5441 : 0 : if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
5442 [ # # ]: 0 : statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
5443 : : /* reject other things that can't change */
5444 [ # # ]: 0 : if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
5445 : : return -EINVAL;
5446 [ # # ]: 0 : if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
5447 : : return -EINVAL;
5448 [ # # ]: 0 : if (params->supported_rates)
5449 : : return -EINVAL;
5450 [ # # # # : 0 : if (params->ext_capab || params->ht_capa || params->vht_capa ||
# # ]
5451 [ # # ]: 0 : params->he_capa)
5452 : : return -EINVAL;
5453 : : }
5454 : :
5455 [ # # ]: 0 : if (statype != CFG80211_STA_AP_CLIENT &&
5456 : : statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
5457 [ # # ]: 0 : if (params->vlan)
5458 : : return -EINVAL;
5459 : : }
5460 : :
5461 [ # # # # : 0 : switch (statype) {
# # # # ]
5462 : 0 : case CFG80211_STA_AP_MLME_CLIENT:
5463 : : /* Use this only for authorizing/unauthorizing a station */
5464 [ # # ]: 0 : if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
5465 : : return -EOPNOTSUPP;
5466 : : break;
5467 : 0 : case CFG80211_STA_AP_CLIENT:
5468 : : case CFG80211_STA_AP_CLIENT_UNASSOC:
5469 : : /* accept only the listed bits */
5470 [ # # ]: 0 : if (params->sta_flags_mask &
5471 : : ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
5472 : : BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5473 : : BIT(NL80211_STA_FLAG_ASSOCIATED) |
5474 : : BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
5475 : : BIT(NL80211_STA_FLAG_WME) |
5476 : : BIT(NL80211_STA_FLAG_MFP)))
5477 : : return -EINVAL;
5478 : :
5479 : : /* but authenticated/associated only if driver handles it */
5480 [ # # # # ]: 0 : if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
5481 : : params->sta_flags_mask &
5482 : : (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5483 : : BIT(NL80211_STA_FLAG_ASSOCIATED)))
5484 : : return -EINVAL;
5485 : : break;
5486 : 0 : case CFG80211_STA_IBSS:
5487 : : case CFG80211_STA_AP_STA:
5488 : : /* reject any changes other than AUTHORIZED */
5489 [ # # ]: 0 : if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
5490 : : return -EINVAL;
5491 : : break;
5492 : 0 : case CFG80211_STA_TDLS_PEER_SETUP:
5493 : : /* reject any changes other than AUTHORIZED or WME */
5494 [ # # ]: 0 : if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
5495 : : BIT(NL80211_STA_FLAG_WME)))
5496 : : return -EINVAL;
5497 : : /* force (at least) rates when authorizing */
5498 [ # # ]: 0 : if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
5499 [ # # ]: 0 : !params->supported_rates)
5500 : : return -EINVAL;
5501 : : break;
5502 : : case CFG80211_STA_TDLS_PEER_ACTIVE:
5503 : : /* reject any changes */
5504 : : return -EINVAL;
5505 : 0 : case CFG80211_STA_MESH_PEER_KERNEL:
5506 [ # # ]: 0 : if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
5507 : : return -EINVAL;
5508 : : break;
5509 : 0 : case CFG80211_STA_MESH_PEER_USER:
5510 [ # # ]: 0 : if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
5511 : : params->plink_action != NL80211_PLINK_ACTION_BLOCK)
5512 : : return -EINVAL;
5513 : : break;
5514 : : }
5515 : :
5516 : : /*
5517 : : * Older kernel versions ignored this attribute entirely, so don't
5518 : : * reject attempts to update it but mark it as unused instead so the
5519 : : * driver won't look at the data.
5520 : : */
5521 [ # # ]: 0 : if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
5522 : : statype != CFG80211_STA_TDLS_PEER_SETUP)
5523 : 0 : params->opmode_notif_used = false;
5524 : :
5525 : : return 0;
5526 : : }
5527 : : EXPORT_SYMBOL(cfg80211_check_station_change);
5528 : :
5529 : : /*
5530 : : * Get vlan interface making sure it is running and on the right wiphy.
5531 : : */
5532 : 0 : static struct net_device *get_vlan(struct genl_info *info,
5533 : : struct cfg80211_registered_device *rdev)
5534 : : {
5535 : 0 : struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
5536 : 0 : struct net_device *v;
5537 : 0 : int ret;
5538 : :
5539 [ # # ]: 0 : if (!vlanattr)
5540 : : return NULL;
5541 : :
5542 : 0 : v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
5543 [ # # ]: 0 : if (!v)
5544 : : return ERR_PTR(-ENODEV);
5545 : :
5546 [ # # # # ]: 0 : if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
5547 : 0 : ret = -EINVAL;
5548 : 0 : goto error;
5549 : : }
5550 : :
5551 : 0 : if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
5552 [ # # ]: 0 : v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
5553 : : v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
5554 : 0 : ret = -EINVAL;
5555 : 0 : goto error;
5556 : : }
5557 : :
5558 [ # # ]: 0 : if (!netif_running(v)) {
5559 : 0 : ret = -ENETDOWN;
5560 : 0 : goto error;
5561 : : }
5562 : :
5563 : : return v;
5564 : 0 : error:
5565 : 0 : dev_put(v);
5566 : 0 : return ERR_PTR(ret);
5567 : : }
5568 : :
5569 : : static const struct nla_policy
5570 : : nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
5571 : : [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
5572 : : [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
5573 : : };
5574 : :
5575 : : static int nl80211_parse_sta_wme(struct genl_info *info,
5576 : : struct station_parameters *params)
5577 : : {
5578 : : struct nlattr *tb[NL80211_STA_WME_MAX + 1];
5579 : : struct nlattr *nla;
5580 : : int err;
5581 : :
5582 : : /* parse WME attributes if present */
5583 : : if (!info->attrs[NL80211_ATTR_STA_WME])
5584 : : return 0;
5585 : :
5586 : : nla = info->attrs[NL80211_ATTR_STA_WME];
5587 : : err = nla_parse_nested_deprecated(tb, NL80211_STA_WME_MAX, nla,
5588 : : nl80211_sta_wme_policy,
5589 : : info->extack);
5590 : : if (err)
5591 : : return err;
5592 : :
5593 : : if (tb[NL80211_STA_WME_UAPSD_QUEUES])
5594 : : params->uapsd_queues = nla_get_u8(
5595 : : tb[NL80211_STA_WME_UAPSD_QUEUES]);
5596 : : if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
5597 : : return -EINVAL;
5598 : :
5599 : : if (tb[NL80211_STA_WME_MAX_SP])
5600 : : params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
5601 : :
5602 : : if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
5603 : : return -EINVAL;
5604 : :
5605 : : params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
5606 : :
5607 : : return 0;
5608 : : }
5609 : :
5610 : : static int nl80211_parse_sta_channel_info(struct genl_info *info,
5611 : : struct station_parameters *params)
5612 : : {
5613 : : if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
5614 : : params->supported_channels =
5615 : : nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
5616 : : params->supported_channels_len =
5617 : : nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
5618 : : /*
5619 : : * Need to include at least one (first channel, number of
5620 : : * channels) tuple for each subband, and must have proper
5621 : : * tuples for the rest of the data as well.
5622 : : */
5623 : : if (params->supported_channels_len < 2)
5624 : : return -EINVAL;
5625 : : if (params->supported_channels_len % 2)
5626 : : return -EINVAL;
5627 : : }
5628 : :
5629 : : if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
5630 : : params->supported_oper_classes =
5631 : : nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
5632 : : params->supported_oper_classes_len =
5633 : : nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
5634 : : /*
5635 : : * The value of the Length field of the Supported Operating
5636 : : * Classes element is between 2 and 253.
5637 : : */
5638 : : if (params->supported_oper_classes_len < 2 ||
5639 : : params->supported_oper_classes_len > 253)
5640 : : return -EINVAL;
5641 : : }
5642 : : return 0;
5643 : : }
5644 : :
5645 : 0 : static int nl80211_set_station_tdls(struct genl_info *info,
5646 : : struct station_parameters *params)
5647 : : {
5648 : 0 : int err;
5649 : : /* Dummy STA entry gets updated once the peer capabilities are known */
5650 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_PEER_AID])
5651 : 0 : params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
5652 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
5653 : 0 : params->ht_capa =
5654 : : nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
5655 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
5656 : 0 : params->vht_capa =
5657 : : nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
5658 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
5659 [ # # ]: 0 : params->he_capa =
5660 : : nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
5661 : 0 : params->he_capa_len =
5662 [ # # ]: 0 : nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
5663 : :
5664 [ # # ]: 0 : if (params->he_capa_len < NL80211_HE_MIN_CAPABILITY_LEN)
5665 : : return -EINVAL;
5666 : : }
5667 : :
5668 : 0 : err = nl80211_parse_sta_channel_info(info, params);
5669 [ # # ]: 0 : if (err)
5670 : : return err;
5671 : :
5672 : 0 : return nl80211_parse_sta_wme(info, params);
5673 : : }
5674 : :
5675 : : static int nl80211_parse_sta_txpower_setting(struct genl_info *info,
5676 : : struct station_parameters *params)
5677 : : {
5678 : : struct cfg80211_registered_device *rdev = info->user_ptr[0];
5679 : : int idx;
5680 : :
5681 : : if (info->attrs[NL80211_ATTR_STA_TX_POWER_SETTING]) {
5682 : : if (!rdev->ops->set_tx_power ||
5683 : : !wiphy_ext_feature_isset(&rdev->wiphy,
5684 : : NL80211_EXT_FEATURE_STA_TX_PWR))
5685 : : return -EOPNOTSUPP;
5686 : :
5687 : : idx = NL80211_ATTR_STA_TX_POWER_SETTING;
5688 : : params->txpwr.type = nla_get_u8(info->attrs[idx]);
5689 : :
5690 : : if (params->txpwr.type == NL80211_TX_POWER_LIMITED) {
5691 : : idx = NL80211_ATTR_STA_TX_POWER;
5692 : :
5693 : : if (info->attrs[idx])
5694 : : params->txpwr.power =
5695 : : nla_get_s16(info->attrs[idx]);
5696 : : else
5697 : : return -EINVAL;
5698 : : }
5699 : : params->sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER;
5700 : : }
5701 : :
5702 : : return 0;
5703 : : }
5704 : :
5705 : 0 : static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
5706 : : {
5707 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
5708 : 0 : struct net_device *dev = info->user_ptr[1];
5709 : 0 : struct station_parameters params;
5710 : 0 : u8 *mac_addr;
5711 : 0 : int err;
5712 : :
5713 : 0 : memset(¶ms, 0, sizeof(params));
5714 : :
5715 [ # # ]: 0 : if (!rdev->ops->change_station)
5716 : : return -EOPNOTSUPP;
5717 : :
5718 : : /*
5719 : : * AID and listen_interval properties can be set only for unassociated
5720 : : * station. Include these parameters here and will check them in
5721 : : * cfg80211_check_station_change().
5722 : : */
5723 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_AID])
5724 : 0 : params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
5725 : :
5726 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_VLAN_ID])
5727 : 0 : params.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);
5728 : :
5729 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
5730 : 0 : params.listen_interval =
5731 : 0 : nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
5732 : : else
5733 : 0 : params.listen_interval = -1;
5734 : :
5735 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS])
5736 : 0 : params.support_p2p_ps =
5737 : 0 : nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
5738 : : else
5739 : 0 : params.support_p2p_ps = -1;
5740 : :
5741 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
5742 : : return -EINVAL;
5743 : :
5744 [ # # ]: 0 : mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
5745 : :
5746 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
5747 : 0 : params.supported_rates =
5748 : : nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5749 : 0 : params.supported_rates_len =
5750 : 0 : nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5751 : : }
5752 : :
5753 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
5754 : 0 : params.capability =
5755 : : nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
5756 : 0 : params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
5757 : : }
5758 : :
5759 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
5760 : 0 : params.ext_capab =
5761 : : nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5762 : 0 : params.ext_capab_len =
5763 : 0 : nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5764 : : }
5765 : :
5766 [ # # ]: 0 : if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms))
5767 : : return -EINVAL;
5768 : :
5769 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
5770 : 0 : params.plink_action =
5771 : : nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
5772 : :
5773 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
5774 [ # # ]: 0 : params.plink_state =
5775 : : nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
5776 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MESH_PEER_AID])
5777 : 0 : params.peer_aid = nla_get_u16(
5778 : : info->attrs[NL80211_ATTR_MESH_PEER_AID]);
5779 : 0 : params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
5780 : : }
5781 : :
5782 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE])
5783 : 0 : params.local_pm = nla_get_u32(
5784 : : info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
5785 : :
5786 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
5787 : 0 : params.opmode_notif_used = true;
5788 : 0 : params.opmode_notif =
5789 : : nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
5790 : : }
5791 : :
5792 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
5793 : 0 : params.airtime_weight =
5794 : : nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
5795 : :
5796 [ # # # # ]: 0 : if (params.airtime_weight &&
5797 : : !wiphy_ext_feature_isset(&rdev->wiphy,
5798 : : NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
5799 : : return -EOPNOTSUPP;
5800 : :
5801 : 0 : err = nl80211_parse_sta_txpower_setting(info, ¶ms);
5802 [ # # ]: 0 : if (err)
5803 : : return err;
5804 : :
5805 : : /* Include parameters for TDLS peer (will check later) */
5806 : 0 : err = nl80211_set_station_tdls(info, ¶ms);
5807 [ # # ]: 0 : if (err)
5808 : : return err;
5809 : :
5810 : 0 : params.vlan = get_vlan(info, rdev);
5811 [ # # ]: 0 : if (IS_ERR(params.vlan))
5812 : 0 : return PTR_ERR(params.vlan);
5813 : :
5814 [ # # ]: 0 : switch (dev->ieee80211_ptr->iftype) {
5815 : : case NL80211_IFTYPE_AP:
5816 : : case NL80211_IFTYPE_AP_VLAN:
5817 : : case NL80211_IFTYPE_P2P_GO:
5818 : : case NL80211_IFTYPE_P2P_CLIENT:
5819 : : case NL80211_IFTYPE_STATION:
5820 : : case NL80211_IFTYPE_ADHOC:
5821 : : case NL80211_IFTYPE_MESH_POINT:
5822 : 0 : break;
5823 : 0 : default:
5824 : 0 : err = -EOPNOTSUPP;
5825 : 0 : goto out_put_vlan;
5826 : : }
5827 : :
5828 : : /* driver will call cfg80211_check_station_change() */
5829 : 0 : err = rdev_change_station(rdev, dev, mac_addr, ¶ms);
5830 : :
5831 : 0 : out_put_vlan:
5832 [ # # ]: 0 : if (params.vlan)
5833 : 0 : dev_put(params.vlan);
5834 : :
5835 : : return err;
5836 : : }
5837 : :
5838 : 0 : static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
5839 : : {
5840 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
5841 : 0 : int err;
5842 : 0 : struct net_device *dev = info->user_ptr[1];
5843 : 0 : struct station_parameters params;
5844 : 0 : u8 *mac_addr = NULL;
5845 : 0 : u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5846 : : BIT(NL80211_STA_FLAG_ASSOCIATED);
5847 : :
5848 : 0 : memset(¶ms, 0, sizeof(params));
5849 : :
5850 [ # # ]: 0 : if (!rdev->ops->add_station)
5851 : : return -EOPNOTSUPP;
5852 : :
5853 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
5854 : : return -EINVAL;
5855 : :
5856 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
5857 : : return -EINVAL;
5858 : :
5859 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
5860 : : return -EINVAL;
5861 : :
5862 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_STA_AID] &&
5863 [ # # ]: 0 : !info->attrs[NL80211_ATTR_PEER_AID])
5864 : : return -EINVAL;
5865 : :
5866 [ # # ]: 0 : mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
5867 : 0 : params.supported_rates =
5868 : : nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5869 : 0 : params.supported_rates_len =
5870 [ # # ]: 0 : nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5871 [ # # ]: 0 : params.listen_interval =
5872 : 0 : nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
5873 : :
5874 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_VLAN_ID])
5875 : 0 : params.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);
5876 : :
5877 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
5878 : 0 : params.support_p2p_ps =
5879 : 0 : nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
5880 : : } else {
5881 : : /*
5882 : : * if not specified, assume it's supported for P2P GO interface,
5883 : : * and is NOT supported for AP interface
5884 : : */
5885 : 0 : params.support_p2p_ps =
5886 : 0 : dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO;
5887 : : }
5888 : :
5889 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_PEER_AID])
5890 : 0 : params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
5891 : : else
5892 : 0 : params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
5893 : :
5894 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
5895 : 0 : params.capability =
5896 : : nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
5897 : 0 : params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
5898 : : }
5899 : :
5900 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
5901 : 0 : params.ext_capab =
5902 : : nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5903 : 0 : params.ext_capab_len =
5904 : 0 : nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5905 : : }
5906 : :
5907 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
5908 : 0 : params.ht_capa =
5909 : : nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
5910 : :
5911 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
5912 : 0 : params.vht_capa =
5913 : : nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
5914 : :
5915 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
5916 [ # # ]: 0 : params.he_capa =
5917 : : nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
5918 : 0 : params.he_capa_len =
5919 [ # # ]: 0 : nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
5920 : :
5921 : : /* max len is validated in nla policy */
5922 [ # # ]: 0 : if (params.he_capa_len < NL80211_HE_MIN_CAPABILITY_LEN)
5923 : : return -EINVAL;
5924 : : }
5925 : :
5926 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
5927 : 0 : params.opmode_notif_used = true;
5928 : 0 : params.opmode_notif =
5929 : : nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
5930 : : }
5931 : :
5932 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
5933 : 0 : params.plink_action =
5934 : : nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
5935 : :
5936 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
5937 : 0 : params.airtime_weight =
5938 : : nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
5939 : :
5940 [ # # # # ]: 0 : if (params.airtime_weight &&
5941 : : !wiphy_ext_feature_isset(&rdev->wiphy,
5942 : : NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
5943 : : return -EOPNOTSUPP;
5944 : :
5945 : 0 : err = nl80211_parse_sta_txpower_setting(info, ¶ms);
5946 [ # # ]: 0 : if (err)
5947 : : return err;
5948 : :
5949 : 0 : err = nl80211_parse_sta_channel_info(info, ¶ms);
5950 [ # # ]: 0 : if (err)
5951 : : return err;
5952 : :
5953 : 0 : err = nl80211_parse_sta_wme(info, ¶ms);
5954 [ # # ]: 0 : if (err)
5955 : : return err;
5956 : :
5957 [ # # ]: 0 : if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms))
5958 : : return -EINVAL;
5959 : :
5960 : : /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
5961 : : * as userspace might just pass through the capabilities from the IEs
5962 : : * directly, rather than enforcing this restriction and returning an
5963 : : * error in this case.
5964 : : */
5965 [ # # ]: 0 : if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
5966 : 0 : params.ht_capa = NULL;
5967 : 0 : params.vht_capa = NULL;
5968 : :
5969 : : /* HE requires WME */
5970 [ # # ]: 0 : if (params.he_capa_len)
5971 : : return -EINVAL;
5972 : : }
5973 : :
5974 : : /* When you run into this, adjust the code below for the new flag */
5975 : 0 : BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
5976 : :
5977 [ # # # # ]: 0 : switch (dev->ieee80211_ptr->iftype) {
5978 : 0 : case NL80211_IFTYPE_AP:
5979 : : case NL80211_IFTYPE_AP_VLAN:
5980 : : case NL80211_IFTYPE_P2P_GO:
5981 : : /* ignore WME attributes if iface/sta is not capable */
5982 [ # # # # ]: 0 : if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
5983 : : !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
5984 : 0 : params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5985 : :
5986 : : /* TDLS peers cannot be added */
5987 [ # # ]: 0 : if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5988 [ # # ]: 0 : info->attrs[NL80211_ATTR_PEER_AID])
5989 : : return -EINVAL;
5990 : : /* but don't bother the driver with it */
5991 : 0 : params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
5992 : :
5993 : : /* allow authenticated/associated only if driver handles it */
5994 [ # # ]: 0 : if (!(rdev->wiphy.features &
5995 : 0 : NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
5996 [ # # ]: 0 : params.sta_flags_mask & auth_assoc)
5997 : : return -EINVAL;
5998 : :
5999 : : /* Older userspace, or userspace wanting to be compatible with
6000 : : * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
6001 : : * and assoc flags in the mask, but assumes the station will be
6002 : : * added as associated anyway since this was the required driver
6003 : : * behaviour before NL80211_FEATURE_FULL_AP_CLIENT_STATE was
6004 : : * introduced.
6005 : : * In order to not bother drivers with this quirk in the API
6006 : : * set the flags in both the mask and set for new stations in
6007 : : * this case.
6008 : : */
6009 [ # # ]: 0 : if (!(params.sta_flags_mask & auth_assoc)) {
6010 : 0 : params.sta_flags_mask |= auth_assoc;
6011 : 0 : params.sta_flags_set |= auth_assoc;
6012 : : }
6013 : :
6014 : : /* must be last in here for error handling */
6015 : 0 : params.vlan = get_vlan(info, rdev);
6016 [ # # ]: 0 : if (IS_ERR(params.vlan))
6017 : 0 : return PTR_ERR(params.vlan);
6018 : : break;
6019 : 0 : case NL80211_IFTYPE_MESH_POINT:
6020 : : /* ignore uAPSD data */
6021 : 0 : params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
6022 : :
6023 : : /* associated is disallowed */
6024 [ # # ]: 0 : if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
6025 : : return -EINVAL;
6026 : : /* TDLS peers cannot be added */
6027 [ # # ]: 0 : if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
6028 [ # # ]: 0 : info->attrs[NL80211_ATTR_PEER_AID])
6029 : : return -EINVAL;
6030 : : break;
6031 : 0 : case NL80211_IFTYPE_STATION:
6032 : : case NL80211_IFTYPE_P2P_CLIENT:
6033 : : /* ignore uAPSD data */
6034 : 0 : params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
6035 : :
6036 : : /* these are disallowed */
6037 [ # # ]: 0 : if (params.sta_flags_mask &
6038 : : (BIT(NL80211_STA_FLAG_ASSOCIATED) |
6039 : : BIT(NL80211_STA_FLAG_AUTHENTICATED)))
6040 : : return -EINVAL;
6041 : : /* Only TDLS peers can be added */
6042 [ # # ]: 0 : if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
6043 : : return -EINVAL;
6044 : : /* Can only add if TDLS ... */
6045 [ # # ]: 0 : if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
6046 : : return -EOPNOTSUPP;
6047 : : /* ... with external setup is supported */
6048 [ # # ]: 0 : if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
6049 : : return -EOPNOTSUPP;
6050 : : /*
6051 : : * Older wpa_supplicant versions always mark the TDLS peer
6052 : : * as authorized, but it shouldn't yet be.
6053 : : */
6054 : 0 : params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
6055 : 0 : break;
6056 : : default:
6057 : : return -EOPNOTSUPP;
6058 : : }
6059 : :
6060 : : /* be aware of params.vlan when changing code here */
6061 : :
6062 : 0 : err = rdev_add_station(rdev, dev, mac_addr, ¶ms);
6063 : :
6064 [ # # ]: 0 : if (params.vlan)
6065 : 0 : dev_put(params.vlan);
6066 : : return err;
6067 : : }
6068 : :
6069 : 0 : static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
6070 : : {
6071 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
6072 : 0 : struct net_device *dev = info->user_ptr[1];
6073 : 0 : struct station_del_parameters params;
6074 : :
6075 : 0 : memset(¶ms, 0, sizeof(params));
6076 : :
6077 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MAC])
6078 : 0 : params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
6079 : :
6080 : 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
6081 [ # # ]: 0 : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
6082 [ # # ]: 0 : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
6083 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
6084 : : return -EINVAL;
6085 : :
6086 [ # # ]: 0 : if (!rdev->ops->del_station)
6087 : : return -EOPNOTSUPP;
6088 : :
6089 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
6090 [ # # ]: 0 : params.subtype =
6091 : : nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
6092 [ # # ]: 0 : if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
6093 : : params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
6094 : : return -EINVAL;
6095 : : } else {
6096 : : /* Default to Deauthentication frame */
6097 : 0 : params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
6098 : : }
6099 : :
6100 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_REASON_CODE]) {
6101 [ # # ]: 0 : params.reason_code =
6102 : : nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
6103 [ # # ]: 0 : if (params.reason_code == 0)
6104 : : return -EINVAL; /* 0 is reserved */
6105 : : } else {
6106 : : /* Default to reason code 2 */
6107 : 0 : params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
6108 : : }
6109 : :
6110 : 0 : return rdev_del_station(rdev, dev, ¶ms);
6111 : : }
6112 : :
6113 : : static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
6114 : : int flags, struct net_device *dev,
6115 : : u8 *dst, u8 *next_hop,
6116 : : struct mpath_info *pinfo)
6117 : : {
6118 : : void *hdr;
6119 : : struct nlattr *pinfoattr;
6120 : :
6121 : : hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH);
6122 : : if (!hdr)
6123 : : return -1;
6124 : :
6125 : : if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
6126 : : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
6127 : : nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
6128 : : nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
6129 : : goto nla_put_failure;
6130 : :
6131 : : pinfoattr = nla_nest_start_noflag(msg, NL80211_ATTR_MPATH_INFO);
6132 : : if (!pinfoattr)
6133 : : goto nla_put_failure;
6134 : : if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
6135 : : nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
6136 : : pinfo->frame_qlen))
6137 : : goto nla_put_failure;
6138 : : if (((pinfo->filled & MPATH_INFO_SN) &&
6139 : : nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
6140 : : ((pinfo->filled & MPATH_INFO_METRIC) &&
6141 : : nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
6142 : : pinfo->metric)) ||
6143 : : ((pinfo->filled & MPATH_INFO_EXPTIME) &&
6144 : : nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
6145 : : pinfo->exptime)) ||
6146 : : ((pinfo->filled & MPATH_INFO_FLAGS) &&
6147 : : nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
6148 : : pinfo->flags)) ||
6149 : : ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
6150 : : nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
6151 : : pinfo->discovery_timeout)) ||
6152 : : ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
6153 : : nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
6154 : : pinfo->discovery_retries)) ||
6155 : : ((pinfo->filled & MPATH_INFO_HOP_COUNT) &&
6156 : : nla_put_u8(msg, NL80211_MPATH_INFO_HOP_COUNT,
6157 : : pinfo->hop_count)) ||
6158 : : ((pinfo->filled & MPATH_INFO_PATH_CHANGE) &&
6159 : : nla_put_u32(msg, NL80211_MPATH_INFO_PATH_CHANGE,
6160 : : pinfo->path_change_count)))
6161 : : goto nla_put_failure;
6162 : :
6163 : : nla_nest_end(msg, pinfoattr);
6164 : :
6165 : : genlmsg_end(msg, hdr);
6166 : : return 0;
6167 : :
6168 : : nla_put_failure:
6169 : : genlmsg_cancel(msg, hdr);
6170 : : return -EMSGSIZE;
6171 : : }
6172 : :
6173 : 0 : static int nl80211_dump_mpath(struct sk_buff *skb,
6174 : : struct netlink_callback *cb)
6175 : : {
6176 : 0 : struct mpath_info pinfo;
6177 : 0 : struct cfg80211_registered_device *rdev;
6178 : 0 : struct wireless_dev *wdev;
6179 : 0 : u8 dst[ETH_ALEN];
6180 : 0 : u8 next_hop[ETH_ALEN];
6181 : 0 : int path_idx = cb->args[2];
6182 : 0 : int err;
6183 : :
6184 : 0 : rtnl_lock();
6185 : 0 : err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
6186 [ # # ]: 0 : if (err)
6187 : 0 : goto out_err;
6188 : :
6189 [ # # ]: 0 : if (!rdev->ops->dump_mpath) {
6190 : 0 : err = -EOPNOTSUPP;
6191 : 0 : goto out_err;
6192 : : }
6193 : :
6194 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
6195 : 0 : err = -EOPNOTSUPP;
6196 : 0 : goto out_err;
6197 : : }
6198 : :
6199 : 0 : while (1) {
6200 : 0 : err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
6201 : : next_hop, &pinfo);
6202 [ # # ]: 0 : if (err == -ENOENT)
6203 : : break;
6204 [ # # ]: 0 : if (err)
6205 : 0 : goto out_err;
6206 : :
6207 [ # # ]: 0 : if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
6208 : 0 : cb->nlh->nlmsg_seq, NLM_F_MULTI,
6209 : 0 : wdev->netdev, dst, next_hop,
6210 : : &pinfo) < 0)
6211 : 0 : goto out;
6212 : :
6213 : 0 : path_idx++;
6214 : : }
6215 : :
6216 : 0 : out:
6217 : 0 : cb->args[2] = path_idx;
6218 : 0 : err = skb->len;
6219 : 0 : out_err:
6220 : 0 : rtnl_unlock();
6221 : 0 : return err;
6222 : : }
6223 : :
6224 : 0 : static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
6225 : : {
6226 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
6227 : 0 : int err;
6228 : 0 : struct net_device *dev = info->user_ptr[1];
6229 : 0 : struct mpath_info pinfo;
6230 : 0 : struct sk_buff *msg;
6231 : 0 : u8 *dst = NULL;
6232 : 0 : u8 next_hop[ETH_ALEN];
6233 : :
6234 : 0 : memset(&pinfo, 0, sizeof(pinfo));
6235 : :
6236 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
6237 : : return -EINVAL;
6238 : :
6239 [ # # ]: 0 : dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
6240 : :
6241 [ # # ]: 0 : if (!rdev->ops->get_mpath)
6242 : : return -EOPNOTSUPP;
6243 : :
6244 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
6245 : : return -EOPNOTSUPP;
6246 : :
6247 : 0 : err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
6248 [ # # ]: 0 : if (err)
6249 : : return err;
6250 : :
6251 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6252 [ # # ]: 0 : if (!msg)
6253 : : return -ENOMEM;
6254 : :
6255 [ # # ]: 0 : if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
6256 : : dev, dst, next_hop, &pinfo) < 0) {
6257 : 0 : nlmsg_free(msg);
6258 : 0 : return -ENOBUFS;
6259 : : }
6260 : :
6261 : 0 : return genlmsg_reply(msg, info);
6262 : : }
6263 : :
6264 : 0 : static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
6265 : : {
6266 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
6267 : 0 : struct net_device *dev = info->user_ptr[1];
6268 : 0 : u8 *dst = NULL;
6269 : 0 : u8 *next_hop = NULL;
6270 : :
6271 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
6272 : : return -EINVAL;
6273 : :
6274 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
6275 : : return -EINVAL;
6276 : :
6277 [ # # ]: 0 : dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
6278 : 0 : next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
6279 : :
6280 [ # # ]: 0 : if (!rdev->ops->change_mpath)
6281 : : return -EOPNOTSUPP;
6282 : :
6283 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
6284 : : return -EOPNOTSUPP;
6285 : :
6286 : 0 : return rdev_change_mpath(rdev, dev, dst, next_hop);
6287 : : }
6288 : :
6289 : 0 : static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
6290 : : {
6291 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
6292 : 0 : struct net_device *dev = info->user_ptr[1];
6293 : 0 : u8 *dst = NULL;
6294 : 0 : u8 *next_hop = NULL;
6295 : :
6296 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
6297 : : return -EINVAL;
6298 : :
6299 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
6300 : : return -EINVAL;
6301 : :
6302 [ # # ]: 0 : dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
6303 : 0 : next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
6304 : :
6305 [ # # ]: 0 : if (!rdev->ops->add_mpath)
6306 : : return -EOPNOTSUPP;
6307 : :
6308 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
6309 : : return -EOPNOTSUPP;
6310 : :
6311 : 0 : return rdev_add_mpath(rdev, dev, dst, next_hop);
6312 : : }
6313 : :
6314 : 0 : static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
6315 : : {
6316 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
6317 : 0 : struct net_device *dev = info->user_ptr[1];
6318 : 0 : u8 *dst = NULL;
6319 : :
6320 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MAC])
6321 : 0 : dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
6322 : :
6323 [ # # ]: 0 : if (!rdev->ops->del_mpath)
6324 : : return -EOPNOTSUPP;
6325 : :
6326 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
6327 : : return -EOPNOTSUPP;
6328 : :
6329 : 0 : return rdev_del_mpath(rdev, dev, dst);
6330 : : }
6331 : :
6332 : 0 : static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
6333 : : {
6334 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
6335 : 0 : int err;
6336 : 0 : struct net_device *dev = info->user_ptr[1];
6337 : 0 : struct mpath_info pinfo;
6338 : 0 : struct sk_buff *msg;
6339 : 0 : u8 *dst = NULL;
6340 : 0 : u8 mpp[ETH_ALEN];
6341 : :
6342 : 0 : memset(&pinfo, 0, sizeof(pinfo));
6343 : :
6344 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
6345 : : return -EINVAL;
6346 : :
6347 [ # # ]: 0 : dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
6348 : :
6349 [ # # ]: 0 : if (!rdev->ops->get_mpp)
6350 : : return -EOPNOTSUPP;
6351 : :
6352 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
6353 : : return -EOPNOTSUPP;
6354 : :
6355 : 0 : err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
6356 [ # # ]: 0 : if (err)
6357 : : return err;
6358 : :
6359 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6360 [ # # ]: 0 : if (!msg)
6361 : : return -ENOMEM;
6362 : :
6363 [ # # ]: 0 : if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
6364 : : dev, dst, mpp, &pinfo) < 0) {
6365 : 0 : nlmsg_free(msg);
6366 : 0 : return -ENOBUFS;
6367 : : }
6368 : :
6369 : 0 : return genlmsg_reply(msg, info);
6370 : : }
6371 : :
6372 : 0 : static int nl80211_dump_mpp(struct sk_buff *skb,
6373 : : struct netlink_callback *cb)
6374 : : {
6375 : 0 : struct mpath_info pinfo;
6376 : 0 : struct cfg80211_registered_device *rdev;
6377 : 0 : struct wireless_dev *wdev;
6378 : 0 : u8 dst[ETH_ALEN];
6379 : 0 : u8 mpp[ETH_ALEN];
6380 : 0 : int path_idx = cb->args[2];
6381 : 0 : int err;
6382 : :
6383 : 0 : rtnl_lock();
6384 : 0 : err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
6385 [ # # ]: 0 : if (err)
6386 : 0 : goto out_err;
6387 : :
6388 [ # # ]: 0 : if (!rdev->ops->dump_mpp) {
6389 : 0 : err = -EOPNOTSUPP;
6390 : 0 : goto out_err;
6391 : : }
6392 : :
6393 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
6394 : 0 : err = -EOPNOTSUPP;
6395 : 0 : goto out_err;
6396 : : }
6397 : :
6398 : 0 : while (1) {
6399 : 0 : err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
6400 : : mpp, &pinfo);
6401 [ # # ]: 0 : if (err == -ENOENT)
6402 : : break;
6403 [ # # ]: 0 : if (err)
6404 : 0 : goto out_err;
6405 : :
6406 [ # # ]: 0 : if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
6407 : 0 : cb->nlh->nlmsg_seq, NLM_F_MULTI,
6408 : 0 : wdev->netdev, dst, mpp,
6409 : : &pinfo) < 0)
6410 : 0 : goto out;
6411 : :
6412 : 0 : path_idx++;
6413 : : }
6414 : :
6415 : 0 : out:
6416 : 0 : cb->args[2] = path_idx;
6417 : 0 : err = skb->len;
6418 : 0 : out_err:
6419 : 0 : rtnl_unlock();
6420 : 0 : return err;
6421 : : }
6422 : :
6423 : 0 : static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
6424 : : {
6425 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
6426 : 0 : struct net_device *dev = info->user_ptr[1];
6427 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
6428 : 0 : struct bss_parameters params;
6429 : 0 : int err;
6430 : :
6431 : 0 : memset(¶ms, 0, sizeof(params));
6432 : : /* default to not changing parameters */
6433 : 0 : params.use_cts_prot = -1;
6434 : 0 : params.use_short_preamble = -1;
6435 : 0 : params.use_short_slot_time = -1;
6436 : 0 : params.ap_isolate = -1;
6437 : 0 : params.ht_opmode = -1;
6438 : 0 : params.p2p_ctwindow = -1;
6439 : 0 : params.p2p_opp_ps = -1;
6440 : :
6441 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
6442 : 0 : params.use_cts_prot =
6443 : 0 : nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
6444 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
6445 : 0 : params.use_short_preamble =
6446 : 0 : nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
6447 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
6448 : 0 : params.use_short_slot_time =
6449 : 0 : nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
6450 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
6451 : 0 : params.basic_rates =
6452 : : nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
6453 : 0 : params.basic_rates_len =
6454 : 0 : nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
6455 : : }
6456 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_AP_ISOLATE])
6457 : 0 : params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
6458 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
6459 : 0 : params.ht_opmode =
6460 : 0 : nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
6461 : :
6462 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
6463 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
6464 : : return -EINVAL;
6465 [ # # ]: 0 : params.p2p_ctwindow =
6466 : 0 : nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
6467 [ # # ]: 0 : if (params.p2p_ctwindow != 0 &&
6468 [ # # ]: 0 : !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
6469 : : return -EINVAL;
6470 : : }
6471 : :
6472 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
6473 : 0 : u8 tmp;
6474 : :
6475 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
6476 : : return -EINVAL;
6477 [ # # ]: 0 : tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
6478 : 0 : params.p2p_opp_ps = tmp;
6479 [ # # ]: 0 : if (params.p2p_opp_ps &&
6480 [ # # ]: 0 : !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
6481 : : return -EINVAL;
6482 : : }
6483 : :
6484 [ # # ]: 0 : if (!rdev->ops->change_bss)
6485 : : return -EOPNOTSUPP;
6486 : :
6487 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
6488 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
6489 : : return -EOPNOTSUPP;
6490 : :
6491 : 0 : wdev_lock(wdev);
6492 : 0 : err = rdev_change_bss(rdev, dev, ¶ms);
6493 : 0 : wdev_unlock(wdev);
6494 : :
6495 : 0 : return err;
6496 : : }
6497 : :
6498 : 0 : static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
6499 : : {
6500 : 0 : char *data = NULL;
6501 : 0 : bool is_indoor;
6502 : 0 : enum nl80211_user_reg_hint_type user_reg_hint_type;
6503 : 0 : u32 owner_nlportid;
6504 : :
6505 : : /*
6506 : : * You should only get this when cfg80211 hasn't yet initialized
6507 : : * completely when built-in to the kernel right between the time
6508 : : * window between nl80211_init() and regulatory_init(), if that is
6509 : : * even possible.
6510 : : */
6511 [ # # ]: 0 : if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
6512 : : return -EINPROGRESS;
6513 : :
6514 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
6515 [ # # # ]: 0 : user_reg_hint_type =
6516 : : nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
6517 : : else
6518 : : user_reg_hint_type = NL80211_USER_REG_HINT_USER;
6519 : :
6520 [ # # # ]: 0 : switch (user_reg_hint_type) {
6521 : 0 : case NL80211_USER_REG_HINT_USER:
6522 : : case NL80211_USER_REG_HINT_CELL_BASE:
6523 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
6524 : : return -EINVAL;
6525 : :
6526 : 0 : data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
6527 : 0 : return regulatory_hint_user(data, user_reg_hint_type);
6528 : 0 : case NL80211_USER_REG_HINT_INDOOR:
6529 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
6530 : 0 : owner_nlportid = info->snd_portid;
6531 : 0 : is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
6532 : : } else {
6533 : : owner_nlportid = 0;
6534 : : is_indoor = true;
6535 : : }
6536 : :
6537 : 0 : return regulatory_hint_indoor(is_indoor, owner_nlportid);
6538 : : default:
6539 : : return -EINVAL;
6540 : : }
6541 : : }
6542 : :
6543 : 0 : static int nl80211_reload_regdb(struct sk_buff *skb, struct genl_info *info)
6544 : : {
6545 : 0 : return reg_reload_regdb();
6546 : : }
6547 : :
6548 : 0 : static int nl80211_get_mesh_config(struct sk_buff *skb,
6549 : : struct genl_info *info)
6550 : : {
6551 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
6552 : 0 : struct net_device *dev = info->user_ptr[1];
6553 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
6554 : 0 : struct mesh_config cur_params;
6555 : 0 : int err = 0;
6556 : 0 : void *hdr;
6557 : 0 : struct nlattr *pinfoattr;
6558 : 0 : struct sk_buff *msg;
6559 : :
6560 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
6561 : : return -EOPNOTSUPP;
6562 : :
6563 [ # # ]: 0 : if (!rdev->ops->get_mesh_config)
6564 : : return -EOPNOTSUPP;
6565 : :
6566 : 0 : wdev_lock(wdev);
6567 : : /* If not connected, get default parameters */
6568 [ # # ]: 0 : if (!wdev->mesh_id_len)
6569 : 0 : memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
6570 : : else
6571 : 0 : err = rdev_get_mesh_config(rdev, dev, &cur_params);
6572 : 0 : wdev_unlock(wdev);
6573 : :
6574 [ # # ]: 0 : if (err)
6575 : : return err;
6576 : :
6577 : : /* Draw up a netlink message to send back */
6578 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6579 [ # # ]: 0 : if (!msg)
6580 : : return -ENOMEM;
6581 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
6582 : : NL80211_CMD_GET_MESH_CONFIG);
6583 [ # # ]: 0 : if (!hdr)
6584 : 0 : goto out;
6585 : 0 : pinfoattr = nla_nest_start_noflag(msg, NL80211_ATTR_MESH_CONFIG);
6586 [ # # ]: 0 : if (!pinfoattr)
6587 : 0 : goto nla_put_failure;
6588 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
6589 : : nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
6590 [ # # ]: 0 : cur_params.dot11MeshRetryTimeout) ||
6591 : : nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
6592 [ # # ]: 0 : cur_params.dot11MeshConfirmTimeout) ||
6593 : : nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
6594 [ # # ]: 0 : cur_params.dot11MeshHoldingTimeout) ||
6595 : : nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
6596 [ # # ]: 0 : cur_params.dot11MeshMaxPeerLinks) ||
6597 : : nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
6598 [ # # ]: 0 : cur_params.dot11MeshMaxRetries) ||
6599 : : nla_put_u8(msg, NL80211_MESHCONF_TTL,
6600 [ # # ]: 0 : cur_params.dot11MeshTTL) ||
6601 : : nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
6602 [ # # ]: 0 : cur_params.element_ttl) ||
6603 : : nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
6604 [ # # ]: 0 : cur_params.auto_open_plinks) ||
6605 : 0 : nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
6606 [ # # ]: 0 : cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
6607 : : nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
6608 [ # # ]: 0 : cur_params.dot11MeshHWMPmaxPREQretries) ||
6609 : 0 : nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
6610 [ # # ]: 0 : cur_params.path_refresh_time) ||
6611 : : nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
6612 [ # # ]: 0 : cur_params.min_discovery_timeout) ||
6613 : 0 : nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
6614 [ # # ]: 0 : cur_params.dot11MeshHWMPactivePathTimeout) ||
6615 : : nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
6616 [ # # ]: 0 : cur_params.dot11MeshHWMPpreqMinInterval) ||
6617 : : nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
6618 [ # # ]: 0 : cur_params.dot11MeshHWMPperrMinInterval) ||
6619 : : nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
6620 [ # # ]: 0 : cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
6621 : : nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
6622 [ # # ]: 0 : cur_params.dot11MeshHWMPRootMode) ||
6623 : : nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
6624 [ # # ]: 0 : cur_params.dot11MeshHWMPRannInterval) ||
6625 : : nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
6626 [ # # ]: 0 : cur_params.dot11MeshGateAnnouncementProtocol) ||
6627 : : nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
6628 [ # # ]: 0 : cur_params.dot11MeshForwarding) ||
6629 : 0 : nla_put_s32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
6630 [ # # ]: 0 : cur_params.rssi_threshold) ||
6631 : 0 : nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
6632 [ # # ]: 0 : cur_params.ht_opmode) ||
6633 : 0 : nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
6634 [ # # ]: 0 : cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
6635 : : nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
6636 [ # # ]: 0 : cur_params.dot11MeshHWMProotInterval) ||
6637 : : nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
6638 [ # # ]: 0 : cur_params.dot11MeshHWMPconfirmationInterval) ||
6639 : : nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
6640 [ # # ]: 0 : cur_params.power_mode) ||
6641 : : nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
6642 [ # # ]: 0 : cur_params.dot11MeshAwakeWindowDuration) ||
6643 : 0 : nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
6644 [ # # ]: 0 : cur_params.plink_timeout) ||
6645 : : nla_put_u8(msg, NL80211_MESHCONF_CONNECTED_TO_GATE,
6646 : 0 : cur_params.dot11MeshConnectedToMeshGate))
6647 : 0 : goto nla_put_failure;
6648 : 0 : nla_nest_end(msg, pinfoattr);
6649 : 0 : genlmsg_end(msg, hdr);
6650 : 0 : return genlmsg_reply(msg, info);
6651 : :
6652 : 0 : nla_put_failure:
6653 : 0 : out:
6654 : 0 : nlmsg_free(msg);
6655 : 0 : return -ENOBUFS;
6656 : : }
6657 : :
6658 : : static const struct nla_policy
6659 : : nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
6660 : : [NL80211_MESHCONF_RETRY_TIMEOUT] =
6661 : : NLA_POLICY_RANGE(NLA_U16, 1, 255),
6662 : : [NL80211_MESHCONF_CONFIRM_TIMEOUT] =
6663 : : NLA_POLICY_RANGE(NLA_U16, 1, 255),
6664 : : [NL80211_MESHCONF_HOLDING_TIMEOUT] =
6665 : : NLA_POLICY_RANGE(NLA_U16, 1, 255),
6666 : : [NL80211_MESHCONF_MAX_PEER_LINKS] =
6667 : : NLA_POLICY_RANGE(NLA_U16, 0, 255),
6668 : : [NL80211_MESHCONF_MAX_RETRIES] = NLA_POLICY_MAX(NLA_U8, 16),
6669 : : [NL80211_MESHCONF_TTL] = NLA_POLICY_MIN(NLA_U8, 1),
6670 : : [NL80211_MESHCONF_ELEMENT_TTL] = NLA_POLICY_MIN(NLA_U8, 1),
6671 : : [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = NLA_POLICY_MAX(NLA_U8, 1),
6672 : : [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] =
6673 : : NLA_POLICY_RANGE(NLA_U32, 1, 255),
6674 : : [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
6675 : : [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
6676 : : [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = NLA_POLICY_MIN(NLA_U16, 1),
6677 : : [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
6678 : : [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] =
6679 : : NLA_POLICY_MIN(NLA_U16, 1),
6680 : : [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] =
6681 : : NLA_POLICY_MIN(NLA_U16, 1),
6682 : : [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] =
6683 : : NLA_POLICY_MIN(NLA_U16, 1),
6684 : : [NL80211_MESHCONF_HWMP_ROOTMODE] = NLA_POLICY_MAX(NLA_U8, 4),
6685 : : [NL80211_MESHCONF_HWMP_RANN_INTERVAL] =
6686 : : NLA_POLICY_MIN(NLA_U16, 1),
6687 : : [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = NLA_POLICY_MAX(NLA_U8, 1),
6688 : : [NL80211_MESHCONF_FORWARDING] = NLA_POLICY_MAX(NLA_U8, 1),
6689 : : [NL80211_MESHCONF_RSSI_THRESHOLD] =
6690 : : NLA_POLICY_RANGE(NLA_S32, -255, 0),
6691 : : [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
6692 : : [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
6693 : : [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] =
6694 : : NLA_POLICY_MIN(NLA_U16, 1),
6695 : : [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] =
6696 : : NLA_POLICY_MIN(NLA_U16, 1),
6697 : : [NL80211_MESHCONF_POWER_MODE] =
6698 : : NLA_POLICY_RANGE(NLA_U32,
6699 : : NL80211_MESH_POWER_ACTIVE,
6700 : : NL80211_MESH_POWER_MAX),
6701 : : [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
6702 : : [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
6703 : : [NL80211_MESHCONF_CONNECTED_TO_GATE] = NLA_POLICY_RANGE(NLA_U8, 0, 1),
6704 : : };
6705 : :
6706 : : static const struct nla_policy
6707 : : nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
6708 : : [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
6709 : : [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
6710 : : [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
6711 : : [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
6712 : : [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 },
6713 : : [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
6714 : : [NL80211_MESH_SETUP_IE] =
6715 : : NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
6716 : : IEEE80211_MAX_DATA_LEN),
6717 : : [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
6718 : : };
6719 : :
6720 : : static int nl80211_parse_mesh_config(struct genl_info *info,
6721 : : struct mesh_config *cfg,
6722 : : u32 *mask_out)
6723 : : {
6724 : : struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
6725 : : u32 mask = 0;
6726 : : u16 ht_opmode;
6727 : :
6728 : : #define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, mask, attr, fn) \
6729 : : do { \
6730 : : if (tb[attr]) { \
6731 : : cfg->param = fn(tb[attr]); \
6732 : : mask |= BIT((attr) - 1); \
6733 : : } \
6734 : : } while (0)
6735 : :
6736 : : if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
6737 : : return -EINVAL;
6738 : : if (nla_parse_nested_deprecated(tb, NL80211_MESHCONF_ATTR_MAX, info->attrs[NL80211_ATTR_MESH_CONFIG], nl80211_meshconf_params_policy, info->extack))
6739 : : return -EINVAL;
6740 : :
6741 : : /* This makes sure that there aren't more than 32 mesh config
6742 : : * parameters (otherwise our bitfield scheme would not work.) */
6743 : : BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
6744 : :
6745 : : /* Fill in the params struct */
6746 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, mask,
6747 : : NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16);
6748 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, mask,
6749 : : NL80211_MESHCONF_CONFIRM_TIMEOUT,
6750 : : nla_get_u16);
6751 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, mask,
6752 : : NL80211_MESHCONF_HOLDING_TIMEOUT,
6753 : : nla_get_u16);
6754 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, mask,
6755 : : NL80211_MESHCONF_MAX_PEER_LINKS,
6756 : : nla_get_u16);
6757 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, mask,
6758 : : NL80211_MESHCONF_MAX_RETRIES, nla_get_u8);
6759 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, mask,
6760 : : NL80211_MESHCONF_TTL, nla_get_u8);
6761 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, mask,
6762 : : NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8);
6763 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, mask,
6764 : : NL80211_MESHCONF_AUTO_OPEN_PLINKS,
6765 : : nla_get_u8);
6766 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
6767 : : mask,
6768 : : NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
6769 : : nla_get_u32);
6770 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, mask,
6771 : : NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
6772 : : nla_get_u8);
6773 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, mask,
6774 : : NL80211_MESHCONF_PATH_REFRESH_TIME,
6775 : : nla_get_u32);
6776 : : if (mask & BIT(NL80211_MESHCONF_PATH_REFRESH_TIME) &&
6777 : : (cfg->path_refresh_time < 1 || cfg->path_refresh_time > 65535))
6778 : : return -EINVAL;
6779 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, mask,
6780 : : NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
6781 : : nla_get_u16);
6782 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
6783 : : mask,
6784 : : NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
6785 : : nla_get_u32);
6786 : : if (mask & BIT(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT) &&
6787 : : (cfg->dot11MeshHWMPactivePathTimeout < 1 ||
6788 : : cfg->dot11MeshHWMPactivePathTimeout > 65535))
6789 : : return -EINVAL;
6790 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, mask,
6791 : : NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
6792 : : nla_get_u16);
6793 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, mask,
6794 : : NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
6795 : : nla_get_u16);
6796 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
6797 : : dot11MeshHWMPnetDiameterTraversalTime, mask,
6798 : : NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
6799 : : nla_get_u16);
6800 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask,
6801 : : NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8);
6802 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask,
6803 : : NL80211_MESHCONF_HWMP_RANN_INTERVAL,
6804 : : nla_get_u16);
6805 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshGateAnnouncementProtocol,
6806 : : mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
6807 : : nla_get_u8);
6808 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, mask,
6809 : : NL80211_MESHCONF_FORWARDING, nla_get_u8);
6810 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, mask,
6811 : : NL80211_MESHCONF_RSSI_THRESHOLD,
6812 : : nla_get_s32);
6813 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConnectedToMeshGate, mask,
6814 : : NL80211_MESHCONF_CONNECTED_TO_GATE,
6815 : : nla_get_u8);
6816 : : /*
6817 : : * Check HT operation mode based on
6818 : : * IEEE 802.11-2016 9.4.2.57 HT Operation element.
6819 : : */
6820 : : if (tb[NL80211_MESHCONF_HT_OPMODE]) {
6821 : : ht_opmode = nla_get_u16(tb[NL80211_MESHCONF_HT_OPMODE]);
6822 : :
6823 : : if (ht_opmode & ~(IEEE80211_HT_OP_MODE_PROTECTION |
6824 : : IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
6825 : : IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
6826 : : return -EINVAL;
6827 : :
6828 : : /* NON_HT_STA bit is reserved, but some programs set it */
6829 : : ht_opmode &= ~IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT;
6830 : :
6831 : : cfg->ht_opmode = ht_opmode;
6832 : : mask |= (1 << (NL80211_MESHCONF_HT_OPMODE - 1));
6833 : : }
6834 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
6835 : : dot11MeshHWMPactivePathToRootTimeout, mask,
6836 : : NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
6837 : : nla_get_u32);
6838 : : if (mask & BIT(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT) &&
6839 : : (cfg->dot11MeshHWMPactivePathToRootTimeout < 1 ||
6840 : : cfg->dot11MeshHWMPactivePathToRootTimeout > 65535))
6841 : : return -EINVAL;
6842 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, mask,
6843 : : NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
6844 : : nla_get_u16);
6845 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPconfirmationInterval,
6846 : : mask,
6847 : : NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
6848 : : nla_get_u16);
6849 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode, mask,
6850 : : NL80211_MESHCONF_POWER_MODE, nla_get_u32);
6851 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, mask,
6852 : : NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
6853 : : FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, mask,
6854 : : NL80211_MESHCONF_PLINK_TIMEOUT, nla_get_u32);
6855 : : if (mask_out)
6856 : : *mask_out = mask;
6857 : :
6858 : : return 0;
6859 : :
6860 : : #undef FILL_IN_MESH_PARAM_IF_SET
6861 : : }
6862 : :
6863 : 0 : static int nl80211_parse_mesh_setup(struct genl_info *info,
6864 : : struct mesh_setup *setup)
6865 : : {
6866 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
6867 : 0 : struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
6868 : :
6869 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MESH_SETUP])
6870 : : return -EINVAL;
6871 [ # # ]: 0 : if (nla_parse_nested_deprecated(tb, NL80211_MESH_SETUP_ATTR_MAX, info->attrs[NL80211_ATTR_MESH_SETUP], nl80211_mesh_setup_params_policy, info->extack))
6872 : : return -EINVAL;
6873 : :
6874 [ # # ]: 0 : if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
6875 [ # # ]: 0 : setup->sync_method =
6876 : : (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
6877 : : IEEE80211_SYNC_METHOD_VENDOR :
6878 : : IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
6879 : :
6880 [ # # ]: 0 : if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
6881 [ # # ]: 0 : setup->path_sel_proto =
6882 : : (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
6883 : : IEEE80211_PATH_PROTOCOL_VENDOR :
6884 : : IEEE80211_PATH_PROTOCOL_HWMP;
6885 : :
6886 [ # # ]: 0 : if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
6887 [ # # ]: 0 : setup->path_metric =
6888 : : (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
6889 : : IEEE80211_PATH_METRIC_VENDOR :
6890 : : IEEE80211_PATH_METRIC_AIRTIME;
6891 : :
6892 [ # # ]: 0 : if (tb[NL80211_MESH_SETUP_IE]) {
6893 : 0 : struct nlattr *ieattr =
6894 : : tb[NL80211_MESH_SETUP_IE];
6895 : 0 : setup->ie = nla_data(ieattr);
6896 : 0 : setup->ie_len = nla_len(ieattr);
6897 : : }
6898 [ # # ]: 0 : if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
6899 [ # # ]: 0 : !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
6900 : : return -EINVAL;
6901 [ # # ]: 0 : setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
6902 : 0 : setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
6903 : 0 : setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
6904 [ # # ]: 0 : if (setup->is_secure)
6905 : 0 : setup->user_mpm = true;
6906 : :
6907 [ # # ]: 0 : if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) {
6908 [ # # ]: 0 : if (!setup->user_mpm)
6909 : : return -EINVAL;
6910 : 0 : setup->auth_id =
6911 : : nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]);
6912 : : }
6913 : :
6914 : : return 0;
6915 : : }
6916 : :
6917 : 0 : static int nl80211_update_mesh_config(struct sk_buff *skb,
6918 : : struct genl_info *info)
6919 : : {
6920 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
6921 : 0 : struct net_device *dev = info->user_ptr[1];
6922 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
6923 : 0 : struct mesh_config cfg;
6924 : 0 : u32 mask;
6925 : 0 : int err;
6926 : :
6927 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
6928 : : return -EOPNOTSUPP;
6929 : :
6930 [ # # ]: 0 : if (!rdev->ops->update_mesh_config)
6931 : : return -EOPNOTSUPP;
6932 : :
6933 : 0 : err = nl80211_parse_mesh_config(info, &cfg, &mask);
6934 [ # # ]: 0 : if (err)
6935 : : return err;
6936 : :
6937 : 0 : wdev_lock(wdev);
6938 [ # # ]: 0 : if (!wdev->mesh_id_len)
6939 : : err = -ENOLINK;
6940 : :
6941 : 0 : if (!err)
6942 : 0 : err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
6943 : :
6944 : 0 : wdev_unlock(wdev);
6945 : :
6946 : 0 : return err;
6947 : : }
6948 : :
6949 : 0 : static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
6950 : : struct sk_buff *msg)
6951 : : {
6952 : 0 : struct nlattr *nl_reg_rules;
6953 : 0 : unsigned int i;
6954 : :
6955 [ # # ]: 0 : if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
6956 [ # # # # ]: 0 : (regdom->dfs_region &&
6957 : 0 : nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
6958 : 0 : goto nla_put_failure;
6959 : :
6960 : 0 : nl_reg_rules = nla_nest_start_noflag(msg, NL80211_ATTR_REG_RULES);
6961 [ # # ]: 0 : if (!nl_reg_rules)
6962 : 0 : goto nla_put_failure;
6963 : :
6964 [ # # ]: 0 : for (i = 0; i < regdom->n_reg_rules; i++) {
6965 : 0 : struct nlattr *nl_reg_rule;
6966 : 0 : const struct ieee80211_reg_rule *reg_rule;
6967 : 0 : const struct ieee80211_freq_range *freq_range;
6968 : 0 : const struct ieee80211_power_rule *power_rule;
6969 : 0 : unsigned int max_bandwidth_khz;
6970 : :
6971 : 0 : reg_rule = ®dom->reg_rules[i];
6972 : 0 : freq_range = ®_rule->freq_range;
6973 : 0 : power_rule = ®_rule->power_rule;
6974 : :
6975 : 0 : nl_reg_rule = nla_nest_start_noflag(msg, i);
6976 [ # # ]: 0 : if (!nl_reg_rule)
6977 : 0 : goto nla_put_failure;
6978 : :
6979 : 0 : max_bandwidth_khz = freq_range->max_bandwidth_khz;
6980 [ # # ]: 0 : if (!max_bandwidth_khz)
6981 : 0 : max_bandwidth_khz = reg_get_max_bandwidth(regdom,
6982 : : reg_rule);
6983 : :
6984 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
6985 [ # # ]: 0 : reg_rule->flags) ||
6986 : 0 : nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
6987 [ # # ]: 0 : freq_range->start_freq_khz) ||
6988 : 0 : nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
6989 [ # # ]: 0 : freq_range->end_freq_khz) ||
6990 : : nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
6991 [ # # ]: 0 : max_bandwidth_khz) ||
6992 : 0 : nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
6993 [ # # ]: 0 : power_rule->max_antenna_gain) ||
6994 : 0 : nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
6995 [ # # ]: 0 : power_rule->max_eirp) ||
6996 : 0 : nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
6997 : : reg_rule->dfs_cac_ms))
6998 : 0 : goto nla_put_failure;
6999 : :
7000 : 0 : nla_nest_end(msg, nl_reg_rule);
7001 : : }
7002 : :
7003 : 0 : nla_nest_end(msg, nl_reg_rules);
7004 : 0 : return 0;
7005 : :
7006 : : nla_put_failure:
7007 : : return -EMSGSIZE;
7008 : : }
7009 : :
7010 : 0 : static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
7011 : : {
7012 : 0 : const struct ieee80211_regdomain *regdom = NULL;
7013 : 0 : struct cfg80211_registered_device *rdev;
7014 : 0 : struct wiphy *wiphy = NULL;
7015 : 0 : struct sk_buff *msg;
7016 : 0 : void *hdr;
7017 : :
7018 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7019 [ # # ]: 0 : if (!msg)
7020 : : return -ENOBUFS;
7021 : :
7022 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
7023 : : NL80211_CMD_GET_REG);
7024 [ # # ]: 0 : if (!hdr)
7025 : 0 : goto put_failure;
7026 : :
7027 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY]) {
7028 : 0 : bool self_managed;
7029 : :
7030 : 0 : rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
7031 [ # # ]: 0 : if (IS_ERR(rdev)) {
7032 : 0 : nlmsg_free(msg);
7033 : 0 : return PTR_ERR(rdev);
7034 : : }
7035 : :
7036 : 0 : wiphy = &rdev->wiphy;
7037 : 0 : self_managed = wiphy->regulatory_flags &
7038 : : REGULATORY_WIPHY_SELF_MANAGED;
7039 : 0 : regdom = get_wiphy_regdom(wiphy);
7040 : :
7041 : : /* a self-managed-reg device must have a private regdom */
7042 [ # # # # ]: 0 : if (WARN_ON(!regdom && self_managed)) {
7043 : 0 : nlmsg_free(msg);
7044 : 0 : return -EINVAL;
7045 : : }
7046 : :
7047 [ # # # # ]: 0 : if (regdom &&
7048 : 0 : nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
7049 : 0 : goto nla_put_failure;
7050 : : }
7051 : :
7052 [ # # # # : 0 : if (!wiphy && reg_last_request_cell_base() &&
# # ]
7053 : : nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
7054 : : NL80211_USER_REG_HINT_CELL_BASE))
7055 : 0 : goto nla_put_failure;
7056 : :
7057 : 0 : rcu_read_lock();
7058 : :
7059 [ # # ]: 0 : if (!regdom)
7060 : 0 : regdom = rcu_dereference(cfg80211_regdomain);
7061 : :
7062 [ # # ]: 0 : if (nl80211_put_regdom(regdom, msg))
7063 : 0 : goto nla_put_failure_rcu;
7064 : :
7065 : 0 : rcu_read_unlock();
7066 : :
7067 : 0 : genlmsg_end(msg, hdr);
7068 : 0 : return genlmsg_reply(msg, info);
7069 : :
7070 : : nla_put_failure_rcu:
7071 : 0 : rcu_read_unlock();
7072 : 0 : nla_put_failure:
7073 : 0 : put_failure:
7074 : 0 : nlmsg_free(msg);
7075 : 0 : return -EMSGSIZE;
7076 : : }
7077 : :
7078 : 0 : static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
7079 : : u32 seq, int flags, struct wiphy *wiphy,
7080 : : const struct ieee80211_regdomain *regdom)
7081 : : {
7082 : 0 : void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
7083 : : NL80211_CMD_GET_REG);
7084 : :
7085 [ # # ]: 0 : if (!hdr)
7086 : : return -1;
7087 : :
7088 [ # # ]: 0 : genl_dump_check_consistent(cb, hdr);
7089 : :
7090 [ # # ]: 0 : if (nl80211_put_regdom(regdom, msg))
7091 : 0 : goto nla_put_failure;
7092 : :
7093 [ # # # # : 0 : if (!wiphy && reg_last_request_cell_base() &&
# # ]
7094 : : nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
7095 : : NL80211_USER_REG_HINT_CELL_BASE))
7096 : 0 : goto nla_put_failure;
7097 : :
7098 [ # # # # ]: 0 : if (wiphy &&
7099 : 0 : nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
7100 : 0 : goto nla_put_failure;
7101 : :
7102 [ # # # # : 0 : if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
# # ]
7103 : : nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
7104 : 0 : goto nla_put_failure;
7105 : :
7106 : 0 : genlmsg_end(msg, hdr);
7107 : 0 : return 0;
7108 : :
7109 : 0 : nla_put_failure:
7110 : 0 : genlmsg_cancel(msg, hdr);
7111 : 0 : return -EMSGSIZE;
7112 : : }
7113 : :
7114 : 0 : static int nl80211_get_reg_dump(struct sk_buff *skb,
7115 : : struct netlink_callback *cb)
7116 : : {
7117 : 0 : const struct ieee80211_regdomain *regdom = NULL;
7118 : 0 : struct cfg80211_registered_device *rdev;
7119 : 0 : int err, reg_idx, start = cb->args[2];
7120 : :
7121 : 0 : rtnl_lock();
7122 : :
7123 [ # # # # ]: 0 : if (cfg80211_regdomain && start == 0) {
7124 : 0 : err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
7125 : : NLM_F_MULTI, NULL,
7126 : 0 : rtnl_dereference(cfg80211_regdomain));
7127 [ # # ]: 0 : if (err < 0)
7128 : 0 : goto out_err;
7129 : : }
7130 : :
7131 : : /* the global regdom is idx 0 */
7132 : 0 : reg_idx = 1;
7133 [ # # ]: 0 : list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
7134 : 0 : regdom = get_wiphy_regdom(&rdev->wiphy);
7135 [ # # ]: 0 : if (!regdom)
7136 : 0 : continue;
7137 : :
7138 [ # # ]: 0 : if (++reg_idx <= start)
7139 : 0 : continue;
7140 : :
7141 : 0 : err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
7142 : : NLM_F_MULTI, &rdev->wiphy, regdom);
7143 [ # # ]: 0 : if (err < 0) {
7144 : : reg_idx--;
7145 : : break;
7146 : : }
7147 : : }
7148 : :
7149 : 0 : cb->args[2] = reg_idx;
7150 : 0 : err = skb->len;
7151 : 0 : out_err:
7152 : 0 : rtnl_unlock();
7153 : 0 : return err;
7154 : : }
7155 : :
7156 : : #ifdef CONFIG_CFG80211_CRDA_SUPPORT
7157 : : static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
7158 : : [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
7159 : : [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
7160 : : [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
7161 : : [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
7162 : : [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
7163 : : [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
7164 : : [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
7165 : : };
7166 : :
7167 : 0 : static int parse_reg_rule(struct nlattr *tb[],
7168 : : struct ieee80211_reg_rule *reg_rule)
7169 : : {
7170 : 0 : struct ieee80211_freq_range *freq_range = ®_rule->freq_range;
7171 : 0 : struct ieee80211_power_rule *power_rule = ®_rule->power_rule;
7172 : :
7173 [ # # ]: 0 : if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
7174 : : return -EINVAL;
7175 [ # # ]: 0 : if (!tb[NL80211_ATTR_FREQ_RANGE_START])
7176 : : return -EINVAL;
7177 [ # # ]: 0 : if (!tb[NL80211_ATTR_FREQ_RANGE_END])
7178 : : return -EINVAL;
7179 [ # # ]: 0 : if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
7180 : : return -EINVAL;
7181 [ # # ]: 0 : if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
7182 : : return -EINVAL;
7183 : :
7184 [ # # ]: 0 : reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
7185 : :
7186 : 0 : freq_range->start_freq_khz =
7187 : 0 : nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
7188 : 0 : freq_range->end_freq_khz =
7189 : 0 : nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
7190 : 0 : freq_range->max_bandwidth_khz =
7191 : 0 : nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
7192 : :
7193 : 0 : power_rule->max_eirp =
7194 : 0 : nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
7195 : :
7196 [ # # ]: 0 : if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
7197 : 0 : power_rule->max_antenna_gain =
7198 : : nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
7199 : :
7200 [ # # ]: 0 : if (tb[NL80211_ATTR_DFS_CAC_TIME])
7201 : 0 : reg_rule->dfs_cac_ms =
7202 : : nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
7203 : :
7204 : : return 0;
7205 : : }
7206 : :
7207 : 0 : static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
7208 : : {
7209 : 0 : struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
7210 : 0 : struct nlattr *nl_reg_rule;
7211 : 0 : char *alpha2;
7212 : 0 : int rem_reg_rules, r;
7213 : 0 : u32 num_rules = 0, rule_idx = 0;
7214 : 0 : enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
7215 : 0 : struct ieee80211_regdomain *rd;
7216 : :
7217 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
7218 : : return -EINVAL;
7219 : :
7220 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_REG_RULES])
7221 : : return -EINVAL;
7222 : :
7223 [ # # ]: 0 : alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
7224 : :
7225 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_DFS_REGION])
7226 : 0 : dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
7227 : :
7228 [ # # ]: 0 : nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
7229 : : rem_reg_rules) {
7230 : 0 : num_rules++;
7231 [ # # ]: 0 : if (num_rules > NL80211_MAX_SUPP_REG_RULES)
7232 : : return -EINVAL;
7233 : : }
7234 : :
7235 [ # # ]: 0 : if (!reg_is_valid_request(alpha2))
7236 : : return -EINVAL;
7237 : :
7238 [ # # ]: 0 : rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL);
7239 [ # # ]: 0 : if (!rd)
7240 : : return -ENOMEM;
7241 : :
7242 : 0 : rd->n_reg_rules = num_rules;
7243 : 0 : rd->alpha2[0] = alpha2[0];
7244 : 0 : rd->alpha2[1] = alpha2[1];
7245 : :
7246 : : /*
7247 : : * Disable DFS master mode if the DFS region was
7248 : : * not supported or known on this kernel.
7249 : : */
7250 [ # # ]: 0 : if (reg_supported_dfs_region(dfs_region))
7251 : 0 : rd->dfs_region = dfs_region;
7252 : :
7253 [ # # ]: 0 : nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
7254 : : rem_reg_rules) {
7255 : 0 : r = nla_parse_nested_deprecated(tb, NL80211_REG_RULE_ATTR_MAX,
7256 : : nl_reg_rule, reg_rule_policy,
7257 : : info->extack);
7258 [ # # ]: 0 : if (r)
7259 : 0 : goto bad_reg;
7260 : 0 : r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
7261 [ # # ]: 0 : if (r)
7262 : 0 : goto bad_reg;
7263 : :
7264 : 0 : rule_idx++;
7265 : :
7266 [ # # ]: 0 : if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
7267 : 0 : r = -EINVAL;
7268 : 0 : goto bad_reg;
7269 : : }
7270 : : }
7271 : :
7272 : : /* set_regdom takes ownership of rd */
7273 : 0 : return set_regdom(rd, REGD_SOURCE_CRDA);
7274 : 0 : bad_reg:
7275 : 0 : kfree(rd);
7276 : 0 : return r;
7277 : : }
7278 : : #endif /* CONFIG_CFG80211_CRDA_SUPPORT */
7279 : :
7280 : 0 : static int validate_scan_freqs(struct nlattr *freqs)
7281 : : {
7282 : 0 : struct nlattr *attr1, *attr2;
7283 : 0 : int n_channels = 0, tmp1, tmp2;
7284 : :
7285 [ # # ]: 0 : nla_for_each_nested(attr1, freqs, tmp1)
7286 [ # # ]: 0 : if (nla_len(attr1) != sizeof(u32))
7287 : : return 0;
7288 : :
7289 [ # # ]: 0 : nla_for_each_nested(attr1, freqs, tmp1) {
7290 : 0 : n_channels++;
7291 : : /*
7292 : : * Some hardware has a limited channel list for
7293 : : * scanning, and it is pretty much nonsensical
7294 : : * to scan for a channel twice, so disallow that
7295 : : * and don't require drivers to check that the
7296 : : * channel list they get isn't longer than what
7297 : : * they can scan, as long as they can scan all
7298 : : * the channels they registered at once.
7299 : : */
7300 [ # # ]: 0 : nla_for_each_nested(attr2, freqs, tmp2)
7301 [ # # # # ]: 0 : if (attr1 != attr2 &&
7302 : : nla_get_u32(attr1) == nla_get_u32(attr2))
7303 : : return 0;
7304 : : }
7305 : :
7306 : : return n_channels;
7307 : : }
7308 : :
7309 : 0 : static bool is_band_valid(struct wiphy *wiphy, enum nl80211_band b)
7310 : : {
7311 [ # # # # : 0 : return b < NUM_NL80211_BANDS && wiphy->bands[b];
# # ]
7312 : : }
7313 : :
7314 : 0 : static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
7315 : : struct cfg80211_bss_selection *bss_select)
7316 : : {
7317 : 0 : struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
7318 : 0 : struct nlattr *nest;
7319 : 0 : int err;
7320 : 0 : bool found = false;
7321 : 0 : int i;
7322 : :
7323 : : /* only process one nested attribute */
7324 [ # # ]: 0 : nest = nla_data(nla);
7325 [ # # ]: 0 : if (!nla_ok(nest, nla_len(nest)))
7326 : : return -EINVAL;
7327 : :
7328 : 0 : err = nla_parse_nested_deprecated(attr, NL80211_BSS_SELECT_ATTR_MAX,
7329 : : nest, nl80211_bss_select_policy,
7330 : : NULL);
7331 [ # # ]: 0 : if (err)
7332 : : return err;
7333 : :
7334 : : /* only one attribute may be given */
7335 [ # # ]: 0 : for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
7336 [ # # ]: 0 : if (attr[i]) {
7337 [ # # ]: 0 : if (found)
7338 : : return -EINVAL;
7339 : : found = true;
7340 : : }
7341 : : }
7342 : :
7343 : 0 : bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
7344 : :
7345 [ # # ]: 0 : if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
7346 : 0 : bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
7347 : :
7348 [ # # ]: 0 : if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
7349 : 0 : bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
7350 [ # # ]: 0 : bss_select->param.band_pref =
7351 : : nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
7352 [ # # # # ]: 0 : if (!is_band_valid(wiphy, bss_select->param.band_pref))
7353 : : return -EINVAL;
7354 : : }
7355 : :
7356 [ # # ]: 0 : if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
7357 : 0 : struct nl80211_bss_select_rssi_adjust *adj_param;
7358 : :
7359 [ # # ]: 0 : adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
7360 : 0 : bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
7361 : 0 : bss_select->param.adjust.band = adj_param->band;
7362 : 0 : bss_select->param.adjust.delta = adj_param->delta;
7363 [ # # # # ]: 0 : if (!is_band_valid(wiphy, bss_select->param.adjust.band))
7364 : : return -EINVAL;
7365 : : }
7366 : :
7367 : : /* user-space did not provide behaviour attribute */
7368 [ # # ]: 0 : if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
7369 : : return -EINVAL;
7370 : :
7371 [ # # ]: 0 : if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
7372 : 0 : return -EINVAL;
7373 : :
7374 : : return 0;
7375 : : }
7376 : :
7377 : 0 : int nl80211_parse_random_mac(struct nlattr **attrs,
7378 : : u8 *mac_addr, u8 *mac_addr_mask)
7379 : : {
7380 : 0 : int i;
7381 : :
7382 [ # # # # ]: 0 : if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
7383 : 0 : eth_zero_addr(mac_addr);
7384 : 0 : eth_zero_addr(mac_addr_mask);
7385 : 0 : mac_addr[0] = 0x2;
7386 : 0 : mac_addr_mask[0] = 0x3;
7387 : :
7388 : 0 : return 0;
7389 : : }
7390 : :
7391 : : /* need both or none */
7392 [ # # # # ]: 0 : if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
7393 : : return -EINVAL;
7394 : :
7395 [ # # ]: 0 : memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
7396 : 0 : memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
7397 : :
7398 : : /* don't allow or configure an mcast address */
7399 [ # # # # ]: 0 : if (!is_multicast_ether_addr(mac_addr_mask) ||
7400 : : is_multicast_ether_addr(mac_addr))
7401 : : return -EINVAL;
7402 : :
7403 : : /*
7404 : : * allow users to pass a MAC address that has bits set outside
7405 : : * of the mask, but don't bother drivers with having to deal
7406 : : * with such bits
7407 : : */
7408 [ # # ]: 0 : for (i = 0; i < ETH_ALEN; i++)
7409 : 0 : mac_addr[i] &= mac_addr_mask[i];
7410 : :
7411 : : return 0;
7412 : : }
7413 : :
7414 : 0 : static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
7415 : : {
7416 : 0 : ASSERT_WDEV_LOCK(wdev);
7417 : :
7418 [ # # ]: 0 : if (!cfg80211_beaconing_iface_active(wdev))
7419 : : return true;
7420 : :
7421 [ # # ]: 0 : if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
7422 : : return true;
7423 : :
7424 : 0 : return regulatory_pre_cac_allowed(wdev->wiphy);
7425 : : }
7426 : :
7427 : 0 : static bool nl80211_check_scan_feat(struct wiphy *wiphy, u32 flags, u32 flag,
7428 : : enum nl80211_ext_feature_index feat)
7429 : : {
7430 [ # # # # : 0 : if (!(flags & flag))
# # # # #
# # # # #
# # # # ]
7431 : : return true;
7432 [ # # # # : 0 : if (wiphy_ext_feature_isset(wiphy, feat))
# # # # #
# # # # #
# # # # ]
7433 : : return true;
7434 : : return false;
7435 : : }
7436 : :
7437 : : static int
7438 : 0 : nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
7439 : : void *request, struct nlattr **attrs,
7440 : : bool is_sched_scan)
7441 : : {
7442 : 0 : u8 *mac_addr, *mac_addr_mask;
7443 : 0 : u32 *flags;
7444 : 0 : enum nl80211_feature_flags randomness_flag;
7445 : :
7446 [ # # ]: 0 : if (!attrs[NL80211_ATTR_SCAN_FLAGS])
7447 : : return 0;
7448 : :
7449 [ # # ]: 0 : if (is_sched_scan) {
7450 : 0 : struct cfg80211_sched_scan_request *req = request;
7451 : :
7452 : 0 : randomness_flag = wdev ?
7453 [ # # ]: 0 : NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR :
7454 : : NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7455 : 0 : flags = &req->flags;
7456 : 0 : mac_addr = req->mac_addr;
7457 : 0 : mac_addr_mask = req->mac_addr_mask;
7458 : : } else {
7459 : 0 : struct cfg80211_scan_request *req = request;
7460 : :
7461 : 0 : randomness_flag = NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
7462 : 0 : flags = &req->flags;
7463 : 0 : mac_addr = req->mac_addr;
7464 : 0 : mac_addr_mask = req->mac_addr_mask;
7465 : : }
7466 : :
7467 [ # # ]: 0 : *flags = nla_get_u32(attrs[NL80211_ATTR_SCAN_FLAGS]);
7468 : :
7469 [ # # ]: 0 : if (((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
7470 [ # # ]: 0 : !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
7471 : : !nl80211_check_scan_feat(wiphy, *flags,
7472 : : NL80211_SCAN_FLAG_LOW_SPAN,
7473 : : NL80211_EXT_FEATURE_LOW_SPAN_SCAN) ||
7474 : : !nl80211_check_scan_feat(wiphy, *flags,
7475 : : NL80211_SCAN_FLAG_LOW_POWER,
7476 : : NL80211_EXT_FEATURE_LOW_POWER_SCAN) ||
7477 : : !nl80211_check_scan_feat(wiphy, *flags,
7478 : : NL80211_SCAN_FLAG_HIGH_ACCURACY,
7479 : : NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN) ||
7480 : : !nl80211_check_scan_feat(wiphy, *flags,
7481 : : NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME,
7482 : : NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME) ||
7483 : : !nl80211_check_scan_feat(wiphy, *flags,
7484 : : NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP,
7485 : : NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP) ||
7486 : : !nl80211_check_scan_feat(wiphy, *flags,
7487 : : NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
7488 : : NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) ||
7489 : : !nl80211_check_scan_feat(wiphy, *flags,
7490 : : NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE,
7491 : : NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE) ||
7492 : : !nl80211_check_scan_feat(wiphy, *flags,
7493 : : NL80211_SCAN_FLAG_RANDOM_SN,
7494 : : NL80211_EXT_FEATURE_SCAN_RANDOM_SN) ||
7495 : : !nl80211_check_scan_feat(wiphy, *flags,
7496 : : NL80211_SCAN_FLAG_MIN_PREQ_CONTENT,
7497 : : NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT))
7498 : : return -EOPNOTSUPP;
7499 : :
7500 [ # # ]: 0 : if (*flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
7501 : 0 : int err;
7502 : :
7503 [ # # # # ]: 0 : if (!(wiphy->features & randomness_flag) ||
7504 [ # # ]: 0 : (wdev && wdev->current_bss))
7505 : : return -EOPNOTSUPP;
7506 : :
7507 : 0 : err = nl80211_parse_random_mac(attrs, mac_addr, mac_addr_mask);
7508 [ # # ]: 0 : if (err)
7509 : 0 : return err;
7510 : : }
7511 : :
7512 : : return 0;
7513 : : }
7514 : :
7515 : 0 : static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
7516 : : {
7517 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
7518 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
7519 : 0 : struct cfg80211_scan_request *request;
7520 : 0 : struct nlattr *attr;
7521 : 0 : struct wiphy *wiphy;
7522 : 0 : int err, tmp, n_ssids = 0, n_channels, i;
7523 : 0 : size_t ie_len;
7524 : :
7525 : 0 : wiphy = &rdev->wiphy;
7526 : :
7527 [ # # ]: 0 : if (wdev->iftype == NL80211_IFTYPE_NAN)
7528 : : return -EOPNOTSUPP;
7529 : :
7530 [ # # ]: 0 : if (!rdev->ops->scan)
7531 : : return -EOPNOTSUPP;
7532 : :
7533 [ # # # # ]: 0 : if (rdev->scan_req || rdev->scan_msg) {
7534 : 0 : err = -EBUSY;
7535 : 0 : goto unlock;
7536 : : }
7537 : :
7538 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
7539 : 0 : n_channels = validate_scan_freqs(
7540 : : info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
7541 [ # # ]: 0 : if (!n_channels) {
7542 : 0 : err = -EINVAL;
7543 : 0 : goto unlock;
7544 : : }
7545 : : } else {
7546 : 0 : n_channels = ieee80211_get_num_supported_channels(wiphy);
7547 : : }
7548 : :
7549 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
7550 [ # # ]: 0 : nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
7551 : 0 : n_ssids++;
7552 : :
7553 [ # # ]: 0 : if (n_ssids > wiphy->max_scan_ssids) {
7554 : 0 : err = -EINVAL;
7555 : 0 : goto unlock;
7556 : : }
7557 : :
7558 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IE])
7559 : 0 : ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
7560 : : else
7561 : : ie_len = 0;
7562 : :
7563 [ # # ]: 0 : if (ie_len > wiphy->max_scan_ie_len) {
7564 : 0 : err = -EINVAL;
7565 : 0 : goto unlock;
7566 : : }
7567 : :
7568 : 0 : request = kzalloc(sizeof(*request)
7569 : 0 : + sizeof(*request->ssids) * n_ssids
7570 : 0 : + sizeof(*request->channels) * n_channels
7571 : 0 : + ie_len, GFP_KERNEL);
7572 [ # # ]: 0 : if (!request) {
7573 : 0 : err = -ENOMEM;
7574 : 0 : goto unlock;
7575 : : }
7576 : :
7577 [ # # ]: 0 : if (n_ssids)
7578 : 0 : request->ssids = (void *)&request->channels[n_channels];
7579 : 0 : request->n_ssids = n_ssids;
7580 [ # # ]: 0 : if (ie_len) {
7581 [ # # ]: 0 : if (n_ssids)
7582 : 0 : request->ie = (void *)(request->ssids + n_ssids);
7583 : : else
7584 : 0 : request->ie = (void *)(request->channels + n_channels);
7585 : : }
7586 : :
7587 : 0 : i = 0;
7588 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
7589 : : /* user specified, bail out if channel not found */
7590 [ # # ]: 0 : nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
7591 : 0 : struct ieee80211_channel *chan;
7592 : :
7593 : 0 : chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
7594 : :
7595 [ # # ]: 0 : if (!chan) {
7596 : 0 : err = -EINVAL;
7597 : 0 : goto out_free;
7598 : : }
7599 : :
7600 : : /* ignore disabled channels */
7601 [ # # ]: 0 : if (chan->flags & IEEE80211_CHAN_DISABLED)
7602 : 0 : continue;
7603 : :
7604 : 0 : request->channels[i] = chan;
7605 : 0 : i++;
7606 : : }
7607 : : } else {
7608 : : enum nl80211_band band;
7609 : :
7610 : : /* all channels */
7611 [ # # ]: 0 : for (band = 0; band < NUM_NL80211_BANDS; band++) {
7612 : 0 : int j;
7613 : :
7614 [ # # ]: 0 : if (!wiphy->bands[band])
7615 : 0 : continue;
7616 [ # # ]: 0 : for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
7617 : 0 : struct ieee80211_channel *chan;
7618 : :
7619 : 0 : chan = &wiphy->bands[band]->channels[j];
7620 : :
7621 [ # # ]: 0 : if (chan->flags & IEEE80211_CHAN_DISABLED)
7622 : 0 : continue;
7623 : :
7624 : 0 : request->channels[i] = chan;
7625 : 0 : i++;
7626 : : }
7627 : : }
7628 : : }
7629 : :
7630 [ # # ]: 0 : if (!i) {
7631 : 0 : err = -EINVAL;
7632 : 0 : goto out_free;
7633 : : }
7634 : :
7635 : 0 : request->n_channels = i;
7636 : :
7637 : 0 : wdev_lock(wdev);
7638 [ # # ]: 0 : if (!cfg80211_off_channel_oper_allowed(wdev)) {
7639 : 0 : struct ieee80211_channel *chan;
7640 : :
7641 [ # # ]: 0 : if (request->n_channels != 1) {
7642 : 0 : wdev_unlock(wdev);
7643 : 0 : err = -EBUSY;
7644 : 0 : goto out_free;
7645 : : }
7646 : :
7647 : 0 : chan = request->channels[0];
7648 [ # # ]: 0 : if (chan->center_freq != wdev->chandef.chan->center_freq) {
7649 : 0 : wdev_unlock(wdev);
7650 : 0 : err = -EBUSY;
7651 : 0 : goto out_free;
7652 : : }
7653 : : }
7654 : 0 : wdev_unlock(wdev);
7655 : :
7656 : 0 : i = 0;
7657 [ # # ]: 0 : if (n_ssids) {
7658 [ # # ]: 0 : nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
7659 [ # # ]: 0 : if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
7660 : 0 : err = -EINVAL;
7661 : 0 : goto out_free;
7662 : : }
7663 : 0 : request->ssids[i].ssid_len = nla_len(attr);
7664 : 0 : memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
7665 : 0 : i++;
7666 : : }
7667 : : }
7668 : :
7669 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IE]) {
7670 : 0 : request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
7671 : 0 : memcpy((void *)request->ie,
7672 : 0 : nla_data(info->attrs[NL80211_ATTR_IE]),
7673 : : request->ie_len);
7674 : : }
7675 : :
7676 [ # # ]: 0 : for (i = 0; i < NUM_NL80211_BANDS; i++)
7677 [ # # ]: 0 : if (wiphy->bands[i])
7678 : 0 : request->rates[i] =
7679 : 0 : (1 << wiphy->bands[i]->n_bitrates) - 1;
7680 : :
7681 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
7682 [ # # ]: 0 : nla_for_each_nested(attr,
7683 : : info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
7684 : : tmp) {
7685 [ # # ]: 0 : enum nl80211_band band = nla_type(attr);
7686 : :
7687 [ # # ]: 0 : if (band < 0 || band >= NUM_NL80211_BANDS) {
7688 : 0 : err = -EINVAL;
7689 : 0 : goto out_free;
7690 : : }
7691 : :
7692 [ # # ]: 0 : if (!wiphy->bands[band])
7693 : 0 : continue;
7694 : :
7695 : 0 : err = ieee80211_get_ratemask(wiphy->bands[band],
7696 : : nla_data(attr),
7697 : : nla_len(attr),
7698 : : &request->rates[band]);
7699 [ # # ]: 0 : if (err)
7700 : 0 : goto out_free;
7701 : : }
7702 : : }
7703 : :
7704 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
7705 [ # # ]: 0 : if (!wiphy_ext_feature_isset(wiphy,
7706 : : NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
7707 : 0 : err = -EOPNOTSUPP;
7708 : 0 : goto out_free;
7709 : : }
7710 : :
7711 : 0 : request->duration =
7712 : : nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
7713 : 0 : request->duration_mandatory =
7714 : 0 : nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
7715 : : }
7716 : :
7717 : 0 : err = nl80211_check_scan_flags(wiphy, wdev, request, info->attrs,
7718 : : false);
7719 [ # # ]: 0 : if (err)
7720 : 0 : goto out_free;
7721 : :
7722 : 0 : request->no_cck =
7723 [ # # ]: 0 : nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
7724 : :
7725 : : /* Initial implementation used NL80211_ATTR_MAC to set the specific
7726 : : * BSSID to scan for. This was problematic because that same attribute
7727 : : * was already used for another purpose (local random MAC address). The
7728 : : * NL80211_ATTR_BSSID attribute was added to fix this. For backwards
7729 : : * compatibility with older userspace components, also use the
7730 : : * NL80211_ATTR_MAC value here if it can be determined to be used for
7731 : : * the specific BSSID use case instead of the random MAC address
7732 : : * (NL80211_ATTR_SCAN_FLAGS is used to enable random MAC address use).
7733 : : */
7734 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BSSID])
7735 : 0 : memcpy(request->bssid,
7736 : : nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
7737 [ # # ]: 0 : else if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
7738 [ # # ]: 0 : info->attrs[NL80211_ATTR_MAC])
7739 : 0 : memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
7740 : : ETH_ALEN);
7741 : : else
7742 : 0 : eth_broadcast_addr(request->bssid);
7743 : :
7744 : 0 : request->wdev = wdev;
7745 : 0 : request->wiphy = &rdev->wiphy;
7746 : 0 : request->scan_start = jiffies;
7747 : :
7748 : 0 : rdev->scan_req = request;
7749 : 0 : err = rdev_scan(rdev, request);
7750 : :
7751 [ # # ]: 0 : if (!err) {
7752 : 0 : nl80211_send_scan_start(rdev, wdev);
7753 [ # # ]: 0 : if (wdev->netdev)
7754 : 0 : dev_hold(wdev->netdev);
7755 : : } else {
7756 : 0 : out_free:
7757 : 0 : rdev->scan_req = NULL;
7758 : 0 : kfree(request);
7759 : : }
7760 : :
7761 : : unlock:
7762 : : return err;
7763 : : }
7764 : :
7765 : 0 : static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
7766 : : {
7767 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
7768 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
7769 : :
7770 [ # # ]: 0 : if (!rdev->ops->abort_scan)
7771 : : return -EOPNOTSUPP;
7772 : :
7773 [ # # ]: 0 : if (rdev->scan_msg)
7774 : : return 0;
7775 : :
7776 [ # # ]: 0 : if (!rdev->scan_req)
7777 : : return -ENOENT;
7778 : :
7779 : 0 : rdev_abort_scan(rdev, wdev);
7780 : 0 : return 0;
7781 : : }
7782 : :
7783 : : static int
7784 : : nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
7785 : : struct cfg80211_sched_scan_request *request,
7786 : : struct nlattr **attrs)
7787 : : {
7788 : : int tmp, err, i = 0;
7789 : : struct nlattr *attr;
7790 : :
7791 : : if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
7792 : : u32 interval;
7793 : :
7794 : : /*
7795 : : * If scan plans are not specified,
7796 : : * %NL80211_ATTR_SCHED_SCAN_INTERVAL will be specified. In this
7797 : : * case one scan plan will be set with the specified scan
7798 : : * interval and infinite number of iterations.
7799 : : */
7800 : : interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
7801 : : if (!interval)
7802 : : return -EINVAL;
7803 : :
7804 : : request->scan_plans[0].interval =
7805 : : DIV_ROUND_UP(interval, MSEC_PER_SEC);
7806 : : if (!request->scan_plans[0].interval)
7807 : : return -EINVAL;
7808 : :
7809 : : if (request->scan_plans[0].interval >
7810 : : wiphy->max_sched_scan_plan_interval)
7811 : : request->scan_plans[0].interval =
7812 : : wiphy->max_sched_scan_plan_interval;
7813 : :
7814 : : return 0;
7815 : : }
7816 : :
7817 : : nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
7818 : : struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
7819 : :
7820 : : if (WARN_ON(i >= n_plans))
7821 : : return -EINVAL;
7822 : :
7823 : : err = nla_parse_nested_deprecated(plan,
7824 : : NL80211_SCHED_SCAN_PLAN_MAX,
7825 : : attr, nl80211_plan_policy,
7826 : : NULL);
7827 : : if (err)
7828 : : return err;
7829 : :
7830 : : if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
7831 : : return -EINVAL;
7832 : :
7833 : : request->scan_plans[i].interval =
7834 : : nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
7835 : : if (!request->scan_plans[i].interval ||
7836 : : request->scan_plans[i].interval >
7837 : : wiphy->max_sched_scan_plan_interval)
7838 : : return -EINVAL;
7839 : :
7840 : : if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
7841 : : request->scan_plans[i].iterations =
7842 : : nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
7843 : : if (!request->scan_plans[i].iterations ||
7844 : : (request->scan_plans[i].iterations >
7845 : : wiphy->max_sched_scan_plan_iterations))
7846 : : return -EINVAL;
7847 : : } else if (i < n_plans - 1) {
7848 : : /*
7849 : : * All scan plans but the last one must specify
7850 : : * a finite number of iterations
7851 : : */
7852 : : return -EINVAL;
7853 : : }
7854 : :
7855 : : i++;
7856 : : }
7857 : :
7858 : : /*
7859 : : * The last scan plan must not specify the number of
7860 : : * iterations, it is supposed to run infinitely
7861 : : */
7862 : : if (request->scan_plans[n_plans - 1].iterations)
7863 : : return -EINVAL;
7864 : :
7865 : : return 0;
7866 : : }
7867 : :
7868 : : static int
7869 : : nl80211_parse_sched_scan_per_band_rssi(struct wiphy *wiphy,
7870 : : struct cfg80211_match_set *match_sets,
7871 : : struct nlattr *tb_band_rssi,
7872 : : s32 rssi_thold)
7873 : : {
7874 : : struct nlattr *attr;
7875 : : int i, tmp, ret = 0;
7876 : :
7877 : : if (!wiphy_ext_feature_isset(wiphy,
7878 : : NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD)) {
7879 : : if (tb_band_rssi)
7880 : : ret = -EOPNOTSUPP;
7881 : : else
7882 : : for (i = 0; i < NUM_NL80211_BANDS; i++)
7883 : : match_sets->per_band_rssi_thold[i] =
7884 : : NL80211_SCAN_RSSI_THOLD_OFF;
7885 : : return ret;
7886 : : }
7887 : :
7888 : : for (i = 0; i < NUM_NL80211_BANDS; i++)
7889 : : match_sets->per_band_rssi_thold[i] = rssi_thold;
7890 : :
7891 : : nla_for_each_nested(attr, tb_band_rssi, tmp) {
7892 : : enum nl80211_band band = nla_type(attr);
7893 : :
7894 : : if (band < 0 || band >= NUM_NL80211_BANDS)
7895 : : return -EINVAL;
7896 : :
7897 : : match_sets->per_band_rssi_thold[band] = nla_get_s32(attr);
7898 : : }
7899 : :
7900 : : return 0;
7901 : : }
7902 : :
7903 : : static struct cfg80211_sched_scan_request *
7904 : 0 : nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
7905 : : struct nlattr **attrs, int max_match_sets)
7906 : : {
7907 : 0 : struct cfg80211_sched_scan_request *request;
7908 : 0 : struct nlattr *attr;
7909 : 0 : int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
7910 : 0 : enum nl80211_band band;
7911 : 0 : size_t ie_len;
7912 : 0 : struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
7913 : 0 : s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
7914 : :
7915 [ # # ]: 0 : if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
7916 : 0 : n_channels = validate_scan_freqs(
7917 : : attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
7918 [ # # ]: 0 : if (!n_channels)
7919 : : return ERR_PTR(-EINVAL);
7920 : : } else {
7921 : 0 : n_channels = ieee80211_get_num_supported_channels(wiphy);
7922 : : }
7923 : :
7924 [ # # ]: 0 : if (attrs[NL80211_ATTR_SCAN_SSIDS])
7925 [ # # ]: 0 : nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
7926 : : tmp)
7927 : 0 : n_ssids++;
7928 : :
7929 [ # # ]: 0 : if (n_ssids > wiphy->max_sched_scan_ssids)
7930 : : return ERR_PTR(-EINVAL);
7931 : :
7932 : : /*
7933 : : * First, count the number of 'real' matchsets. Due to an issue with
7934 : : * the old implementation, matchsets containing only the RSSI attribute
7935 : : * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
7936 : : * RSSI for all matchsets, rather than their own matchset for reporting
7937 : : * all APs with a strong RSSI. This is needed to be compatible with
7938 : : * older userspace that treated a matchset with only the RSSI as the
7939 : : * global RSSI for all other matchsets - if there are other matchsets.
7940 : : */
7941 [ # # ]: 0 : if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
7942 [ # # ]: 0 : nla_for_each_nested(attr,
7943 : : attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
7944 : : tmp) {
7945 : 0 : struct nlattr *rssi;
7946 : :
7947 : 0 : err = nla_parse_nested_deprecated(tb,
7948 : : NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
7949 : : attr,
7950 : : nl80211_match_policy,
7951 : : NULL);
7952 [ # # ]: 0 : if (err)
7953 : 0 : return ERR_PTR(err);
7954 : :
7955 : : /* SSID and BSSID are mutually exclusive */
7956 [ # # ]: 0 : if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] &&
7957 [ # # ]: 0 : tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID])
7958 : : return ERR_PTR(-EINVAL);
7959 : :
7960 : : /* add other standalone attributes here */
7961 [ # # ]: 0 : if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] ||
7962 [ # # ]: 0 : tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID]) {
7963 : 0 : n_match_sets++;
7964 : 0 : continue;
7965 : : }
7966 : 0 : rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
7967 [ # # ]: 0 : if (rssi)
7968 : 0 : default_match_rssi = nla_get_s32(rssi);
7969 : : }
7970 : : }
7971 : :
7972 : : /* However, if there's no other matchset, add the RSSI one */
7973 [ # # ]: 0 : if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
7974 : 0 : n_match_sets = 1;
7975 : :
7976 [ # # ]: 0 : if (n_match_sets > max_match_sets)
7977 : : return ERR_PTR(-EINVAL);
7978 : :
7979 [ # # ]: 0 : if (attrs[NL80211_ATTR_IE])
7980 : 0 : ie_len = nla_len(attrs[NL80211_ATTR_IE]);
7981 : : else
7982 : : ie_len = 0;
7983 : :
7984 [ # # ]: 0 : if (ie_len > wiphy->max_sched_scan_ie_len)
7985 : : return ERR_PTR(-EINVAL);
7986 : :
7987 [ # # ]: 0 : if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
7988 : : /*
7989 : : * NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
7990 : : * each scan plan already specifies its own interval
7991 : : */
7992 [ # # ]: 0 : if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
7993 : : return ERR_PTR(-EINVAL);
7994 : :
7995 [ # # ]: 0 : nla_for_each_nested(attr,
7996 : : attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
7997 : 0 : n_plans++;
7998 : : } else {
7999 : : /*
8000 : : * The scan interval attribute is kept for backward
8001 : : * compatibility. If no scan plans are specified and sched scan
8002 : : * interval is specified, one scan plan will be set with this
8003 : : * scan interval and infinite number of iterations.
8004 : : */
8005 [ # # ]: 0 : if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
8006 : : return ERR_PTR(-EINVAL);
8007 : :
8008 : : n_plans = 1;
8009 : : }
8010 : :
8011 [ # # # # ]: 0 : if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
8012 : 0 : return ERR_PTR(-EINVAL);
8013 : :
8014 [ # # ]: 0 : if (!wiphy_ext_feature_isset(
8015 : 0 : wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
8016 [ # # ]: 0 : (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
8017 [ # # ]: 0 : attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
8018 : : return ERR_PTR(-EINVAL);
8019 : :
8020 : 0 : request = kzalloc(sizeof(*request)
8021 : 0 : + sizeof(*request->ssids) * n_ssids
8022 : 0 : + sizeof(*request->match_sets) * n_match_sets
8023 : 0 : + sizeof(*request->scan_plans) * n_plans
8024 : 0 : + sizeof(*request->channels) * n_channels
8025 : 0 : + ie_len, GFP_KERNEL);
8026 [ # # ]: 0 : if (!request)
8027 : : return ERR_PTR(-ENOMEM);
8028 : :
8029 [ # # ]: 0 : if (n_ssids)
8030 : 0 : request->ssids = (void *)&request->channels[n_channels];
8031 : 0 : request->n_ssids = n_ssids;
8032 [ # # ]: 0 : if (ie_len) {
8033 [ # # ]: 0 : if (n_ssids)
8034 : 0 : request->ie = (void *)(request->ssids + n_ssids);
8035 : : else
8036 : 0 : request->ie = (void *)(request->channels + n_channels);
8037 : : }
8038 : :
8039 [ # # ]: 0 : if (n_match_sets) {
8040 [ # # ]: 0 : if (request->ie)
8041 : 0 : request->match_sets = (void *)(request->ie + ie_len);
8042 [ # # ]: 0 : else if (n_ssids)
8043 : 0 : request->match_sets =
8044 : 0 : (void *)(request->ssids + n_ssids);
8045 : : else
8046 : 0 : request->match_sets =
8047 : 0 : (void *)(request->channels + n_channels);
8048 : : }
8049 : 0 : request->n_match_sets = n_match_sets;
8050 : :
8051 [ # # ]: 0 : if (n_match_sets)
8052 : 0 : request->scan_plans = (void *)(request->match_sets +
8053 : : n_match_sets);
8054 [ # # ]: 0 : else if (request->ie)
8055 : 0 : request->scan_plans = (void *)(request->ie + ie_len);
8056 [ # # ]: 0 : else if (n_ssids)
8057 : 0 : request->scan_plans = (void *)(request->ssids + n_ssids);
8058 : : else
8059 : 0 : request->scan_plans = (void *)(request->channels + n_channels);
8060 : :
8061 : 0 : request->n_scan_plans = n_plans;
8062 : :
8063 : 0 : i = 0;
8064 [ # # ]: 0 : if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
8065 : : /* user specified, bail out if channel not found */
8066 [ # # ]: 0 : nla_for_each_nested(attr,
8067 : : attrs[NL80211_ATTR_SCAN_FREQUENCIES],
8068 : : tmp) {
8069 : 0 : struct ieee80211_channel *chan;
8070 : :
8071 : 0 : chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
8072 : :
8073 [ # # ]: 0 : if (!chan) {
8074 : 0 : err = -EINVAL;
8075 : 0 : goto out_free;
8076 : : }
8077 : :
8078 : : /* ignore disabled channels */
8079 [ # # ]: 0 : if (chan->flags & IEEE80211_CHAN_DISABLED)
8080 : 0 : continue;
8081 : :
8082 : 0 : request->channels[i] = chan;
8083 : 0 : i++;
8084 : : }
8085 : : } else {
8086 : : /* all channels */
8087 [ # # ]: 0 : for (band = 0; band < NUM_NL80211_BANDS; band++) {
8088 : 0 : int j;
8089 : :
8090 [ # # ]: 0 : if (!wiphy->bands[band])
8091 : 0 : continue;
8092 [ # # ]: 0 : for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
8093 : 0 : struct ieee80211_channel *chan;
8094 : :
8095 : 0 : chan = &wiphy->bands[band]->channels[j];
8096 : :
8097 [ # # ]: 0 : if (chan->flags & IEEE80211_CHAN_DISABLED)
8098 : 0 : continue;
8099 : :
8100 : 0 : request->channels[i] = chan;
8101 : 0 : i++;
8102 : : }
8103 : : }
8104 : : }
8105 : :
8106 [ # # ]: 0 : if (!i) {
8107 : 0 : err = -EINVAL;
8108 : 0 : goto out_free;
8109 : : }
8110 : :
8111 : 0 : request->n_channels = i;
8112 : :
8113 : 0 : i = 0;
8114 [ # # ]: 0 : if (n_ssids) {
8115 [ # # ]: 0 : nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
8116 : : tmp) {
8117 [ # # ]: 0 : if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
8118 : 0 : err = -EINVAL;
8119 : 0 : goto out_free;
8120 : : }
8121 : 0 : request->ssids[i].ssid_len = nla_len(attr);
8122 : 0 : memcpy(request->ssids[i].ssid, nla_data(attr),
8123 : 0 : nla_len(attr));
8124 : 0 : i++;
8125 : : }
8126 : : }
8127 : :
8128 : 0 : i = 0;
8129 [ # # ]: 0 : if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
8130 [ # # ]: 0 : nla_for_each_nested(attr,
8131 : : attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
8132 : : tmp) {
8133 : 0 : struct nlattr *ssid, *bssid, *rssi;
8134 : :
8135 : 0 : err = nla_parse_nested_deprecated(tb,
8136 : : NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
8137 : : attr,
8138 : : nl80211_match_policy,
8139 : : NULL);
8140 [ # # ]: 0 : if (err)
8141 : 0 : goto out_free;
8142 : 0 : ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
8143 : 0 : bssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID];
8144 : :
8145 [ # # ]: 0 : if (!ssid && !bssid) {
8146 : 0 : i++;
8147 : 0 : continue;
8148 : : }
8149 : :
8150 [ # # # # ]: 0 : if (WARN_ON(i >= n_match_sets)) {
8151 : : /* this indicates a programming error,
8152 : : * the loop above should have verified
8153 : : * things properly
8154 : : */
8155 : 0 : err = -EINVAL;
8156 : 0 : goto out_free;
8157 : : }
8158 : :
8159 [ # # ]: 0 : if (ssid) {
8160 [ # # ]: 0 : if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
8161 : 0 : err = -EINVAL;
8162 : 0 : goto out_free;
8163 : : }
8164 : 0 : memcpy(request->match_sets[i].ssid.ssid,
8165 : : nla_data(ssid), nla_len(ssid));
8166 : 0 : request->match_sets[i].ssid.ssid_len =
8167 : 0 : nla_len(ssid);
8168 : : }
8169 [ # # ]: 0 : if (bssid) {
8170 [ # # ]: 0 : if (nla_len(bssid) != ETH_ALEN) {
8171 : 0 : err = -EINVAL;
8172 : 0 : goto out_free;
8173 : : }
8174 : 0 : memcpy(request->match_sets[i].bssid,
8175 : : nla_data(bssid), ETH_ALEN);
8176 : : }
8177 : :
8178 : : /* special attribute - old implementation w/a */
8179 : 0 : request->match_sets[i].rssi_thold = default_match_rssi;
8180 : 0 : rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
8181 [ # # ]: 0 : if (rssi)
8182 : 0 : request->match_sets[i].rssi_thold =
8183 : : nla_get_s32(rssi);
8184 : :
8185 : : /* Parse per band RSSI attribute */
8186 : 0 : err = nl80211_parse_sched_scan_per_band_rssi(wiphy,
8187 : : &request->match_sets[i],
8188 : : tb[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI],
8189 : 0 : request->match_sets[i].rssi_thold);
8190 [ # # ]: 0 : if (err)
8191 : 0 : goto out_free;
8192 : :
8193 : 0 : i++;
8194 : : }
8195 : :
8196 : : /* there was no other matchset, so the RSSI one is alone */
8197 [ # # ]: 0 : if (i == 0 && n_match_sets)
8198 : 0 : request->match_sets[0].rssi_thold = default_match_rssi;
8199 : :
8200 : 0 : request->min_rssi_thold = INT_MAX;
8201 [ # # ]: 0 : for (i = 0; i < n_match_sets; i++)
8202 : 0 : request->min_rssi_thold =
8203 : 0 : min(request->match_sets[i].rssi_thold,
8204 : : request->min_rssi_thold);
8205 : : } else {
8206 : 0 : request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
8207 : : }
8208 : :
8209 [ # # ]: 0 : if (ie_len) {
8210 : 0 : request->ie_len = ie_len;
8211 : 0 : memcpy((void *)request->ie,
8212 : 0 : nla_data(attrs[NL80211_ATTR_IE]),
8213 : : request->ie_len);
8214 : : }
8215 : :
8216 : 0 : err = nl80211_check_scan_flags(wiphy, wdev, request, attrs, true);
8217 [ # # ]: 0 : if (err)
8218 : 0 : goto out_free;
8219 : :
8220 [ # # ]: 0 : if (attrs[NL80211_ATTR_SCHED_SCAN_DELAY])
8221 : 0 : request->delay =
8222 : : nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
8223 : :
8224 [ # # ]: 0 : if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
8225 : 0 : request->relative_rssi = nla_get_s8(
8226 : : attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
8227 : 0 : request->relative_rssi_set = true;
8228 : : }
8229 : :
8230 [ # # ]: 0 : if (request->relative_rssi_set &&
8231 [ # # ]: 0 : attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
8232 : 0 : struct nl80211_bss_select_rssi_adjust *rssi_adjust;
8233 : :
8234 [ # # ]: 0 : rssi_adjust = nla_data(
8235 : : attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
8236 : 0 : request->rssi_adjust.band = rssi_adjust->band;
8237 : 0 : request->rssi_adjust.delta = rssi_adjust->delta;
8238 [ # # # # ]: 0 : if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
8239 : 0 : err = -EINVAL;
8240 : 0 : goto out_free;
8241 : : }
8242 : : }
8243 : :
8244 : 0 : err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
8245 [ # # ]: 0 : if (err)
8246 : 0 : goto out_free;
8247 : :
8248 : 0 : request->scan_start = jiffies;
8249 : :
8250 : 0 : return request;
8251 : :
8252 : 0 : out_free:
8253 : 0 : kfree(request);
8254 : 0 : return ERR_PTR(err);
8255 : : }
8256 : :
8257 : 0 : static int nl80211_start_sched_scan(struct sk_buff *skb,
8258 : : struct genl_info *info)
8259 : : {
8260 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
8261 : 0 : struct net_device *dev = info->user_ptr[1];
8262 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
8263 : 0 : struct cfg80211_sched_scan_request *sched_scan_req;
8264 : 0 : bool want_multi;
8265 : 0 : int err;
8266 : :
8267 [ # # # # ]: 0 : if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_start)
8268 : : return -EOPNOTSUPP;
8269 : :
8270 : 0 : want_multi = info->attrs[NL80211_ATTR_SCHED_SCAN_MULTI];
8271 : 0 : err = cfg80211_sched_scan_req_possible(rdev, want_multi);
8272 [ # # ]: 0 : if (err)
8273 : : return err;
8274 : :
8275 : 0 : sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
8276 : : info->attrs,
8277 : 0 : rdev->wiphy.max_match_sets);
8278 : :
8279 [ # # ]: 0 : err = PTR_ERR_OR_ZERO(sched_scan_req);
8280 [ # # ]: 0 : if (err)
8281 : 0 : goto out_err;
8282 : :
8283 : : /* leave request id zero for legacy request
8284 : : * or if driver does not support multi-scheduled scan
8285 : : */
8286 [ # # # # ]: 0 : if (want_multi && rdev->wiphy.max_sched_scan_reqs > 1)
8287 [ # # ]: 0 : sched_scan_req->reqid = cfg80211_assign_cookie(rdev);
8288 : :
8289 : 0 : err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
8290 [ # # ]: 0 : if (err)
8291 : 0 : goto out_free;
8292 : :
8293 : 0 : sched_scan_req->dev = dev;
8294 : 0 : sched_scan_req->wiphy = &rdev->wiphy;
8295 : :
8296 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
8297 : 0 : sched_scan_req->owner_nlportid = info->snd_portid;
8298 : :
8299 : 0 : cfg80211_add_sched_scan_req(rdev, sched_scan_req);
8300 : :
8301 : 0 : nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN);
8302 : 0 : return 0;
8303 : :
8304 : : out_free:
8305 : 0 : kfree(sched_scan_req);
8306 : : out_err:
8307 : : return err;
8308 : : }
8309 : :
8310 : 0 : static int nl80211_stop_sched_scan(struct sk_buff *skb,
8311 : : struct genl_info *info)
8312 : : {
8313 : 0 : struct cfg80211_sched_scan_request *req;
8314 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
8315 : 0 : u64 cookie;
8316 : :
8317 [ # # # # ]: 0 : if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_stop)
8318 : : return -EOPNOTSUPP;
8319 : :
8320 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_COOKIE]) {
8321 : 0 : cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
8322 : 0 : return __cfg80211_stop_sched_scan(rdev, cookie, false);
8323 : : }
8324 : :
8325 [ # # # # ]: 0 : req = list_first_or_null_rcu(&rdev->sched_scan_req_list,
8326 : : struct cfg80211_sched_scan_request,
8327 : : list);
8328 [ # # # # ]: 0 : if (!req || req->reqid ||
8329 [ # # ]: 0 : (req->owner_nlportid &&
8330 [ # # ]: 0 : req->owner_nlportid != info->snd_portid))
8331 : 0 : return -ENOENT;
8332 : :
8333 : 0 : return cfg80211_stop_sched_scan_req(rdev, req, false);
8334 : : }
8335 : :
8336 : 0 : static int nl80211_start_radar_detection(struct sk_buff *skb,
8337 : : struct genl_info *info)
8338 : : {
8339 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
8340 : 0 : struct net_device *dev = info->user_ptr[1];
8341 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
8342 : 0 : struct wiphy *wiphy = wdev->wiphy;
8343 : 0 : struct cfg80211_chan_def chandef;
8344 : 0 : enum nl80211_dfs_regions dfs_region;
8345 : 0 : unsigned int cac_time_ms;
8346 : 0 : int err;
8347 : :
8348 : 0 : dfs_region = reg_get_dfs_region(wiphy);
8349 [ # # ]: 0 : if (dfs_region == NL80211_DFS_UNSET)
8350 : : return -EINVAL;
8351 : :
8352 : 0 : err = nl80211_parse_chandef(rdev, info, &chandef);
8353 [ # # ]: 0 : if (err)
8354 : : return err;
8355 : :
8356 [ # # ]: 0 : if (netif_carrier_ok(dev))
8357 : : return -EBUSY;
8358 : :
8359 [ # # ]: 0 : if (wdev->cac_started)
8360 : : return -EBUSY;
8361 : :
8362 : 0 : err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
8363 [ # # ]: 0 : if (err < 0)
8364 : : return err;
8365 : :
8366 [ # # ]: 0 : if (err == 0)
8367 : : return -EINVAL;
8368 : :
8369 [ # # ]: 0 : if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
8370 : : return -EINVAL;
8371 : :
8372 : : /* CAC start is offloaded to HW and can't be started manually */
8373 [ # # ]: 0 : if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))
8374 : : return -EOPNOTSUPP;
8375 : :
8376 [ # # ]: 0 : if (!rdev->ops->start_radar_detection)
8377 : : return -EOPNOTSUPP;
8378 : :
8379 : 0 : cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
8380 [ # # # # ]: 0 : if (WARN_ON(!cac_time_ms))
8381 : 0 : cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
8382 : :
8383 : 0 : err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
8384 [ # # ]: 0 : if (!err) {
8385 : 0 : wdev->chandef = chandef;
8386 : 0 : wdev->cac_started = true;
8387 : 0 : wdev->cac_start_time = jiffies;
8388 : 0 : wdev->cac_time_ms = cac_time_ms;
8389 : : }
8390 : : return err;
8391 : : }
8392 : :
8393 : 0 : static int nl80211_notify_radar_detection(struct sk_buff *skb,
8394 : : struct genl_info *info)
8395 : : {
8396 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
8397 : 0 : struct net_device *dev = info->user_ptr[1];
8398 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
8399 : 0 : struct wiphy *wiphy = wdev->wiphy;
8400 : 0 : struct cfg80211_chan_def chandef;
8401 : 0 : enum nl80211_dfs_regions dfs_region;
8402 : 0 : int err;
8403 : :
8404 : 0 : dfs_region = reg_get_dfs_region(wiphy);
8405 [ # # ]: 0 : if (dfs_region == NL80211_DFS_UNSET) {
8406 [ # # ]: 0 : GENL_SET_ERR_MSG(info,
8407 : : "DFS Region is not set. Unexpected Radar indication");
8408 : 0 : return -EINVAL;
8409 : : }
8410 : :
8411 : 0 : err = nl80211_parse_chandef(rdev, info, &chandef);
8412 [ # # ]: 0 : if (err) {
8413 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "Unable to extract chandef info");
8414 : 0 : return err;
8415 : : }
8416 : :
8417 : 0 : err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
8418 [ # # ]: 0 : if (err < 0) {
8419 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "chandef is invalid");
8420 : 0 : return err;
8421 : : }
8422 : :
8423 [ # # ]: 0 : if (err == 0) {
8424 [ # # ]: 0 : GENL_SET_ERR_MSG(info,
8425 : : "Unexpected Radar indication for chandef/iftype");
8426 : 0 : return -EINVAL;
8427 : : }
8428 : :
8429 : : /* Do not process this notification if radar is already detected
8430 : : * by kernel on this channel, and return success.
8431 : : */
8432 [ # # ]: 0 : if (chandef.chan->dfs_state == NL80211_DFS_UNAVAILABLE)
8433 : : return 0;
8434 : :
8435 : 0 : cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_UNAVAILABLE);
8436 : :
8437 : 0 : cfg80211_sched_dfs_chan_update(rdev);
8438 : :
8439 : 0 : rdev->radar_chandef = chandef;
8440 : :
8441 : : /* Propagate this notification to other radios as well */
8442 : 0 : queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
8443 : :
8444 : 0 : return 0;
8445 : : }
8446 : :
8447 : 0 : static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
8448 : : {
8449 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
8450 : 0 : struct net_device *dev = info->user_ptr[1];
8451 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
8452 : 0 : struct cfg80211_csa_settings params;
8453 : : /* csa_attrs is defined static to avoid waste of stack size - this
8454 : : * function is called under RTNL lock, so this should not be a problem.
8455 : : */
8456 : 0 : static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
8457 : 0 : int err;
8458 : 0 : bool need_new_beacon = false;
8459 : 0 : bool need_handle_dfs_flag = true;
8460 : 0 : int len, i;
8461 : 0 : u32 cs_count;
8462 : :
8463 [ # # ]: 0 : if (!rdev->ops->channel_switch ||
8464 [ # # ]: 0 : !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
8465 : : return -EOPNOTSUPP;
8466 : :
8467 [ # # # # ]: 0 : switch (dev->ieee80211_ptr->iftype) {
8468 : 0 : case NL80211_IFTYPE_AP:
8469 : : case NL80211_IFTYPE_P2P_GO:
8470 : 0 : need_new_beacon = true;
8471 : : /* For all modes except AP the handle_dfs flag needs to be
8472 : : * supplied to tell the kernel that userspace will handle radar
8473 : : * events when they happen. Otherwise a switch to a channel
8474 : : * requiring DFS will be rejected.
8475 : : */
8476 : 0 : need_handle_dfs_flag = false;
8477 : :
8478 : : /* useless if AP is not running */
8479 [ # # ]: 0 : if (!wdev->beacon_interval)
8480 : : return -ENOTCONN;
8481 : : break;
8482 : 0 : case NL80211_IFTYPE_ADHOC:
8483 [ # # ]: 0 : if (!wdev->ssid_len)
8484 : : return -ENOTCONN;
8485 : : break;
8486 : 0 : case NL80211_IFTYPE_MESH_POINT:
8487 [ # # ]: 0 : if (!wdev->mesh_id_len)
8488 : : return -ENOTCONN;
8489 : : break;
8490 : : default:
8491 : : return -EOPNOTSUPP;
8492 : : }
8493 : :
8494 : 0 : memset(¶ms, 0, sizeof(params));
8495 : 0 : params.beacon_csa.ftm_responder = -1;
8496 : :
8497 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
8498 [ # # ]: 0 : !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
8499 : : return -EINVAL;
8500 : :
8501 : : /* only important for AP, IBSS and mesh create IEs internally */
8502 [ # # # # ]: 0 : if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
8503 : : return -EINVAL;
8504 : :
8505 : : /* Even though the attribute is u32, the specification says
8506 : : * u8, so let's make sure we don't overflow.
8507 : : */
8508 [ # # ]: 0 : cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
8509 [ # # ]: 0 : if (cs_count > 255)
8510 : : return -EINVAL;
8511 : :
8512 : 0 : params.count = cs_count;
8513 : :
8514 [ # # ]: 0 : if (!need_new_beacon)
8515 : 0 : goto skip_beacons;
8516 : :
8517 : 0 : err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after);
8518 [ # # ]: 0 : if (err)
8519 : : return err;
8520 : :
8521 : 0 : err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX,
8522 : 0 : info->attrs[NL80211_ATTR_CSA_IES],
8523 : : nl80211_policy, info->extack);
8524 [ # # ]: 0 : if (err)
8525 : : return err;
8526 : :
8527 : 0 : err = nl80211_parse_beacon(rdev, csa_attrs, ¶ms.beacon_csa);
8528 [ # # ]: 0 : if (err)
8529 : : return err;
8530 : :
8531 [ # # ]: 0 : if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
8532 : : return -EINVAL;
8533 : :
8534 [ # # ]: 0 : len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
8535 [ # # # # ]: 0 : if (!len || (len % sizeof(u16)))
8536 : : return -EINVAL;
8537 : :
8538 : 0 : params.n_counter_offsets_beacon = len / sizeof(u16);
8539 [ # # ]: 0 : if (rdev->wiphy.max_num_csa_counters &&
8540 : : (params.n_counter_offsets_beacon >
8541 [ # # ]: 0 : rdev->wiphy.max_num_csa_counters))
8542 : : return -EINVAL;
8543 : :
8544 : 0 : params.counter_offsets_beacon =
8545 : : nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
8546 : :
8547 : : /* sanity checks - counters should fit and be the same */
8548 [ # # ]: 0 : for (i = 0; i < params.n_counter_offsets_beacon; i++) {
8549 : 0 : u16 offset = params.counter_offsets_beacon[i];
8550 : :
8551 [ # # ]: 0 : if (offset >= params.beacon_csa.tail_len)
8552 : : return -EINVAL;
8553 : :
8554 [ # # ]: 0 : if (params.beacon_csa.tail[offset] != params.count)
8555 : : return -EINVAL;
8556 : : }
8557 : :
8558 [ # # ]: 0 : if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
8559 [ # # ]: 0 : len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
8560 [ # # # # ]: 0 : if (!len || (len % sizeof(u16)))
8561 : : return -EINVAL;
8562 : :
8563 : 0 : params.n_counter_offsets_presp = len / sizeof(u16);
8564 [ # # ]: 0 : if (rdev->wiphy.max_num_csa_counters &&
8565 : : (params.n_counter_offsets_presp >
8566 [ # # ]: 0 : rdev->wiphy.max_num_csa_counters))
8567 : : return -EINVAL;
8568 : :
8569 : 0 : params.counter_offsets_presp =
8570 : : nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
8571 : :
8572 : : /* sanity checks - counters should fit and be the same */
8573 [ # # ]: 0 : for (i = 0; i < params.n_counter_offsets_presp; i++) {
8574 : 0 : u16 offset = params.counter_offsets_presp[i];
8575 : :
8576 [ # # ]: 0 : if (offset >= params.beacon_csa.probe_resp_len)
8577 : : return -EINVAL;
8578 : :
8579 : 0 : if (params.beacon_csa.probe_resp[offset] !=
8580 [ # # ]: 0 : params.count)
8581 : : return -EINVAL;
8582 : : }
8583 : : }
8584 : :
8585 : 0 : skip_beacons:
8586 : 0 : err = nl80211_parse_chandef(rdev, info, ¶ms.chandef);
8587 [ # # ]: 0 : if (err)
8588 : : return err;
8589 : :
8590 [ # # ]: 0 : if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
8591 : : wdev->iftype))
8592 : : return -EINVAL;
8593 : :
8594 : 0 : err = cfg80211_chandef_dfs_required(wdev->wiphy,
8595 : : ¶ms.chandef,
8596 : : wdev->iftype);
8597 [ # # ]: 0 : if (err < 0)
8598 : : return err;
8599 : :
8600 [ # # ]: 0 : if (err > 0) {
8601 : 0 : params.radar_required = true;
8602 [ # # # # ]: 0 : if (need_handle_dfs_flag &&
8603 [ # # ]: 0 : !nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) {
8604 : : return -EINVAL;
8605 : : }
8606 : : }
8607 : :
8608 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
8609 : 0 : params.block_tx = true;
8610 : :
8611 : 0 : wdev_lock(wdev);
8612 : 0 : err = rdev_channel_switch(rdev, dev, ¶ms);
8613 : 0 : wdev_unlock(wdev);
8614 : :
8615 : 0 : return err;
8616 : : }
8617 : :
8618 : : static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
8619 : : u32 seq, int flags,
8620 : : struct cfg80211_registered_device *rdev,
8621 : : struct wireless_dev *wdev,
8622 : : struct cfg80211_internal_bss *intbss)
8623 : : {
8624 : : struct cfg80211_bss *res = &intbss->pub;
8625 : : const struct cfg80211_bss_ies *ies;
8626 : : void *hdr;
8627 : : struct nlattr *bss;
8628 : :
8629 : : ASSERT_WDEV_LOCK(wdev);
8630 : :
8631 : : hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
8632 : : NL80211_CMD_NEW_SCAN_RESULTS);
8633 : : if (!hdr)
8634 : : return -1;
8635 : :
8636 : : genl_dump_check_consistent(cb, hdr);
8637 : :
8638 : : if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
8639 : : goto nla_put_failure;
8640 : : if (wdev->netdev &&
8641 : : nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
8642 : : goto nla_put_failure;
8643 : : if (nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
8644 : : NL80211_ATTR_PAD))
8645 : : goto nla_put_failure;
8646 : :
8647 : : bss = nla_nest_start_noflag(msg, NL80211_ATTR_BSS);
8648 : : if (!bss)
8649 : : goto nla_put_failure;
8650 : : if ((!is_zero_ether_addr(res->bssid) &&
8651 : : nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
8652 : : goto nla_put_failure;
8653 : :
8654 : : rcu_read_lock();
8655 : : /* indicate whether we have probe response data or not */
8656 : : if (rcu_access_pointer(res->proberesp_ies) &&
8657 : : nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
8658 : : goto fail_unlock_rcu;
8659 : :
8660 : : /* this pointer prefers to be pointed to probe response data
8661 : : * but is always valid
8662 : : */
8663 : : ies = rcu_dereference(res->ies);
8664 : : if (ies) {
8665 : : if (nla_put_u64_64bit(msg, NL80211_BSS_TSF, ies->tsf,
8666 : : NL80211_BSS_PAD))
8667 : : goto fail_unlock_rcu;
8668 : : if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
8669 : : ies->len, ies->data))
8670 : : goto fail_unlock_rcu;
8671 : : }
8672 : :
8673 : : /* and this pointer is always (unless driver didn't know) beacon data */
8674 : : ies = rcu_dereference(res->beacon_ies);
8675 : : if (ies && ies->from_beacon) {
8676 : : if (nla_put_u64_64bit(msg, NL80211_BSS_BEACON_TSF, ies->tsf,
8677 : : NL80211_BSS_PAD))
8678 : : goto fail_unlock_rcu;
8679 : : if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
8680 : : ies->len, ies->data))
8681 : : goto fail_unlock_rcu;
8682 : : }
8683 : : rcu_read_unlock();
8684 : :
8685 : : if (res->beacon_interval &&
8686 : : nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
8687 : : goto nla_put_failure;
8688 : : if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
8689 : : nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
8690 : : nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
8691 : : nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
8692 : : jiffies_to_msecs(jiffies - intbss->ts)))
8693 : : goto nla_put_failure;
8694 : :
8695 : : if (intbss->parent_tsf &&
8696 : : (nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
8697 : : intbss->parent_tsf, NL80211_BSS_PAD) ||
8698 : : nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
8699 : : intbss->parent_bssid)))
8700 : : goto nla_put_failure;
8701 : :
8702 : : if (intbss->ts_boottime &&
8703 : : nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
8704 : : intbss->ts_boottime, NL80211_BSS_PAD))
8705 : : goto nla_put_failure;
8706 : :
8707 : : if (!nl80211_put_signal(msg, intbss->pub.chains,
8708 : : intbss->pub.chain_signal,
8709 : : NL80211_BSS_CHAIN_SIGNAL))
8710 : : goto nla_put_failure;
8711 : :
8712 : : switch (rdev->wiphy.signal_type) {
8713 : : case CFG80211_SIGNAL_TYPE_MBM:
8714 : : if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
8715 : : goto nla_put_failure;
8716 : : break;
8717 : : case CFG80211_SIGNAL_TYPE_UNSPEC:
8718 : : if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
8719 : : goto nla_put_failure;
8720 : : break;
8721 : : default:
8722 : : break;
8723 : : }
8724 : :
8725 : : switch (wdev->iftype) {
8726 : : case NL80211_IFTYPE_P2P_CLIENT:
8727 : : case NL80211_IFTYPE_STATION:
8728 : : if (intbss == wdev->current_bss &&
8729 : : nla_put_u32(msg, NL80211_BSS_STATUS,
8730 : : NL80211_BSS_STATUS_ASSOCIATED))
8731 : : goto nla_put_failure;
8732 : : break;
8733 : : case NL80211_IFTYPE_ADHOC:
8734 : : if (intbss == wdev->current_bss &&
8735 : : nla_put_u32(msg, NL80211_BSS_STATUS,
8736 : : NL80211_BSS_STATUS_IBSS_JOINED))
8737 : : goto nla_put_failure;
8738 : : break;
8739 : : default:
8740 : : break;
8741 : : }
8742 : :
8743 : : nla_nest_end(msg, bss);
8744 : :
8745 : : genlmsg_end(msg, hdr);
8746 : : return 0;
8747 : :
8748 : : fail_unlock_rcu:
8749 : : rcu_read_unlock();
8750 : : nla_put_failure:
8751 : : genlmsg_cancel(msg, hdr);
8752 : : return -EMSGSIZE;
8753 : : }
8754 : :
8755 : 0 : static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
8756 : : {
8757 : 0 : struct cfg80211_registered_device *rdev;
8758 : 0 : struct cfg80211_internal_bss *scan;
8759 : 0 : struct wireless_dev *wdev;
8760 : 0 : int start = cb->args[2], idx = 0;
8761 : 0 : int err;
8762 : :
8763 : 0 : rtnl_lock();
8764 : 0 : err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
8765 [ # # ]: 0 : if (err) {
8766 : 0 : rtnl_unlock();
8767 : 0 : return err;
8768 : : }
8769 : :
8770 : 0 : wdev_lock(wdev);
8771 : 0 : spin_lock_bh(&rdev->bss_lock);
8772 : :
8773 : : /*
8774 : : * dump_scan will be called multiple times to break up the scan results
8775 : : * into multiple messages. It is unlikely that any more bss-es will be
8776 : : * expired after the first call, so only call only call this on the
8777 : : * first dump_scan invocation.
8778 : : */
8779 [ # # ]: 0 : if (start == 0)
8780 : 0 : cfg80211_bss_expire(rdev);
8781 : :
8782 : 0 : cb->seq = rdev->bss_generation;
8783 : :
8784 [ # # ]: 0 : list_for_each_entry(scan, &rdev->bss_list, list) {
8785 [ # # ]: 0 : if (++idx <= start)
8786 : 0 : continue;
8787 [ # # ]: 0 : if (nl80211_send_bss(skb, cb,
8788 : 0 : cb->nlh->nlmsg_seq, NLM_F_MULTI,
8789 : : rdev, wdev, scan) < 0) {
8790 : : idx--;
8791 : : break;
8792 : : }
8793 : : }
8794 : :
8795 : 0 : spin_unlock_bh(&rdev->bss_lock);
8796 : 0 : wdev_unlock(wdev);
8797 : :
8798 : 0 : cb->args[2] = idx;
8799 : 0 : rtnl_unlock();
8800 : :
8801 : 0 : return skb->len;
8802 : : }
8803 : :
8804 : 0 : static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
8805 : : int flags, struct net_device *dev,
8806 : : bool allow_radio_stats,
8807 : : struct survey_info *survey)
8808 : : {
8809 : 0 : void *hdr;
8810 : 0 : struct nlattr *infoattr;
8811 : :
8812 : : /* skip radio stats if userspace didn't request them */
8813 [ # # # # ]: 0 : if (!survey->channel && !allow_radio_stats)
8814 : : return 0;
8815 : :
8816 : 0 : hdr = nl80211hdr_put(msg, portid, seq, flags,
8817 : : NL80211_CMD_NEW_SURVEY_RESULTS);
8818 [ # # ]: 0 : if (!hdr)
8819 : : return -ENOMEM;
8820 : :
8821 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
8822 : 0 : goto nla_put_failure;
8823 : :
8824 : 0 : infoattr = nla_nest_start_noflag(msg, NL80211_ATTR_SURVEY_INFO);
8825 [ # # ]: 0 : if (!infoattr)
8826 : 0 : goto nla_put_failure;
8827 : :
8828 [ # # # # ]: 0 : if (survey->channel &&
8829 : 0 : nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
8830 : : survey->channel->center_freq))
8831 : 0 : goto nla_put_failure;
8832 : :
8833 [ # # # # ]: 0 : if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
8834 : 0 : nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
8835 : 0 : goto nla_put_failure;
8836 [ # # # # ]: 0 : if ((survey->filled & SURVEY_INFO_IN_USE) &&
8837 : : nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
8838 : 0 : goto nla_put_failure;
8839 [ # # # # ]: 0 : if ((survey->filled & SURVEY_INFO_TIME) &&
8840 : 0 : nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME,
8841 : : survey->time, NL80211_SURVEY_INFO_PAD))
8842 : 0 : goto nla_put_failure;
8843 [ # # # # ]: 0 : if ((survey->filled & SURVEY_INFO_TIME_BUSY) &&
8844 : 0 : nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BUSY,
8845 : : survey->time_busy, NL80211_SURVEY_INFO_PAD))
8846 : 0 : goto nla_put_failure;
8847 [ # # # # ]: 0 : if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) &&
8848 : 0 : nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
8849 : : survey->time_ext_busy, NL80211_SURVEY_INFO_PAD))
8850 : 0 : goto nla_put_failure;
8851 [ # # # # ]: 0 : if ((survey->filled & SURVEY_INFO_TIME_RX) &&
8852 : 0 : nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_RX,
8853 : : survey->time_rx, NL80211_SURVEY_INFO_PAD))
8854 : 0 : goto nla_put_failure;
8855 [ # # # # ]: 0 : if ((survey->filled & SURVEY_INFO_TIME_TX) &&
8856 : 0 : nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_TX,
8857 : : survey->time_tx, NL80211_SURVEY_INFO_PAD))
8858 : 0 : goto nla_put_failure;
8859 [ # # # # ]: 0 : if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
8860 : 0 : nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_SCAN,
8861 : : survey->time_scan, NL80211_SURVEY_INFO_PAD))
8862 : 0 : goto nla_put_failure;
8863 [ # # # # ]: 0 : if ((survey->filled & SURVEY_INFO_TIME_BSS_RX) &&
8864 : 0 : nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BSS_RX,
8865 : : survey->time_bss_rx, NL80211_SURVEY_INFO_PAD))
8866 : 0 : goto nla_put_failure;
8867 : :
8868 : 0 : nla_nest_end(msg, infoattr);
8869 : :
8870 : 0 : genlmsg_end(msg, hdr);
8871 : 0 : return 0;
8872 : :
8873 : 0 : nla_put_failure:
8874 : 0 : genlmsg_cancel(msg, hdr);
8875 : 0 : return -EMSGSIZE;
8876 : : }
8877 : :
8878 : 0 : static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
8879 : : {
8880 : 0 : struct nlattr **attrbuf;
8881 : 0 : struct survey_info survey;
8882 : 0 : struct cfg80211_registered_device *rdev;
8883 : 0 : struct wireless_dev *wdev;
8884 : 0 : int survey_idx = cb->args[2];
8885 : 0 : int res;
8886 : 0 : bool radio_stats;
8887 : :
8888 : 0 : attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
8889 [ # # ]: 0 : if (!attrbuf)
8890 : : return -ENOMEM;
8891 : :
8892 : 0 : rtnl_lock();
8893 : 0 : res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
8894 [ # # ]: 0 : if (res)
8895 : 0 : goto out_err;
8896 : :
8897 : : /* prepare_wdev_dump parsed the attributes */
8898 : 0 : radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
8899 : :
8900 [ # # ]: 0 : if (!wdev->netdev) {
8901 : 0 : res = -EINVAL;
8902 : 0 : goto out_err;
8903 : : }
8904 : :
8905 [ # # ]: 0 : if (!rdev->ops->dump_survey) {
8906 : 0 : res = -EOPNOTSUPP;
8907 : 0 : goto out_err;
8908 : : }
8909 : :
8910 : 0 : while (1) {
8911 : 0 : res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
8912 [ # # ]: 0 : if (res == -ENOENT)
8913 : : break;
8914 [ # # ]: 0 : if (res)
8915 : 0 : goto out_err;
8916 : :
8917 : : /* don't send disabled channels, but do send non-channel data */
8918 [ # # ]: 0 : if (survey.channel &&
8919 [ # # ]: 0 : survey.channel->flags & IEEE80211_CHAN_DISABLED) {
8920 : 0 : survey_idx++;
8921 : 0 : continue;
8922 : : }
8923 : :
8924 [ # # ]: 0 : if (nl80211_send_survey(skb,
8925 : 0 : NETLINK_CB(cb->skb).portid,
8926 : 0 : cb->nlh->nlmsg_seq, NLM_F_MULTI,
8927 : 0 : wdev->netdev, radio_stats, &survey) < 0)
8928 : 0 : goto out;
8929 : 0 : survey_idx++;
8930 : : }
8931 : :
8932 : 0 : out:
8933 : 0 : cb->args[2] = survey_idx;
8934 : 0 : res = skb->len;
8935 : 0 : out_err:
8936 : 0 : kfree(attrbuf);
8937 : 0 : rtnl_unlock();
8938 : 0 : return res;
8939 : : }
8940 : :
8941 : 0 : static bool nl80211_valid_wpa_versions(u32 wpa_versions)
8942 : : {
8943 : 0 : return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
8944 : : NL80211_WPA_VERSION_2 |
8945 : : NL80211_WPA_VERSION_3));
8946 : : }
8947 : :
8948 : 0 : static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
8949 : : {
8950 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
8951 : 0 : struct net_device *dev = info->user_ptr[1];
8952 : 0 : struct ieee80211_channel *chan;
8953 : 0 : const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
8954 : 0 : int err, ssid_len, ie_len = 0, auth_data_len = 0;
8955 : 0 : enum nl80211_auth_type auth_type;
8956 : 0 : struct key_parse key;
8957 : 0 : bool local_state_change;
8958 : :
8959 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
8960 : : return -EINVAL;
8961 : :
8962 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
8963 : : return -EINVAL;
8964 : :
8965 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_SSID])
8966 : : return -EINVAL;
8967 : :
8968 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
8969 : : return -EINVAL;
8970 : :
8971 : 0 : err = nl80211_parse_key(info, &key);
8972 [ # # ]: 0 : if (err)
8973 : : return err;
8974 : :
8975 [ # # ]: 0 : if (key.idx >= 0) {
8976 [ # # ]: 0 : if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
8977 : : return -EINVAL;
8978 [ # # # # ]: 0 : if (!key.p.key || !key.p.key_len)
8979 : : return -EINVAL;
8980 [ # # # # ]: 0 : if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
8981 [ # # ]: 0 : key.p.key_len != WLAN_KEY_LEN_WEP40) &&
8982 [ # # ]: 0 : (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
8983 : : key.p.key_len != WLAN_KEY_LEN_WEP104))
8984 : : return -EINVAL;
8985 [ # # ]: 0 : if (key.idx > 3)
8986 : : return -EINVAL;
8987 : : } else {
8988 : 0 : key.p.key_len = 0;
8989 : 0 : key.p.key = NULL;
8990 : : }
8991 : :
8992 [ # # ]: 0 : if (key.idx >= 0) {
8993 : : int i;
8994 : : bool ok = false;
8995 : :
8996 [ # # ]: 0 : for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
8997 [ # # ]: 0 : if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
8998 : : ok = true;
8999 : : break;
9000 : : }
9001 : : }
9002 [ # # ]: 0 : if (!ok)
9003 : : return -EINVAL;
9004 : : }
9005 : :
9006 [ # # ]: 0 : if (!rdev->ops->auth)
9007 : : return -EOPNOTSUPP;
9008 : :
9009 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
9010 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9011 : : return -EOPNOTSUPP;
9012 : :
9013 : 0 : bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9014 : 0 : chan = nl80211_get_valid_chan(&rdev->wiphy,
9015 : : info->attrs[NL80211_ATTR_WIPHY_FREQ]);
9016 [ # # ]: 0 : if (!chan)
9017 : : return -EINVAL;
9018 : :
9019 [ # # ]: 0 : ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9020 [ # # ]: 0 : ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9021 : :
9022 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IE]) {
9023 : 0 : ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9024 : 0 : ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9025 : : }
9026 : :
9027 [ # # ]: 0 : auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
9028 [ # # ]: 0 : if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
9029 : : return -EINVAL;
9030 : :
9031 : 0 : if ((auth_type == NL80211_AUTHTYPE_SAE ||
9032 : : auth_type == NL80211_AUTHTYPE_FILS_SK ||
9033 [ # # ]: 0 : auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
9034 : 0 : auth_type == NL80211_AUTHTYPE_FILS_PK) &&
9035 [ # # ]: 0 : !info->attrs[NL80211_ATTR_AUTH_DATA])
9036 : : return -EINVAL;
9037 : :
9038 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
9039 [ # # ]: 0 : if (auth_type != NL80211_AUTHTYPE_SAE &&
9040 : : auth_type != NL80211_AUTHTYPE_FILS_SK &&
9041 : : auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
9042 : : auth_type != NL80211_AUTHTYPE_FILS_PK)
9043 : : return -EINVAL;
9044 [ # # ]: 0 : auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
9045 [ # # ]: 0 : auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
9046 : : /* need to include at least Auth Transaction and Status Code */
9047 [ # # ]: 0 : if (auth_data_len < 4)
9048 : : return -EINVAL;
9049 : : }
9050 : :
9051 : 0 : local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
9052 : :
9053 : : /*
9054 : : * Since we no longer track auth state, ignore
9055 : : * requests to only change local state.
9056 : : */
9057 [ # # ]: 0 : if (local_state_change)
9058 : : return 0;
9059 : :
9060 : 0 : wdev_lock(dev->ieee80211_ptr);
9061 : 0 : err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
9062 : : ssid, ssid_len, ie, ie_len,
9063 : : key.p.key, key.p.key_len, key.idx,
9064 : : auth_data, auth_data_len);
9065 : 0 : wdev_unlock(dev->ieee80211_ptr);
9066 : 0 : return err;
9067 : : }
9068 : :
9069 : 0 : static int validate_pae_over_nl80211(struct cfg80211_registered_device *rdev,
9070 : : struct genl_info *info)
9071 : : {
9072 : 0 : if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
9073 [ # # # # : 0 : GENL_SET_ERR_MSG(info, "SOCKET_OWNER not set");
# # ]
9074 : : return -EINVAL;
9075 : : }
9076 : :
9077 [ # # # # : 0 : if (!rdev->ops->tx_control_port ||
# # # # #
# # # ]
9078 : : !wiphy_ext_feature_isset(&rdev->wiphy,
9079 : : NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
9080 : : return -EOPNOTSUPP;
9081 : :
9082 : : return 0;
9083 : : }
9084 : :
9085 : 0 : static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
9086 : : struct genl_info *info,
9087 : : struct cfg80211_crypto_settings *settings,
9088 : : int cipher_limit)
9089 : : {
9090 : 0 : memset(settings, 0, sizeof(*settings));
9091 : :
9092 : 0 : settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
9093 : :
9094 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
9095 : 0 : u16 proto;
9096 : :
9097 [ # # ]: 0 : proto = nla_get_u16(
9098 : : info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
9099 : 0 : settings->control_port_ethertype = cpu_to_be16(proto);
9100 [ # # # # ]: 0 : if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
9101 : : proto != ETH_P_PAE)
9102 : : return -EINVAL;
9103 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
9104 : 0 : settings->control_port_no_encrypt = true;
9105 : : } else
9106 : 0 : settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
9107 : :
9108 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
9109 [ # # ]: 0 : int r = validate_pae_over_nl80211(rdev, info);
9110 : :
9111 : 0 : if (r < 0)
9112 : 0 : return r;
9113 : :
9114 : 0 : settings->control_port_over_nl80211 = true;
9115 : : }
9116 : :
9117 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
9118 : 0 : void *data;
9119 : 0 : int len, i;
9120 : :
9121 [ # # ]: 0 : data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
9122 [ # # ]: 0 : len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
9123 : 0 : settings->n_ciphers_pairwise = len / sizeof(u32);
9124 : :
9125 [ # # ]: 0 : if (len % sizeof(u32))
9126 : : return -EINVAL;
9127 : :
9128 [ # # ]: 0 : if (settings->n_ciphers_pairwise > cipher_limit)
9129 : : return -EINVAL;
9130 : :
9131 : 0 : memcpy(settings->ciphers_pairwise, data, len);
9132 : :
9133 [ # # ]: 0 : for (i = 0; i < settings->n_ciphers_pairwise; i++)
9134 [ # # ]: 0 : if (!cfg80211_supported_cipher_suite(
9135 : : &rdev->wiphy,
9136 : : settings->ciphers_pairwise[i]))
9137 : : return -EINVAL;
9138 : : }
9139 : :
9140 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
9141 : 0 : settings->cipher_group =
9142 : : nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
9143 [ # # ]: 0 : if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
9144 : : settings->cipher_group))
9145 : : return -EINVAL;
9146 : : }
9147 : :
9148 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
9149 [ # # ]: 0 : settings->wpa_versions =
9150 : : nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
9151 [ # # ]: 0 : if (!nl80211_valid_wpa_versions(settings->wpa_versions))
9152 : : return -EINVAL;
9153 : : }
9154 : :
9155 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
9156 : 0 : void *data;
9157 : 0 : int len;
9158 : :
9159 [ # # ]: 0 : data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
9160 [ # # ]: 0 : len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
9161 : 0 : settings->n_akm_suites = len / sizeof(u32);
9162 : :
9163 [ # # ]: 0 : if (len % sizeof(u32))
9164 : : return -EINVAL;
9165 : :
9166 [ # # ]: 0 : if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
9167 : : return -EINVAL;
9168 : :
9169 : 0 : memcpy(settings->akm_suites, data, len);
9170 : : }
9171 : :
9172 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_PMK]) {
9173 [ # # ]: 0 : if (nla_len(info->attrs[NL80211_ATTR_PMK]) != WLAN_PMK_LEN)
9174 : : return -EINVAL;
9175 [ # # ]: 0 : if (!wiphy_ext_feature_isset(&rdev->wiphy,
9176 : : NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK))
9177 : : return -EINVAL;
9178 : 0 : settings->psk = nla_data(info->attrs[NL80211_ATTR_PMK]);
9179 : : }
9180 : :
9181 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SAE_PASSWORD]) {
9182 [ # # ]: 0 : if (!wiphy_ext_feature_isset(&rdev->wiphy,
9183 : : NL80211_EXT_FEATURE_SAE_OFFLOAD))
9184 : : return -EINVAL;
9185 : 0 : settings->sae_pwd =
9186 : : nla_data(info->attrs[NL80211_ATTR_SAE_PASSWORD]);
9187 : 0 : settings->sae_pwd_len =
9188 : 0 : nla_len(info->attrs[NL80211_ATTR_SAE_PASSWORD]);
9189 : : }
9190 : :
9191 : : return 0;
9192 : : }
9193 : :
9194 : 0 : static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
9195 : : {
9196 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
9197 : 0 : struct net_device *dev = info->user_ptr[1];
9198 : 0 : struct ieee80211_channel *chan;
9199 : 0 : struct cfg80211_assoc_request req = {};
9200 : 0 : const u8 *bssid, *ssid;
9201 : 0 : int err, ssid_len = 0;
9202 : :
9203 [ # # ]: 0 : if (dev->ieee80211_ptr->conn_owner_nlportid &&
9204 [ # # ]: 0 : dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
9205 : : return -EPERM;
9206 : :
9207 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC] ||
9208 [ # # ]: 0 : !info->attrs[NL80211_ATTR_SSID] ||
9209 [ # # ]: 0 : !info->attrs[NL80211_ATTR_WIPHY_FREQ])
9210 : : return -EINVAL;
9211 : :
9212 [ # # ]: 0 : if (!rdev->ops->assoc)
9213 : : return -EOPNOTSUPP;
9214 : :
9215 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
9216 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9217 : : return -EOPNOTSUPP;
9218 : :
9219 : 0 : bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9220 : :
9221 : 0 : chan = nl80211_get_valid_chan(&rdev->wiphy,
9222 : : info->attrs[NL80211_ATTR_WIPHY_FREQ]);
9223 [ # # ]: 0 : if (!chan)
9224 : : return -EINVAL;
9225 : :
9226 [ # # ]: 0 : ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9227 [ # # ]: 0 : ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9228 : :
9229 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IE]) {
9230 : 0 : req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9231 : 0 : req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9232 : : }
9233 : :
9234 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_USE_MFP]) {
9235 [ # # ]: 0 : enum nl80211_mfp mfp =
9236 : : nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
9237 [ # # ]: 0 : if (mfp == NL80211_MFP_REQUIRED)
9238 : 0 : req.use_mfp = true;
9239 [ # # ]: 0 : else if (mfp != NL80211_MFP_NO)
9240 : : return -EINVAL;
9241 : : }
9242 : :
9243 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_PREV_BSSID])
9244 : 0 : req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
9245 : :
9246 [ # # ]: 0 : if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
9247 : 0 : req.flags |= ASSOC_REQ_DISABLE_HT;
9248 : :
9249 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
9250 : 0 : memcpy(&req.ht_capa_mask,
9251 : : nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
9252 : : sizeof(req.ht_capa_mask));
9253 : :
9254 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
9255 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
9256 : : return -EINVAL;
9257 : 0 : memcpy(&req.ht_capa,
9258 : : nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
9259 : : sizeof(req.ht_capa));
9260 : : }
9261 : :
9262 [ # # ]: 0 : if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
9263 : 0 : req.flags |= ASSOC_REQ_DISABLE_VHT;
9264 : :
9265 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
9266 : 0 : memcpy(&req.vht_capa_mask,
9267 : : nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
9268 : : sizeof(req.vht_capa_mask));
9269 : :
9270 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
9271 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
9272 : : return -EINVAL;
9273 : 0 : memcpy(&req.vht_capa,
9274 : : nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
9275 : : sizeof(req.vht_capa));
9276 : : }
9277 : :
9278 [ # # ]: 0 : if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
9279 [ # # ]: 0 : if (!((rdev->wiphy.features &
9280 : : NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
9281 [ # # ]: 0 : (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
9282 : : !wiphy_ext_feature_isset(&rdev->wiphy,
9283 : : NL80211_EXT_FEATURE_RRM))
9284 : : return -EINVAL;
9285 : 0 : req.flags |= ASSOC_REQ_USE_RRM;
9286 : : }
9287 : :
9288 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_FILS_KEK]) {
9289 [ # # ]: 0 : req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
9290 [ # # ]: 0 : req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
9291 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_FILS_NONCES])
9292 : : return -EINVAL;
9293 : 0 : req.fils_nonces =
9294 : : nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
9295 : : }
9296 : :
9297 : 0 : err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
9298 [ # # ]: 0 : if (!err) {
9299 : 0 : wdev_lock(dev->ieee80211_ptr);
9300 : :
9301 : 0 : err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
9302 : : ssid, ssid_len, &req);
9303 : :
9304 [ # # # # ]: 0 : if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
9305 : 0 : dev->ieee80211_ptr->conn_owner_nlportid =
9306 : 0 : info->snd_portid;
9307 : 0 : memcpy(dev->ieee80211_ptr->disconnect_bssid,
9308 : : bssid, ETH_ALEN);
9309 : : }
9310 : :
9311 : 0 : wdev_unlock(dev->ieee80211_ptr);
9312 : : }
9313 : :
9314 : : return err;
9315 : : }
9316 : :
9317 : 0 : static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
9318 : : {
9319 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
9320 : 0 : struct net_device *dev = info->user_ptr[1];
9321 : 0 : const u8 *ie = NULL, *bssid;
9322 : 0 : int ie_len = 0, err;
9323 : 0 : u16 reason_code;
9324 : 0 : bool local_state_change;
9325 : :
9326 [ # # ]: 0 : if (dev->ieee80211_ptr->conn_owner_nlportid &&
9327 [ # # ]: 0 : dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
9328 : : return -EPERM;
9329 : :
9330 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
9331 : : return -EINVAL;
9332 : :
9333 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_REASON_CODE])
9334 : : return -EINVAL;
9335 : :
9336 [ # # ]: 0 : if (!rdev->ops->deauth)
9337 : : return -EOPNOTSUPP;
9338 : :
9339 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
9340 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9341 : : return -EOPNOTSUPP;
9342 : :
9343 [ # # ]: 0 : bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9344 : :
9345 [ # # ]: 0 : reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
9346 [ # # ]: 0 : if (reason_code == 0) {
9347 : : /* Reason Code 0 is reserved */
9348 : : return -EINVAL;
9349 : : }
9350 : :
9351 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IE]) {
9352 : 0 : ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9353 : 0 : ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9354 : : }
9355 : :
9356 : 0 : local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
9357 : :
9358 : 0 : wdev_lock(dev->ieee80211_ptr);
9359 : 0 : err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
9360 : : local_state_change);
9361 : 0 : wdev_unlock(dev->ieee80211_ptr);
9362 : 0 : return err;
9363 : : }
9364 : :
9365 : 0 : static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
9366 : : {
9367 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
9368 : 0 : struct net_device *dev = info->user_ptr[1];
9369 : 0 : const u8 *ie = NULL, *bssid;
9370 : 0 : int ie_len = 0, err;
9371 : 0 : u16 reason_code;
9372 : 0 : bool local_state_change;
9373 : :
9374 [ # # ]: 0 : if (dev->ieee80211_ptr->conn_owner_nlportid &&
9375 [ # # ]: 0 : dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
9376 : : return -EPERM;
9377 : :
9378 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
9379 : : return -EINVAL;
9380 : :
9381 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_REASON_CODE])
9382 : : return -EINVAL;
9383 : :
9384 [ # # ]: 0 : if (!rdev->ops->disassoc)
9385 : : return -EOPNOTSUPP;
9386 : :
9387 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
9388 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9389 : : return -EOPNOTSUPP;
9390 : :
9391 [ # # ]: 0 : bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9392 : :
9393 [ # # ]: 0 : reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
9394 [ # # ]: 0 : if (reason_code == 0) {
9395 : : /* Reason Code 0 is reserved */
9396 : : return -EINVAL;
9397 : : }
9398 : :
9399 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IE]) {
9400 : 0 : ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9401 : 0 : ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9402 : : }
9403 : :
9404 : 0 : local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
9405 : :
9406 : 0 : wdev_lock(dev->ieee80211_ptr);
9407 : 0 : err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
9408 : : local_state_change);
9409 : 0 : wdev_unlock(dev->ieee80211_ptr);
9410 : 0 : return err;
9411 : : }
9412 : :
9413 : : static bool
9414 : 0 : nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
9415 : : int mcast_rate[NUM_NL80211_BANDS],
9416 : : int rateval)
9417 : : {
9418 : 0 : struct wiphy *wiphy = &rdev->wiphy;
9419 : 0 : bool found = false;
9420 : 0 : int band, i;
9421 : :
9422 [ # # ]: 0 : for (band = 0; band < NUM_NL80211_BANDS; band++) {
9423 : 0 : struct ieee80211_supported_band *sband;
9424 : :
9425 : 0 : sband = wiphy->bands[band];
9426 [ # # ]: 0 : if (!sband)
9427 : 0 : continue;
9428 : :
9429 [ # # ]: 0 : for (i = 0; i < sband->n_bitrates; i++) {
9430 [ # # ]: 0 : if (sband->bitrates[i].bitrate == rateval) {
9431 : 0 : mcast_rate[band] = i + 1;
9432 : 0 : found = true;
9433 : 0 : break;
9434 : : }
9435 : : }
9436 : : }
9437 : :
9438 : 0 : return found;
9439 : : }
9440 : :
9441 : 0 : static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
9442 : : {
9443 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
9444 : 0 : struct net_device *dev = info->user_ptr[1];
9445 : 0 : struct cfg80211_ibss_params ibss;
9446 : 0 : struct wiphy *wiphy;
9447 : 0 : struct cfg80211_cached_keys *connkeys = NULL;
9448 : 0 : int err;
9449 : :
9450 : 0 : memset(&ibss, 0, sizeof(ibss));
9451 : :
9452 [ # # # # ]: 0 : if (!info->attrs[NL80211_ATTR_SSID] ||
9453 [ # # ]: 0 : !nla_len(info->attrs[NL80211_ATTR_SSID]))
9454 : : return -EINVAL;
9455 : :
9456 : 0 : ibss.beacon_interval = 100;
9457 : :
9458 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
9459 : 0 : ibss.beacon_interval =
9460 : : nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
9461 : :
9462 : 0 : err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
9463 : 0 : ibss.beacon_interval);
9464 [ # # ]: 0 : if (err)
9465 : : return err;
9466 : :
9467 [ # # ]: 0 : if (!rdev->ops->join_ibss)
9468 : : return -EOPNOTSUPP;
9469 : :
9470 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
9471 : : return -EOPNOTSUPP;
9472 : :
9473 : 0 : wiphy = &rdev->wiphy;
9474 : :
9475 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MAC]) {
9476 [ # # ]: 0 : ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9477 : :
9478 [ # # # # ]: 0 : if (!is_valid_ether_addr(ibss.bssid))
9479 : : return -EINVAL;
9480 : : }
9481 [ # # ]: 0 : ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9482 [ # # ]: 0 : ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9483 : :
9484 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IE]) {
9485 : 0 : ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9486 : 0 : ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9487 : : }
9488 : :
9489 : 0 : err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
9490 [ # # ]: 0 : if (err)
9491 : : return err;
9492 : :
9493 [ # # ]: 0 : if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
9494 : : NL80211_IFTYPE_ADHOC))
9495 : : return -EINVAL;
9496 : :
9497 [ # # # # ]: 0 : switch (ibss.chandef.width) {
9498 : : case NL80211_CHAN_WIDTH_5:
9499 : : case NL80211_CHAN_WIDTH_10:
9500 : : case NL80211_CHAN_WIDTH_20_NOHT:
9501 : : break;
9502 : 0 : case NL80211_CHAN_WIDTH_20:
9503 : : case NL80211_CHAN_WIDTH_40:
9504 [ # # ]: 0 : if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
9505 : : return -EINVAL;
9506 : : break;
9507 : 0 : case NL80211_CHAN_WIDTH_80:
9508 : : case NL80211_CHAN_WIDTH_80P80:
9509 : : case NL80211_CHAN_WIDTH_160:
9510 [ # # ]: 0 : if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
9511 : : return -EINVAL;
9512 [ # # ]: 0 : if (!wiphy_ext_feature_isset(&rdev->wiphy,
9513 : : NL80211_EXT_FEATURE_VHT_IBSS))
9514 : : return -EINVAL;
9515 : : break;
9516 : : default:
9517 : : return -EINVAL;
9518 : : }
9519 : :
9520 : 0 : ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
9521 : 0 : ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
9522 : :
9523 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
9524 : 0 : u8 *rates =
9525 : : nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9526 : 0 : int n_rates =
9527 : 0 : nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9528 : 0 : struct ieee80211_supported_band *sband =
9529 : 0 : wiphy->bands[ibss.chandef.chan->band];
9530 : :
9531 : 0 : err = ieee80211_get_ratemask(sband, rates, n_rates,
9532 : : &ibss.basic_rates);
9533 [ # # ]: 0 : if (err)
9534 : : return err;
9535 : : }
9536 : :
9537 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
9538 : 0 : memcpy(&ibss.ht_capa_mask,
9539 : : nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
9540 : : sizeof(ibss.ht_capa_mask));
9541 : :
9542 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
9543 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
9544 : : return -EINVAL;
9545 : 0 : memcpy(&ibss.ht_capa,
9546 : : nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
9547 : : sizeof(ibss.ht_capa));
9548 : : }
9549 : :
9550 [ # # # # ]: 0 : if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
9551 : 0 : !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
9552 : : nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
9553 : : return -EINVAL;
9554 : :
9555 [ # # # # ]: 0 : if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
9556 : 0 : bool no_ht = false;
9557 : :
9558 : 0 : connkeys = nl80211_parse_connkeys(rdev, info, &no_ht);
9559 [ # # ]: 0 : if (IS_ERR(connkeys))
9560 : 0 : return PTR_ERR(connkeys);
9561 : :
9562 [ # # # # ]: 0 : if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
9563 : : no_ht) {
9564 : 0 : kzfree(connkeys);
9565 : 0 : return -EINVAL;
9566 : : }
9567 : : }
9568 : :
9569 : 0 : ibss.control_port =
9570 [ # # ]: 0 : nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
9571 : :
9572 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
9573 [ # # ]: 0 : int r = validate_pae_over_nl80211(rdev, info);
9574 : :
9575 : 0 : if (r < 0) {
9576 : 0 : kzfree(connkeys);
9577 : 0 : return r;
9578 : : }
9579 : :
9580 : 0 : ibss.control_port_over_nl80211 = true;
9581 : : }
9582 : :
9583 : 0 : ibss.userspace_handles_dfs =
9584 : 0 : nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
9585 : :
9586 : 0 : wdev_lock(dev->ieee80211_ptr);
9587 : 0 : err = __cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
9588 [ # # ]: 0 : if (err)
9589 : 0 : kzfree(connkeys);
9590 [ # # ]: 0 : else if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
9591 : 0 : dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
9592 : 0 : wdev_unlock(dev->ieee80211_ptr);
9593 : :
9594 : 0 : return err;
9595 : : }
9596 : :
9597 : 0 : static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
9598 : : {
9599 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
9600 : 0 : struct net_device *dev = info->user_ptr[1];
9601 : :
9602 [ # # ]: 0 : if (!rdev->ops->leave_ibss)
9603 : : return -EOPNOTSUPP;
9604 : :
9605 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
9606 : : return -EOPNOTSUPP;
9607 : :
9608 : 0 : return cfg80211_leave_ibss(rdev, dev, false);
9609 : : }
9610 : :
9611 : 0 : static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
9612 : : {
9613 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
9614 : 0 : struct net_device *dev = info->user_ptr[1];
9615 : 0 : int mcast_rate[NUM_NL80211_BANDS];
9616 : 0 : u32 nla_rate;
9617 : 0 : int err;
9618 : :
9619 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
9620 [ # # ]: 0 : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
9621 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
9622 : : return -EOPNOTSUPP;
9623 : :
9624 [ # # ]: 0 : if (!rdev->ops->set_mcast_rate)
9625 : : return -EOPNOTSUPP;
9626 : :
9627 : 0 : memset(mcast_rate, 0, sizeof(mcast_rate));
9628 : :
9629 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MCAST_RATE])
9630 : : return -EINVAL;
9631 : :
9632 : 0 : nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
9633 [ # # ]: 0 : if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
9634 : : return -EINVAL;
9635 : :
9636 : 0 : err = rdev_set_mcast_rate(rdev, dev, mcast_rate);
9637 : :
9638 : 0 : return err;
9639 : : }
9640 : :
9641 : : static struct sk_buff *
9642 : 0 : __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
9643 : : struct wireless_dev *wdev, int approxlen,
9644 : : u32 portid, u32 seq, enum nl80211_commands cmd,
9645 : : enum nl80211_attrs attr,
9646 : : const struct nl80211_vendor_cmd_info *info,
9647 : : gfp_t gfp)
9648 : : {
9649 : 0 : struct sk_buff *skb;
9650 : 0 : void *hdr;
9651 : 0 : struct nlattr *data;
9652 : :
9653 : 0 : skb = nlmsg_new(approxlen + 100, gfp);
9654 [ # # ]: 0 : if (!skb)
9655 : : return NULL;
9656 : :
9657 : 0 : hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
9658 [ # # ]: 0 : if (!hdr) {
9659 : 0 : kfree_skb(skb);
9660 : 0 : return NULL;
9661 : : }
9662 : :
9663 [ # # ]: 0 : if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
9664 : 0 : goto nla_put_failure;
9665 : :
9666 [ # # ]: 0 : if (info) {
9667 [ # # ]: 0 : if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
9668 : : info->vendor_id))
9669 : 0 : goto nla_put_failure;
9670 [ # # ]: 0 : if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
9671 : : info->subcmd))
9672 : 0 : goto nla_put_failure;
9673 : : }
9674 : :
9675 [ # # ]: 0 : if (wdev) {
9676 [ # # # # ]: 0 : if (nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
9677 : : wdev_id(wdev), NL80211_ATTR_PAD))
9678 : 0 : goto nla_put_failure;
9679 [ # # # # ]: 0 : if (wdev->netdev &&
9680 : 0 : nla_put_u32(skb, NL80211_ATTR_IFINDEX,
9681 : 0 : wdev->netdev->ifindex))
9682 : 0 : goto nla_put_failure;
9683 : : }
9684 : :
9685 : 0 : data = nla_nest_start_noflag(skb, attr);
9686 [ # # ]: 0 : if (!data)
9687 : 0 : goto nla_put_failure;
9688 : :
9689 : 0 : ((void **)skb->cb)[0] = rdev;
9690 : 0 : ((void **)skb->cb)[1] = hdr;
9691 : 0 : ((void **)skb->cb)[2] = data;
9692 : :
9693 : 0 : return skb;
9694 : :
9695 : 0 : nla_put_failure:
9696 : 0 : kfree_skb(skb);
9697 : 0 : return NULL;
9698 : : }
9699 : :
9700 : 0 : struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
9701 : : struct wireless_dev *wdev,
9702 : : enum nl80211_commands cmd,
9703 : : enum nl80211_attrs attr,
9704 : : unsigned int portid,
9705 : : int vendor_event_idx,
9706 : : int approxlen, gfp_t gfp)
9707 : : {
9708 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
9709 : 0 : const struct nl80211_vendor_cmd_info *info;
9710 : :
9711 [ # # # ]: 0 : switch (cmd) {
9712 : 0 : case NL80211_CMD_TESTMODE:
9713 [ # # # # ]: 0 : if (WARN_ON(vendor_event_idx != -1))
9714 : : return NULL;
9715 : : info = NULL;
9716 : : break;
9717 : 0 : case NL80211_CMD_VENDOR:
9718 [ # # # # : 0 : if (WARN_ON(vendor_event_idx < 0 ||
# # # # ]
9719 : : vendor_event_idx >= wiphy->n_vendor_events))
9720 : : return NULL;
9721 : 0 : info = &wiphy->vendor_events[vendor_event_idx];
9722 : 0 : break;
9723 : : default:
9724 : 0 : WARN_ON(1);
9725 : 0 : return NULL;
9726 : : }
9727 : :
9728 : 0 : return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, portid, 0,
9729 : : cmd, attr, info, gfp);
9730 : : }
9731 : : EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
9732 : :
9733 : 0 : void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
9734 : : {
9735 : 0 : struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
9736 : 0 : void *hdr = ((void **)skb->cb)[1];
9737 [ # # ]: 0 : struct nlmsghdr *nlhdr = nlmsg_hdr(skb);
9738 : 0 : struct nlattr *data = ((void **)skb->cb)[2];
9739 : 0 : enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
9740 : :
9741 : : /* clear CB data for netlink core to own from now on */
9742 : 0 : memset(skb->cb, 0, sizeof(skb->cb));
9743 : :
9744 [ # # ]: 0 : nla_nest_end(skb, data);
9745 [ # # ]: 0 : genlmsg_end(skb, hdr);
9746 : :
9747 [ # # ]: 0 : if (nlhdr->nlmsg_pid) {
9748 : 0 : genlmsg_unicast(wiphy_net(&rdev->wiphy), skb,
9749 : : nlhdr->nlmsg_pid);
9750 : : } else {
9751 [ # # ]: 0 : if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
9752 : 0 : mcgrp = NL80211_MCGRP_VENDOR;
9753 : :
9754 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
9755 : : skb, 0, mcgrp, gfp);
9756 : : }
9757 : 0 : }
9758 : : EXPORT_SYMBOL(__cfg80211_send_event_skb);
9759 : :
9760 : : #ifdef CONFIG_NL80211_TESTMODE
9761 : : static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
9762 : : {
9763 : : struct cfg80211_registered_device *rdev = info->user_ptr[0];
9764 : : struct wireless_dev *wdev =
9765 : : __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
9766 : : int err;
9767 : :
9768 : : if (!rdev->ops->testmode_cmd)
9769 : : return -EOPNOTSUPP;
9770 : :
9771 : : if (IS_ERR(wdev)) {
9772 : : err = PTR_ERR(wdev);
9773 : : if (err != -EINVAL)
9774 : : return err;
9775 : : wdev = NULL;
9776 : : } else if (wdev->wiphy != &rdev->wiphy) {
9777 : : return -EINVAL;
9778 : : }
9779 : :
9780 : : if (!info->attrs[NL80211_ATTR_TESTDATA])
9781 : : return -EINVAL;
9782 : :
9783 : : rdev->cur_cmd_info = info;
9784 : : err = rdev_testmode_cmd(rdev, wdev,
9785 : : nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
9786 : : nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
9787 : : rdev->cur_cmd_info = NULL;
9788 : :
9789 : : return err;
9790 : : }
9791 : :
9792 : : static int nl80211_testmode_dump(struct sk_buff *skb,
9793 : : struct netlink_callback *cb)
9794 : : {
9795 : : struct cfg80211_registered_device *rdev;
9796 : : struct nlattr **attrbuf = NULL;
9797 : : int err;
9798 : : long phy_idx;
9799 : : void *data = NULL;
9800 : : int data_len = 0;
9801 : :
9802 : : rtnl_lock();
9803 : :
9804 : : if (cb->args[0]) {
9805 : : /*
9806 : : * 0 is a valid index, but not valid for args[0],
9807 : : * so we need to offset by 1.
9808 : : */
9809 : : phy_idx = cb->args[0] - 1;
9810 : :
9811 : : rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
9812 : : if (!rdev) {
9813 : : err = -ENOENT;
9814 : : goto out_err;
9815 : : }
9816 : : } else {
9817 : : attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
9818 : : GFP_KERNEL);
9819 : : if (!attrbuf) {
9820 : : err = -ENOMEM;
9821 : : goto out_err;
9822 : : }
9823 : :
9824 : : err = nlmsg_parse_deprecated(cb->nlh,
9825 : : GENL_HDRLEN + nl80211_fam.hdrsize,
9826 : : attrbuf, nl80211_fam.maxattr,
9827 : : nl80211_policy, NULL);
9828 : : if (err)
9829 : : goto out_err;
9830 : :
9831 : : rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
9832 : : if (IS_ERR(rdev)) {
9833 : : err = PTR_ERR(rdev);
9834 : : goto out_err;
9835 : : }
9836 : : phy_idx = rdev->wiphy_idx;
9837 : :
9838 : : if (attrbuf[NL80211_ATTR_TESTDATA])
9839 : : cb->args[1] = (long)attrbuf[NL80211_ATTR_TESTDATA];
9840 : : }
9841 : :
9842 : : if (cb->args[1]) {
9843 : : data = nla_data((void *)cb->args[1]);
9844 : : data_len = nla_len((void *)cb->args[1]);
9845 : : }
9846 : :
9847 : : if (!rdev->ops->testmode_dump) {
9848 : : err = -EOPNOTSUPP;
9849 : : goto out_err;
9850 : : }
9851 : :
9852 : : while (1) {
9853 : : void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
9854 : : cb->nlh->nlmsg_seq, NLM_F_MULTI,
9855 : : NL80211_CMD_TESTMODE);
9856 : : struct nlattr *tmdata;
9857 : :
9858 : : if (!hdr)
9859 : : break;
9860 : :
9861 : : if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
9862 : : genlmsg_cancel(skb, hdr);
9863 : : break;
9864 : : }
9865 : :
9866 : : tmdata = nla_nest_start_noflag(skb, NL80211_ATTR_TESTDATA);
9867 : : if (!tmdata) {
9868 : : genlmsg_cancel(skb, hdr);
9869 : : break;
9870 : : }
9871 : : err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
9872 : : nla_nest_end(skb, tmdata);
9873 : :
9874 : : if (err == -ENOBUFS || err == -ENOENT) {
9875 : : genlmsg_cancel(skb, hdr);
9876 : : break;
9877 : : } else if (err) {
9878 : : genlmsg_cancel(skb, hdr);
9879 : : goto out_err;
9880 : : }
9881 : :
9882 : : genlmsg_end(skb, hdr);
9883 : : }
9884 : :
9885 : : err = skb->len;
9886 : : /* see above */
9887 : : cb->args[0] = phy_idx + 1;
9888 : : out_err:
9889 : : kfree(attrbuf);
9890 : : rtnl_unlock();
9891 : : return err;
9892 : : }
9893 : : #endif
9894 : :
9895 : 0 : static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
9896 : : {
9897 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
9898 : 0 : struct net_device *dev = info->user_ptr[1];
9899 : 0 : struct cfg80211_connect_params connect;
9900 : 0 : struct wiphy *wiphy;
9901 : 0 : struct cfg80211_cached_keys *connkeys = NULL;
9902 : 0 : int err;
9903 : :
9904 : 0 : memset(&connect, 0, sizeof(connect));
9905 : :
9906 [ # # # # ]: 0 : if (!info->attrs[NL80211_ATTR_SSID] ||
9907 [ # # ]: 0 : !nla_len(info->attrs[NL80211_ATTR_SSID]))
9908 : : return -EINVAL;
9909 : :
9910 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
9911 [ # # ]: 0 : connect.auth_type =
9912 : : nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
9913 [ # # ]: 0 : if (!nl80211_valid_auth_type(rdev, connect.auth_type,
9914 : : NL80211_CMD_CONNECT))
9915 : : return -EINVAL;
9916 : : } else
9917 : 0 : connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
9918 : :
9919 : 0 : connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
9920 : :
9921 [ # # # # ]: 0 : if (info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS] &&
9922 : : !wiphy_ext_feature_isset(&rdev->wiphy,
9923 : : NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
9924 : : return -EINVAL;
9925 : 0 : connect.want_1x = info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS];
9926 : :
9927 : 0 : err = nl80211_crypto_settings(rdev, info, &connect.crypto,
9928 : : NL80211_MAX_NR_CIPHER_SUITES);
9929 [ # # ]: 0 : if (err)
9930 : : return err;
9931 : :
9932 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
9933 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9934 : : return -EOPNOTSUPP;
9935 : :
9936 : 0 : wiphy = &rdev->wiphy;
9937 : :
9938 : 0 : connect.bg_scan_period = -1;
9939 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
9940 [ # # ]: 0 : (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
9941 : 0 : connect.bg_scan_period =
9942 : 0 : nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
9943 : : }
9944 : :
9945 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MAC])
9946 : 0 : connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9947 [ # # ]: 0 : else if (info->attrs[NL80211_ATTR_MAC_HINT])
9948 : 0 : connect.bssid_hint =
9949 : : nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
9950 [ # # ]: 0 : connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9951 [ # # ]: 0 : connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9952 : :
9953 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IE]) {
9954 : 0 : connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9955 : 0 : connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9956 : : }
9957 : :
9958 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_USE_MFP]) {
9959 [ # # ]: 0 : connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
9960 [ # # # # ]: 0 : if (connect.mfp == NL80211_MFP_OPTIONAL &&
9961 : : !wiphy_ext_feature_isset(&rdev->wiphy,
9962 : : NL80211_EXT_FEATURE_MFP_OPTIONAL))
9963 : : return -EOPNOTSUPP;
9964 : : } else {
9965 : 0 : connect.mfp = NL80211_MFP_NO;
9966 : : }
9967 : :
9968 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_PREV_BSSID])
9969 : 0 : connect.prev_bssid =
9970 : : nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
9971 : :
9972 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
9973 : 0 : connect.channel = nl80211_get_valid_chan(
9974 : : wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
9975 [ # # ]: 0 : if (!connect.channel)
9976 : : return -EINVAL;
9977 [ # # ]: 0 : } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
9978 : 0 : connect.channel_hint = nl80211_get_valid_chan(
9979 : : wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
9980 [ # # ]: 0 : if (!connect.channel_hint)
9981 : : return -EINVAL;
9982 : : }
9983 : :
9984 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]) {
9985 [ # # ]: 0 : connect.edmg.channels =
9986 : : nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]);
9987 : :
9988 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG])
9989 : 0 : connect.edmg.bw_config =
9990 : 0 : nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG]);
9991 : : }
9992 : :
9993 [ # # # # ]: 0 : if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
9994 : 0 : connkeys = nl80211_parse_connkeys(rdev, info, NULL);
9995 [ # # ]: 0 : if (IS_ERR(connkeys))
9996 : 0 : return PTR_ERR(connkeys);
9997 : : }
9998 : :
9999 [ # # ]: 0 : if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
10000 : 0 : connect.flags |= ASSOC_REQ_DISABLE_HT;
10001 : :
10002 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
10003 : 0 : memcpy(&connect.ht_capa_mask,
10004 : : nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
10005 : : sizeof(connect.ht_capa_mask));
10006 : :
10007 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
10008 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
10009 : 0 : kzfree(connkeys);
10010 : 0 : return -EINVAL;
10011 : : }
10012 : 0 : memcpy(&connect.ht_capa,
10013 : : nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
10014 : : sizeof(connect.ht_capa));
10015 : : }
10016 : :
10017 [ # # ]: 0 : if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
10018 : 0 : connect.flags |= ASSOC_REQ_DISABLE_VHT;
10019 : :
10020 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
10021 : 0 : memcpy(&connect.vht_capa_mask,
10022 : : nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
10023 : : sizeof(connect.vht_capa_mask));
10024 : :
10025 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
10026 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
10027 : 0 : kzfree(connkeys);
10028 : 0 : return -EINVAL;
10029 : : }
10030 : 0 : memcpy(&connect.vht_capa,
10031 : : nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
10032 : : sizeof(connect.vht_capa));
10033 : : }
10034 : :
10035 [ # # ]: 0 : if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
10036 [ # # ]: 0 : if (!((rdev->wiphy.features &
10037 : : NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
10038 [ # # ]: 0 : (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
10039 : : !wiphy_ext_feature_isset(&rdev->wiphy,
10040 : : NL80211_EXT_FEATURE_RRM)) {
10041 : 0 : kzfree(connkeys);
10042 : 0 : return -EINVAL;
10043 : : }
10044 : 0 : connect.flags |= ASSOC_REQ_USE_RRM;
10045 : : }
10046 : :
10047 [ # # ]: 0 : connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
10048 [ # # # # ]: 0 : if (connect.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
10049 : 0 : kzfree(connkeys);
10050 : 0 : return -EOPNOTSUPP;
10051 : : }
10052 : :
10053 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
10054 : : /* bss selection makes no sense if bssid is set */
10055 [ # # ]: 0 : if (connect.bssid) {
10056 : 0 : kzfree(connkeys);
10057 : 0 : return -EINVAL;
10058 : : }
10059 : :
10060 : 0 : err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
10061 : : wiphy, &connect.bss_select);
10062 [ # # ]: 0 : if (err) {
10063 : 0 : kzfree(connkeys);
10064 : 0 : return err;
10065 : : }
10066 : : }
10067 : :
10068 [ # # ]: 0 : if (wiphy_ext_feature_isset(&rdev->wiphy,
10069 : 0 : NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
10070 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
10071 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
10072 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
10073 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
10074 : 0 : connect.fils_erp_username =
10075 : : nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
10076 : 0 : connect.fils_erp_username_len =
10077 : 0 : nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
10078 : 0 : connect.fils_erp_realm =
10079 : : nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
10080 : 0 : connect.fils_erp_realm_len =
10081 : 0 : nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
10082 : 0 : connect.fils_erp_next_seq_num =
10083 : : nla_get_u16(
10084 : : info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
10085 : 0 : connect.fils_erp_rrk =
10086 : : nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
10087 : 0 : connect.fils_erp_rrk_len =
10088 : 0 : nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
10089 [ # # ]: 0 : } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
10090 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
10091 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
10092 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
10093 : 0 : kzfree(connkeys);
10094 : 0 : return -EINVAL;
10095 : : }
10096 : :
10097 [ # # ]: 0 : if (nla_get_flag(info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])) {
10098 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
10099 : 0 : kzfree(connkeys);
10100 [ # # ]: 0 : GENL_SET_ERR_MSG(info,
10101 : : "external auth requires connection ownership");
10102 : 0 : return -EINVAL;
10103 : : }
10104 : 0 : connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT;
10105 : : }
10106 : :
10107 : 0 : wdev_lock(dev->ieee80211_ptr);
10108 : :
10109 : 0 : err = cfg80211_connect(rdev, dev, &connect, connkeys,
10110 : : connect.prev_bssid);
10111 [ # # ]: 0 : if (err)
10112 : 0 : kzfree(connkeys);
10113 : :
10114 [ # # # # ]: 0 : if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
10115 : 0 : dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
10116 [ # # ]: 0 : if (connect.bssid)
10117 : 0 : memcpy(dev->ieee80211_ptr->disconnect_bssid,
10118 : : connect.bssid, ETH_ALEN);
10119 : : else
10120 : 0 : memset(dev->ieee80211_ptr->disconnect_bssid,
10121 : : 0, ETH_ALEN);
10122 : : }
10123 : :
10124 : 0 : wdev_unlock(dev->ieee80211_ptr);
10125 : :
10126 : 0 : return err;
10127 : : }
10128 : :
10129 : 0 : static int nl80211_update_connect_params(struct sk_buff *skb,
10130 : : struct genl_info *info)
10131 : : {
10132 : 0 : struct cfg80211_connect_params connect = {};
10133 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10134 : 0 : struct net_device *dev = info->user_ptr[1];
10135 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
10136 : 0 : bool fils_sk_offload;
10137 : 0 : u32 auth_type;
10138 : 0 : u32 changed = 0;
10139 : 0 : int ret;
10140 : :
10141 [ # # ]: 0 : if (!rdev->ops->update_connect_params)
10142 : : return -EOPNOTSUPP;
10143 : :
10144 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IE]) {
10145 : 0 : connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
10146 : 0 : connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
10147 : 0 : changed |= UPDATE_ASSOC_IES;
10148 : : }
10149 : :
10150 [ # # ]: 0 : fils_sk_offload = wiphy_ext_feature_isset(&rdev->wiphy,
10151 : : NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
10152 : :
10153 : : /*
10154 : : * when driver supports fils-sk offload all attributes must be
10155 : : * provided. So the else covers "fils-sk-not-all" and
10156 : : * "no-fils-sk-any".
10157 : : */
10158 [ # # ]: 0 : if (fils_sk_offload &&
10159 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
10160 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
10161 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
10162 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
10163 : 0 : connect.fils_erp_username =
10164 : : nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
10165 : 0 : connect.fils_erp_username_len =
10166 : 0 : nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
10167 : 0 : connect.fils_erp_realm =
10168 : : nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
10169 : 0 : connect.fils_erp_realm_len =
10170 : 0 : nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
10171 : 0 : connect.fils_erp_next_seq_num =
10172 : : nla_get_u16(
10173 : : info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
10174 : 0 : connect.fils_erp_rrk =
10175 : : nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
10176 : 0 : connect.fils_erp_rrk_len =
10177 : 0 : nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
10178 : 0 : changed |= UPDATE_FILS_ERP_INFO;
10179 [ # # ]: 0 : } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
10180 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
10181 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
10182 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
10183 : : return -EINVAL;
10184 : : }
10185 : :
10186 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
10187 [ # # ]: 0 : auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
10188 [ # # ]: 0 : if (!nl80211_valid_auth_type(rdev, auth_type,
10189 : : NL80211_CMD_CONNECT))
10190 : : return -EINVAL;
10191 : :
10192 [ # # ]: 0 : if (auth_type == NL80211_AUTHTYPE_FILS_SK &&
10193 [ # # ]: 0 : fils_sk_offload && !(changed & UPDATE_FILS_ERP_INFO))
10194 : : return -EINVAL;
10195 : :
10196 : 0 : connect.auth_type = auth_type;
10197 : 0 : changed |= UPDATE_AUTH_TYPE;
10198 : : }
10199 : :
10200 : 0 : wdev_lock(dev->ieee80211_ptr);
10201 [ # # ]: 0 : if (!wdev->current_bss)
10202 : : ret = -ENOLINK;
10203 : : else
10204 : 0 : ret = rdev_update_connect_params(rdev, dev, &connect, changed);
10205 : 0 : wdev_unlock(dev->ieee80211_ptr);
10206 : :
10207 : 0 : return ret;
10208 : : }
10209 : :
10210 : 0 : static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
10211 : : {
10212 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10213 : 0 : struct net_device *dev = info->user_ptr[1];
10214 : 0 : u16 reason;
10215 : 0 : int ret;
10216 : :
10217 [ # # ]: 0 : if (dev->ieee80211_ptr->conn_owner_nlportid &&
10218 [ # # ]: 0 : dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
10219 : : return -EPERM;
10220 : :
10221 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_REASON_CODE])
10222 : : reason = WLAN_REASON_DEAUTH_LEAVING;
10223 : : else
10224 [ # # ]: 0 : reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
10225 : :
10226 [ # # ]: 0 : if (reason == 0)
10227 : : return -EINVAL;
10228 : :
10229 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
10230 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
10231 : : return -EOPNOTSUPP;
10232 : :
10233 : 0 : wdev_lock(dev->ieee80211_ptr);
10234 : 0 : ret = cfg80211_disconnect(rdev, dev, reason, true);
10235 : 0 : wdev_unlock(dev->ieee80211_ptr);
10236 : 0 : return ret;
10237 : : }
10238 : :
10239 : 0 : static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
10240 : : {
10241 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10242 : 0 : struct net *net;
10243 : 0 : int err;
10244 : :
10245 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_PID]) {
10246 : 0 : u32 pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
10247 : :
10248 : 0 : net = get_net_ns_by_pid(pid);
10249 [ # # ]: 0 : } else if (info->attrs[NL80211_ATTR_NETNS_FD]) {
10250 : 0 : u32 fd = nla_get_u32(info->attrs[NL80211_ATTR_NETNS_FD]);
10251 : :
10252 : 0 : net = get_net_ns_by_fd(fd);
10253 : : } else {
10254 : : return -EINVAL;
10255 : : }
10256 : :
10257 [ # # ]: 0 : if (IS_ERR(net))
10258 : 0 : return PTR_ERR(net);
10259 : :
10260 : 0 : err = 0;
10261 : :
10262 : : /* check if anything to do */
10263 [ # # ]: 0 : if (!net_eq(wiphy_net(&rdev->wiphy), net))
10264 : 0 : err = cfg80211_switch_netns(rdev, net);
10265 : :
10266 : 0 : put_net(net);
10267 : 0 : return err;
10268 : : }
10269 : :
10270 : 0 : static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
10271 : : {
10272 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10273 : 0 : int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
10274 : : struct cfg80211_pmksa *pmksa) = NULL;
10275 : 0 : struct net_device *dev = info->user_ptr[1];
10276 : 0 : struct cfg80211_pmksa pmksa;
10277 : :
10278 : 0 : memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
10279 : :
10280 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_PMKID])
10281 : : return -EINVAL;
10282 : :
10283 [ # # ]: 0 : pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
10284 : :
10285 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MAC]) {
10286 : 0 : pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
10287 [ # # ]: 0 : } else if (info->attrs[NL80211_ATTR_SSID] &&
10288 [ # # ]: 0 : info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
10289 [ # # ]: 0 : (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
10290 [ # # ]: 0 : info->attrs[NL80211_ATTR_PMK])) {
10291 : 0 : pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
10292 : 0 : pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
10293 : 0 : pmksa.cache_id =
10294 : : nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
10295 : : } else {
10296 : : return -EINVAL;
10297 : : }
10298 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_PMK]) {
10299 : 0 : pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
10300 : 0 : pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
10301 : : }
10302 : :
10303 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
10304 [ # # ]: 0 : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
10305 [ # # ]: 0 : !(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP &&
10306 : : wiphy_ext_feature_isset(&rdev->wiphy,
10307 : : NL80211_EXT_FEATURE_AP_PMKSA_CACHING)))
10308 : : return -EOPNOTSUPP;
10309 : :
10310 [ # # # ]: 0 : switch (info->genlhdr->cmd) {
10311 : 0 : case NL80211_CMD_SET_PMKSA:
10312 : 0 : rdev_ops = rdev->ops->set_pmksa;
10313 : 0 : break;
10314 : 0 : case NL80211_CMD_DEL_PMKSA:
10315 : 0 : rdev_ops = rdev->ops->del_pmksa;
10316 : 0 : break;
10317 : : default:
10318 : 0 : WARN_ON(1);
10319 : 0 : break;
10320 : : }
10321 : :
10322 [ # # ]: 0 : if (!rdev_ops)
10323 : : return -EOPNOTSUPP;
10324 : :
10325 : 0 : return rdev_ops(&rdev->wiphy, dev, &pmksa);
10326 : : }
10327 : :
10328 : 0 : static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
10329 : : {
10330 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10331 : 0 : struct net_device *dev = info->user_ptr[1];
10332 : :
10333 [ # # ]: 0 : if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
10334 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
10335 : : return -EOPNOTSUPP;
10336 : :
10337 [ # # ]: 0 : if (!rdev->ops->flush_pmksa)
10338 : : return -EOPNOTSUPP;
10339 : :
10340 : 0 : return rdev_flush_pmksa(rdev, dev);
10341 : : }
10342 : :
10343 : 0 : static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
10344 : : {
10345 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10346 : 0 : struct net_device *dev = info->user_ptr[1];
10347 : 0 : u8 action_code, dialog_token;
10348 : 0 : u32 peer_capability = 0;
10349 : 0 : u16 status_code;
10350 : 0 : u8 *peer;
10351 : 0 : bool initiator;
10352 : :
10353 [ # # ]: 0 : if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
10354 [ # # ]: 0 : !rdev->ops->tdls_mgmt)
10355 : : return -EOPNOTSUPP;
10356 : :
10357 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
10358 [ # # ]: 0 : !info->attrs[NL80211_ATTR_STATUS_CODE] ||
10359 [ # # ]: 0 : !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
10360 [ # # ]: 0 : !info->attrs[NL80211_ATTR_IE] ||
10361 [ # # ]: 0 : !info->attrs[NL80211_ATTR_MAC])
10362 : : return -EINVAL;
10363 : :
10364 [ # # ]: 0 : peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
10365 [ # # ]: 0 : action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
10366 [ # # ]: 0 : status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
10367 : 0 : dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
10368 [ # # ]: 0 : initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]);
10369 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
10370 : 0 : peer_capability =
10371 : : nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
10372 : :
10373 : 0 : return rdev_tdls_mgmt(rdev, dev, peer, action_code,
10374 : : dialog_token, status_code, peer_capability,
10375 : : initiator,
10376 : : nla_data(info->attrs[NL80211_ATTR_IE]),
10377 : 0 : nla_len(info->attrs[NL80211_ATTR_IE]));
10378 : : }
10379 : :
10380 : 0 : static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
10381 : : {
10382 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10383 : 0 : struct net_device *dev = info->user_ptr[1];
10384 : 0 : enum nl80211_tdls_operation operation;
10385 : 0 : u8 *peer;
10386 : :
10387 [ # # ]: 0 : if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
10388 [ # # ]: 0 : !rdev->ops->tdls_oper)
10389 : : return -EOPNOTSUPP;
10390 : :
10391 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
10392 [ # # ]: 0 : !info->attrs[NL80211_ATTR_MAC])
10393 : : return -EINVAL;
10394 : :
10395 : 0 : operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
10396 : 0 : peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
10397 : :
10398 : 0 : return rdev_tdls_oper(rdev, dev, peer, operation);
10399 : : }
10400 : :
10401 : 0 : static int nl80211_remain_on_channel(struct sk_buff *skb,
10402 : : struct genl_info *info)
10403 : : {
10404 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10405 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
10406 : 0 : struct cfg80211_chan_def chandef;
10407 : 0 : const struct cfg80211_chan_def *compat_chandef;
10408 : 0 : struct sk_buff *msg;
10409 : 0 : void *hdr;
10410 : 0 : u64 cookie;
10411 : 0 : u32 duration;
10412 : 0 : int err;
10413 : :
10414 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
10415 [ # # ]: 0 : !info->attrs[NL80211_ATTR_DURATION])
10416 : : return -EINVAL;
10417 : :
10418 [ # # ]: 0 : duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
10419 : :
10420 [ # # ]: 0 : if (!rdev->ops->remain_on_channel ||
10421 [ # # ]: 0 : !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
10422 : : return -EOPNOTSUPP;
10423 : :
10424 : : /*
10425 : : * We should be on that channel for at least a minimum amount of
10426 : : * time (10ms) but no longer than the driver supports.
10427 : : */
10428 [ # # ]: 0 : if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
10429 [ # # ]: 0 : duration > rdev->wiphy.max_remain_on_channel_duration)
10430 : : return -EINVAL;
10431 : :
10432 : 0 : err = nl80211_parse_chandef(rdev, info, &chandef);
10433 [ # # ]: 0 : if (err)
10434 : : return err;
10435 : :
10436 : 0 : wdev_lock(wdev);
10437 [ # # # # ]: 0 : if (!cfg80211_off_channel_oper_allowed(wdev) &&
10438 : : !cfg80211_chandef_identical(&wdev->chandef, &chandef)) {
10439 : 0 : compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
10440 : : &chandef);
10441 [ # # ]: 0 : if (compat_chandef != &chandef) {
10442 : 0 : wdev_unlock(wdev);
10443 : 0 : return -EBUSY;
10444 : : }
10445 : : }
10446 : 0 : wdev_unlock(wdev);
10447 : :
10448 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10449 [ # # ]: 0 : if (!msg)
10450 : : return -ENOMEM;
10451 : :
10452 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
10453 : : NL80211_CMD_REMAIN_ON_CHANNEL);
10454 [ # # ]: 0 : if (!hdr) {
10455 : 0 : err = -ENOBUFS;
10456 : 0 : goto free_msg;
10457 : : }
10458 : :
10459 : 0 : err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
10460 : : duration, &cookie);
10461 : :
10462 [ # # ]: 0 : if (err)
10463 : 0 : goto free_msg;
10464 : :
10465 [ # # ]: 0 : if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
10466 : : NL80211_ATTR_PAD))
10467 : 0 : goto nla_put_failure;
10468 : :
10469 : 0 : genlmsg_end(msg, hdr);
10470 : :
10471 : 0 : return genlmsg_reply(msg, info);
10472 : :
10473 : : nla_put_failure:
10474 : 0 : err = -ENOBUFS;
10475 : 0 : free_msg:
10476 : 0 : nlmsg_free(msg);
10477 : 0 : return err;
10478 : : }
10479 : :
10480 : 0 : static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
10481 : : struct genl_info *info)
10482 : : {
10483 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10484 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
10485 : 0 : u64 cookie;
10486 : :
10487 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_COOKIE])
10488 : : return -EINVAL;
10489 : :
10490 [ # # ]: 0 : if (!rdev->ops->cancel_remain_on_channel)
10491 : : return -EOPNOTSUPP;
10492 : :
10493 : 0 : cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
10494 : :
10495 : 0 : return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
10496 : : }
10497 : :
10498 : 0 : static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
10499 : : struct genl_info *info)
10500 : : {
10501 : 0 : struct cfg80211_bitrate_mask mask;
10502 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10503 : 0 : struct net_device *dev = info->user_ptr[1];
10504 : 0 : int err;
10505 : :
10506 [ # # ]: 0 : if (!rdev->ops->set_bitrate_mask)
10507 : : return -EOPNOTSUPP;
10508 : :
10509 : 0 : err = nl80211_parse_tx_bitrate_mask(info, &mask);
10510 [ # # ]: 0 : if (err)
10511 : : return err;
10512 : :
10513 : 0 : return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
10514 : : }
10515 : :
10516 : 0 : static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
10517 : : {
10518 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10519 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
10520 : 0 : u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
10521 : :
10522 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
10523 : : return -EINVAL;
10524 : :
10525 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_FRAME_TYPE])
10526 : 0 : frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
10527 : :
10528 [ # # ]: 0 : switch (wdev->iftype) {
10529 : : case NL80211_IFTYPE_STATION:
10530 : : case NL80211_IFTYPE_ADHOC:
10531 : : case NL80211_IFTYPE_P2P_CLIENT:
10532 : : case NL80211_IFTYPE_AP:
10533 : : case NL80211_IFTYPE_AP_VLAN:
10534 : : case NL80211_IFTYPE_MESH_POINT:
10535 : : case NL80211_IFTYPE_P2P_GO:
10536 : : case NL80211_IFTYPE_P2P_DEVICE:
10537 : 0 : break;
10538 : : case NL80211_IFTYPE_NAN:
10539 : : default:
10540 : : return -EOPNOTSUPP;
10541 : : }
10542 : :
10543 : : /* not much point in registering if we can't reply */
10544 [ # # ]: 0 : if (!rdev->ops->mgmt_tx)
10545 : : return -EOPNOTSUPP;
10546 : :
10547 : 0 : return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
10548 : : nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
10549 : : nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
10550 : : }
10551 : :
10552 : 0 : static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
10553 : : {
10554 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10555 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
10556 : 0 : struct cfg80211_chan_def chandef;
10557 : 0 : int err;
10558 : 0 : void *hdr = NULL;
10559 : 0 : u64 cookie;
10560 : 0 : struct sk_buff *msg = NULL;
10561 : 0 : struct cfg80211_mgmt_tx_params params = {
10562 : : .dont_wait_for_ack =
10563 : 0 : info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
10564 : : };
10565 : :
10566 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_FRAME])
10567 : : return -EINVAL;
10568 : :
10569 [ # # ]: 0 : if (!rdev->ops->mgmt_tx)
10570 : : return -EOPNOTSUPP;
10571 : :
10572 [ # # # ]: 0 : switch (wdev->iftype) {
10573 : 0 : case NL80211_IFTYPE_P2P_DEVICE:
10574 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
10575 : : return -EINVAL;
10576 : : case NL80211_IFTYPE_STATION:
10577 : : case NL80211_IFTYPE_ADHOC:
10578 : : case NL80211_IFTYPE_P2P_CLIENT:
10579 : : case NL80211_IFTYPE_AP:
10580 : : case NL80211_IFTYPE_AP_VLAN:
10581 : : case NL80211_IFTYPE_MESH_POINT:
10582 : : case NL80211_IFTYPE_P2P_GO:
10583 : 0 : break;
10584 : : case NL80211_IFTYPE_NAN:
10585 : : default:
10586 : : return -EOPNOTSUPP;
10587 : : }
10588 : :
10589 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_DURATION]) {
10590 [ # # ]: 0 : if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
10591 : : return -EINVAL;
10592 [ # # ]: 0 : params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
10593 : :
10594 : : /*
10595 : : * We should wait on the channel for at least a minimum amount
10596 : : * of time (10ms) but no longer than the driver supports.
10597 : : */
10598 [ # # ]: 0 : if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
10599 [ # # ]: 0 : params.wait > rdev->wiphy.max_remain_on_channel_duration)
10600 : : return -EINVAL;
10601 : : }
10602 : :
10603 : 0 : params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
10604 : :
10605 [ # # # # ]: 0 : if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
10606 : : return -EINVAL;
10607 : :
10608 [ # # ]: 0 : params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
10609 : :
10610 : : /* get the channel if any has been specified, otherwise pass NULL to
10611 : : * the driver. The latter will use the current one
10612 : : */
10613 : 0 : chandef.chan = NULL;
10614 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
10615 : 0 : err = nl80211_parse_chandef(rdev, info, &chandef);
10616 [ # # ]: 0 : if (err)
10617 : : return err;
10618 : : }
10619 : :
10620 [ # # # # ]: 0 : if (!chandef.chan && params.offchan)
10621 : : return -EINVAL;
10622 : :
10623 : 0 : wdev_lock(wdev);
10624 [ # # # # ]: 0 : if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) {
10625 : 0 : wdev_unlock(wdev);
10626 : 0 : return -EBUSY;
10627 : : }
10628 : 0 : wdev_unlock(wdev);
10629 : :
10630 [ # # ]: 0 : params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
10631 [ # # ]: 0 : params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
10632 : :
10633 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
10634 [ # # ]: 0 : int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
10635 : 0 : int i;
10636 : :
10637 [ # # ]: 0 : if (len % sizeof(u16))
10638 : : return -EINVAL;
10639 : :
10640 : 0 : params.n_csa_offsets = len / sizeof(u16);
10641 : 0 : params.csa_offsets =
10642 : : nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
10643 : :
10644 : : /* check that all the offsets fit the frame */
10645 [ # # ]: 0 : for (i = 0; i < params.n_csa_offsets; i++) {
10646 [ # # ]: 0 : if (params.csa_offsets[i] >= params.len)
10647 : : return -EINVAL;
10648 : : }
10649 : : }
10650 : :
10651 [ # # ]: 0 : if (!params.dont_wait_for_ack) {
10652 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10653 [ # # ]: 0 : if (!msg)
10654 : : return -ENOMEM;
10655 : :
10656 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
10657 : : NL80211_CMD_FRAME);
10658 [ # # ]: 0 : if (!hdr) {
10659 : 0 : err = -ENOBUFS;
10660 : 0 : goto free_msg;
10661 : : }
10662 : : }
10663 : :
10664 : 0 : params.chan = chandef.chan;
10665 : 0 : err = cfg80211_mlme_mgmt_tx(rdev, wdev, ¶ms, &cookie);
10666 [ # # ]: 0 : if (err)
10667 : 0 : goto free_msg;
10668 : :
10669 [ # # ]: 0 : if (msg) {
10670 [ # # ]: 0 : if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
10671 : : NL80211_ATTR_PAD))
10672 : 0 : goto nla_put_failure;
10673 : :
10674 : 0 : genlmsg_end(msg, hdr);
10675 : 0 : return genlmsg_reply(msg, info);
10676 : : }
10677 : :
10678 : : return 0;
10679 : :
10680 : : nla_put_failure:
10681 : 0 : err = -ENOBUFS;
10682 : 0 : free_msg:
10683 : 0 : nlmsg_free(msg);
10684 : 0 : return err;
10685 : : }
10686 : :
10687 : 0 : static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
10688 : : {
10689 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10690 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
10691 : 0 : u64 cookie;
10692 : :
10693 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_COOKIE])
10694 : : return -EINVAL;
10695 : :
10696 [ # # ]: 0 : if (!rdev->ops->mgmt_tx_cancel_wait)
10697 : : return -EOPNOTSUPP;
10698 : :
10699 [ # # ]: 0 : switch (wdev->iftype) {
10700 : : case NL80211_IFTYPE_STATION:
10701 : : case NL80211_IFTYPE_ADHOC:
10702 : : case NL80211_IFTYPE_P2P_CLIENT:
10703 : : case NL80211_IFTYPE_AP:
10704 : : case NL80211_IFTYPE_AP_VLAN:
10705 : : case NL80211_IFTYPE_P2P_GO:
10706 : : case NL80211_IFTYPE_P2P_DEVICE:
10707 : 0 : break;
10708 : : case NL80211_IFTYPE_NAN:
10709 : : default:
10710 : : return -EOPNOTSUPP;
10711 : : }
10712 : :
10713 : 0 : cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
10714 : :
10715 : 0 : return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
10716 : : }
10717 : :
10718 : 0 : static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
10719 : : {
10720 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10721 : 0 : struct wireless_dev *wdev;
10722 : 0 : struct net_device *dev = info->user_ptr[1];
10723 : 0 : u8 ps_state;
10724 : 0 : bool state;
10725 : 0 : int err;
10726 : :
10727 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_PS_STATE])
10728 : : return -EINVAL;
10729 : :
10730 [ # # ]: 0 : ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
10731 : :
10732 : 0 : wdev = dev->ieee80211_ptr;
10733 : :
10734 [ # # ]: 0 : if (!rdev->ops->set_power_mgmt)
10735 : : return -EOPNOTSUPP;
10736 : :
10737 : 0 : state = (ps_state == NL80211_PS_ENABLED) ? true : false;
10738 : :
10739 [ # # ]: 0 : if (state == wdev->ps)
10740 : : return 0;
10741 : :
10742 : 0 : err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
10743 [ # # ]: 0 : if (!err)
10744 : 0 : wdev->ps = state;
10745 : : return err;
10746 : : }
10747 : :
10748 : 0 : static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
10749 : : {
10750 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10751 : 0 : enum nl80211_ps_state ps_state;
10752 : 0 : struct wireless_dev *wdev;
10753 : 0 : struct net_device *dev = info->user_ptr[1];
10754 : 0 : struct sk_buff *msg;
10755 : 0 : void *hdr;
10756 : 0 : int err;
10757 : :
10758 : 0 : wdev = dev->ieee80211_ptr;
10759 : :
10760 [ # # ]: 0 : if (!rdev->ops->set_power_mgmt)
10761 : : return -EOPNOTSUPP;
10762 : :
10763 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10764 [ # # ]: 0 : if (!msg)
10765 : : return -ENOMEM;
10766 : :
10767 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
10768 : : NL80211_CMD_GET_POWER_SAVE);
10769 [ # # ]: 0 : if (!hdr) {
10770 : 0 : err = -ENOBUFS;
10771 : 0 : goto free_msg;
10772 : : }
10773 : :
10774 [ # # ]: 0 : if (wdev->ps)
10775 : : ps_state = NL80211_PS_ENABLED;
10776 : : else
10777 : 0 : ps_state = NL80211_PS_DISABLED;
10778 : :
10779 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
10780 : 0 : goto nla_put_failure;
10781 : :
10782 : 0 : genlmsg_end(msg, hdr);
10783 : 0 : return genlmsg_reply(msg, info);
10784 : :
10785 : : nla_put_failure:
10786 : 0 : err = -ENOBUFS;
10787 : 0 : free_msg:
10788 : 0 : nlmsg_free(msg);
10789 : 0 : return err;
10790 : : }
10791 : :
10792 : : static const struct nla_policy
10793 : : nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
10794 : : [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
10795 : : [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
10796 : : [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
10797 : : [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
10798 : : [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
10799 : : [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
10800 : : [NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
10801 : : };
10802 : :
10803 : : static int nl80211_set_cqm_txe(struct genl_info *info,
10804 : : u32 rate, u32 pkts, u32 intvl)
10805 : : {
10806 : : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10807 : : struct net_device *dev = info->user_ptr[1];
10808 : : struct wireless_dev *wdev = dev->ieee80211_ptr;
10809 : :
10810 : : if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
10811 : : return -EINVAL;
10812 : :
10813 : : if (!rdev->ops->set_cqm_txe_config)
10814 : : return -EOPNOTSUPP;
10815 : :
10816 : : if (wdev->iftype != NL80211_IFTYPE_STATION &&
10817 : : wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
10818 : : return -EOPNOTSUPP;
10819 : :
10820 : : return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
10821 : : }
10822 : :
10823 : 0 : static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
10824 : : struct net_device *dev)
10825 : : {
10826 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
10827 : 0 : s32 last, low, high;
10828 : 0 : u32 hyst;
10829 : 0 : int i, n, low_index;
10830 : 0 : int err;
10831 : :
10832 : : /* RSSI reporting disabled? */
10833 [ # # ]: 0 : if (!wdev->cqm_config)
10834 : 0 : return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
10835 : :
10836 : : /*
10837 : : * Obtain current RSSI value if possible, if not and no RSSI threshold
10838 : : * event has been received yet, we should receive an event after a
10839 : : * connection is established and enough beacons received to calculate
10840 : : * the average.
10841 : : */
10842 [ # # # # ]: 0 : if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
10843 [ # # ]: 0 : rdev->ops->get_station) {
10844 : 0 : struct station_info sinfo = {};
10845 : 0 : u8 *mac_addr;
10846 : :
10847 : 0 : mac_addr = wdev->current_bss->pub.bssid;
10848 : :
10849 : 0 : err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
10850 [ # # ]: 0 : if (err)
10851 : 0 : return err;
10852 : :
10853 : 0 : cfg80211_sinfo_release_content(&sinfo);
10854 [ # # ]: 0 : if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
10855 : 0 : wdev->cqm_config->last_rssi_event_value =
10856 : 0 : (s8) sinfo.rx_beacon_signal_avg;
10857 : : }
10858 : :
10859 : 0 : last = wdev->cqm_config->last_rssi_event_value;
10860 : 0 : hyst = wdev->cqm_config->rssi_hyst;
10861 : 0 : n = wdev->cqm_config->n_rssi_thresholds;
10862 : :
10863 [ # # ]: 0 : for (i = 0; i < n; i++) {
10864 : 0 : i = array_index_nospec(i, n);
10865 [ # # ]: 0 : if (last < wdev->cqm_config->rssi_thresholds[i])
10866 : : break;
10867 : : }
10868 : :
10869 : 0 : low_index = i - 1;
10870 [ # # ]: 0 : if (low_index >= 0) {
10871 : 0 : low_index = array_index_nospec(low_index, n);
10872 : 0 : low = wdev->cqm_config->rssi_thresholds[low_index] - hyst;
10873 : : } else {
10874 : : low = S32_MIN;
10875 : : }
10876 [ # # ]: 0 : if (i < n) {
10877 : 0 : i = array_index_nospec(i, n);
10878 : 0 : high = wdev->cqm_config->rssi_thresholds[i] + hyst - 1;
10879 : : } else {
10880 : : high = S32_MAX;
10881 : : }
10882 : :
10883 : 0 : return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
10884 : : }
10885 : :
10886 : : static int nl80211_set_cqm_rssi(struct genl_info *info,
10887 : : const s32 *thresholds, int n_thresholds,
10888 : : u32 hysteresis)
10889 : : {
10890 : : struct cfg80211_registered_device *rdev = info->user_ptr[0];
10891 : : struct net_device *dev = info->user_ptr[1];
10892 : : struct wireless_dev *wdev = dev->ieee80211_ptr;
10893 : : int i, err;
10894 : : s32 prev = S32_MIN;
10895 : :
10896 : : /* Check all values negative and sorted */
10897 : : for (i = 0; i < n_thresholds; i++) {
10898 : : if (thresholds[i] > 0 || thresholds[i] <= prev)
10899 : : return -EINVAL;
10900 : :
10901 : : prev = thresholds[i];
10902 : : }
10903 : :
10904 : : if (wdev->iftype != NL80211_IFTYPE_STATION &&
10905 : : wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
10906 : : return -EOPNOTSUPP;
10907 : :
10908 : : wdev_lock(wdev);
10909 : : cfg80211_cqm_config_free(wdev);
10910 : : wdev_unlock(wdev);
10911 : :
10912 : : if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
10913 : : if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
10914 : : return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
10915 : :
10916 : : return rdev_set_cqm_rssi_config(rdev, dev,
10917 : : thresholds[0], hysteresis);
10918 : : }
10919 : :
10920 : : if (!wiphy_ext_feature_isset(&rdev->wiphy,
10921 : : NL80211_EXT_FEATURE_CQM_RSSI_LIST))
10922 : : return -EOPNOTSUPP;
10923 : :
10924 : : if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */
10925 : : n_thresholds = 0;
10926 : :
10927 : : wdev_lock(wdev);
10928 : : if (n_thresholds) {
10929 : : struct cfg80211_cqm_config *cqm_config;
10930 : :
10931 : : cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
10932 : : n_thresholds * sizeof(s32), GFP_KERNEL);
10933 : : if (!cqm_config) {
10934 : : err = -ENOMEM;
10935 : : goto unlock;
10936 : : }
10937 : :
10938 : : cqm_config->rssi_hyst = hysteresis;
10939 : : cqm_config->n_rssi_thresholds = n_thresholds;
10940 : : memcpy(cqm_config->rssi_thresholds, thresholds,
10941 : : n_thresholds * sizeof(s32));
10942 : :
10943 : : wdev->cqm_config = cqm_config;
10944 : : }
10945 : :
10946 : : err = cfg80211_cqm_rssi_update(rdev, dev);
10947 : :
10948 : : unlock:
10949 : : wdev_unlock(wdev);
10950 : :
10951 : : return err;
10952 : : }
10953 : :
10954 : 0 : static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
10955 : : {
10956 : 0 : struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
10957 : 0 : struct nlattr *cqm;
10958 : 0 : int err;
10959 : :
10960 : 0 : cqm = info->attrs[NL80211_ATTR_CQM];
10961 [ # # ]: 0 : if (!cqm)
10962 : : return -EINVAL;
10963 : :
10964 : 0 : err = nla_parse_nested_deprecated(attrs, NL80211_ATTR_CQM_MAX, cqm,
10965 : : nl80211_attr_cqm_policy,
10966 : : info->extack);
10967 [ # # ]: 0 : if (err)
10968 : : return err;
10969 : :
10970 [ # # ]: 0 : if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
10971 [ # # ]: 0 : attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
10972 [ # # ]: 0 : const s32 *thresholds =
10973 : : nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
10974 [ # # ]: 0 : int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
10975 [ # # ]: 0 : u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
10976 : :
10977 [ # # ]: 0 : if (len % 4)
10978 : : return -EINVAL;
10979 : :
10980 : 0 : return nl80211_set_cqm_rssi(info, thresholds, len / 4,
10981 : : hysteresis);
10982 : : }
10983 : :
10984 [ # # ]: 0 : if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
10985 [ # # ]: 0 : attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
10986 [ # # ]: 0 : attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
10987 : 0 : u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
10988 : 0 : u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
10989 : 0 : u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
10990 : :
10991 : 0 : return nl80211_set_cqm_txe(info, rate, pkts, intvl);
10992 : : }
10993 : :
10994 : : return -EINVAL;
10995 : : }
10996 : :
10997 : 0 : static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
10998 : : {
10999 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
11000 : 0 : struct net_device *dev = info->user_ptr[1];
11001 : 0 : struct ocb_setup setup = {};
11002 : 0 : int err;
11003 : :
11004 : 0 : err = nl80211_parse_chandef(rdev, info, &setup.chandef);
11005 [ # # ]: 0 : if (err)
11006 : : return err;
11007 : :
11008 : 0 : return cfg80211_join_ocb(rdev, dev, &setup);
11009 : : }
11010 : :
11011 : 0 : static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
11012 : : {
11013 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
11014 : 0 : struct net_device *dev = info->user_ptr[1];
11015 : :
11016 : 0 : return cfg80211_leave_ocb(rdev, dev);
11017 : : }
11018 : :
11019 : 0 : static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
11020 : : {
11021 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
11022 : 0 : struct net_device *dev = info->user_ptr[1];
11023 : 0 : struct mesh_config cfg;
11024 : 0 : struct mesh_setup setup;
11025 : 0 : int err;
11026 : :
11027 : : /* start with default */
11028 : 0 : memcpy(&cfg, &default_mesh_config, sizeof(cfg));
11029 : 0 : memcpy(&setup, &default_mesh_setup, sizeof(setup));
11030 : :
11031 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
11032 : : /* and parse parameters if given */
11033 : 0 : err = nl80211_parse_mesh_config(info, &cfg, NULL);
11034 [ # # ]: 0 : if (err)
11035 : : return err;
11036 : : }
11037 : :
11038 [ # # # # ]: 0 : if (!info->attrs[NL80211_ATTR_MESH_ID] ||
11039 [ # # ]: 0 : !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
11040 : : return -EINVAL;
11041 : :
11042 [ # # ]: 0 : setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
11043 [ # # ]: 0 : setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
11044 : :
11045 [ # # # # ]: 0 : if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
11046 : 0 : !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
11047 : : nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
11048 : : return -EINVAL;
11049 : :
11050 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
11051 : 0 : setup.beacon_interval =
11052 : : nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
11053 : :
11054 : 0 : err = cfg80211_validate_beacon_int(rdev,
11055 : : NL80211_IFTYPE_MESH_POINT,
11056 : : setup.beacon_interval);
11057 [ # # ]: 0 : if (err)
11058 : : return err;
11059 : : }
11060 : :
11061 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
11062 [ # # ]: 0 : setup.dtim_period =
11063 : : nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
11064 [ # # ]: 0 : if (setup.dtim_period < 1 || setup.dtim_period > 100)
11065 : : return -EINVAL;
11066 : : }
11067 : :
11068 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
11069 : : /* parse additional setup parameters if given */
11070 : 0 : err = nl80211_parse_mesh_setup(info, &setup);
11071 [ # # ]: 0 : if (err)
11072 : : return err;
11073 : : }
11074 : :
11075 [ # # ]: 0 : if (setup.user_mpm)
11076 : 0 : cfg.auto_open_plinks = false;
11077 : :
11078 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
11079 : 0 : err = nl80211_parse_chandef(rdev, info, &setup.chandef);
11080 [ # # ]: 0 : if (err)
11081 : : return err;
11082 : : } else {
11083 : : /* __cfg80211_join_mesh() will sort it out */
11084 : 0 : setup.chandef.chan = NULL;
11085 : : }
11086 : :
11087 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
11088 [ # # ]: 0 : u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
11089 : 0 : int n_rates =
11090 [ # # ]: 0 : nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
11091 : 0 : struct ieee80211_supported_band *sband;
11092 : :
11093 [ # # ]: 0 : if (!setup.chandef.chan)
11094 : : return -EINVAL;
11095 : :
11096 : 0 : sband = rdev->wiphy.bands[setup.chandef.chan->band];
11097 : :
11098 : 0 : err = ieee80211_get_ratemask(sband, rates, n_rates,
11099 : : &setup.basic_rates);
11100 [ # # ]: 0 : if (err)
11101 : : return err;
11102 : : }
11103 : :
11104 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_TX_RATES]) {
11105 : 0 : err = nl80211_parse_tx_bitrate_mask(info, &setup.beacon_rate);
11106 [ # # ]: 0 : if (err)
11107 : : return err;
11108 : :
11109 [ # # ]: 0 : if (!setup.chandef.chan)
11110 : : return -EINVAL;
11111 : :
11112 : 0 : err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band,
11113 : : &setup.beacon_rate);
11114 [ # # ]: 0 : if (err)
11115 : : return err;
11116 : : }
11117 : :
11118 : 0 : setup.userspace_handles_dfs =
11119 [ # # ]: 0 : nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
11120 : :
11121 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
11122 [ # # ]: 0 : int r = validate_pae_over_nl80211(rdev, info);
11123 : :
11124 : 0 : if (r < 0)
11125 : 0 : return r;
11126 : :
11127 : 0 : setup.control_port_over_nl80211 = true;
11128 : : }
11129 : :
11130 : 0 : wdev_lock(dev->ieee80211_ptr);
11131 : 0 : err = __cfg80211_join_mesh(rdev, dev, &setup, &cfg);
11132 [ # # # # ]: 0 : if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER])
11133 : 0 : dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
11134 : 0 : wdev_unlock(dev->ieee80211_ptr);
11135 : :
11136 : 0 : return err;
11137 : : }
11138 : :
11139 : 0 : static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
11140 : : {
11141 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
11142 : 0 : struct net_device *dev = info->user_ptr[1];
11143 : :
11144 : 0 : return cfg80211_leave_mesh(rdev, dev);
11145 : : }
11146 : :
11147 : : #ifdef CONFIG_PM
11148 : : static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
11149 : : struct cfg80211_registered_device *rdev)
11150 : : {
11151 : : struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
11152 : : struct nlattr *nl_pats, *nl_pat;
11153 : : int i, pat_len;
11154 : :
11155 : : if (!wowlan->n_patterns)
11156 : : return 0;
11157 : :
11158 : : nl_pats = nla_nest_start_noflag(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
11159 : : if (!nl_pats)
11160 : : return -ENOBUFS;
11161 : :
11162 : : for (i = 0; i < wowlan->n_patterns; i++) {
11163 : : nl_pat = nla_nest_start_noflag(msg, i + 1);
11164 : : if (!nl_pat)
11165 : : return -ENOBUFS;
11166 : : pat_len = wowlan->patterns[i].pattern_len;
11167 : : if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
11168 : : wowlan->patterns[i].mask) ||
11169 : : nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
11170 : : wowlan->patterns[i].pattern) ||
11171 : : nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
11172 : : wowlan->patterns[i].pkt_offset))
11173 : : return -ENOBUFS;
11174 : : nla_nest_end(msg, nl_pat);
11175 : : }
11176 : : nla_nest_end(msg, nl_pats);
11177 : :
11178 : : return 0;
11179 : : }
11180 : :
11181 : 0 : static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
11182 : : struct cfg80211_wowlan_tcp *tcp)
11183 : : {
11184 : 0 : struct nlattr *nl_tcp;
11185 : :
11186 [ # # ]: 0 : if (!tcp)
11187 : : return 0;
11188 : :
11189 : 0 : nl_tcp = nla_nest_start_noflag(msg,
11190 : : NL80211_WOWLAN_TRIG_TCP_CONNECTION);
11191 [ # # ]: 0 : if (!nl_tcp)
11192 : : return -ENOBUFS;
11193 : :
11194 [ # # # # ]: 0 : if (nla_put_in_addr(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
11195 [ # # ]: 0 : nla_put_in_addr(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
11196 [ # # ]: 0 : nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
11197 [ # # ]: 0 : nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
11198 [ # # ]: 0 : nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
11199 : 0 : nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
11200 [ # # ]: 0 : tcp->payload_len, tcp->payload) ||
11201 : 0 : nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
11202 [ # # ]: 0 : tcp->data_interval) ||
11203 : 0 : nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
11204 [ # # ]: 0 : tcp->wake_len, tcp->wake_data) ||
11205 : 0 : nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK,
11206 : 0 : DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask))
11207 : 0 : return -ENOBUFS;
11208 : :
11209 [ # # # # ]: 0 : if (tcp->payload_seq.len &&
11210 : 0 : nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
11211 : 0 : sizeof(tcp->payload_seq), &tcp->payload_seq))
11212 : : return -ENOBUFS;
11213 : :
11214 [ # # # # ]: 0 : if (tcp->payload_tok.len &&
11215 : 0 : nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
11216 : 0 : sizeof(tcp->payload_tok) + tcp->tokens_size,
11217 : 0 : &tcp->payload_tok))
11218 : : return -ENOBUFS;
11219 : :
11220 : 0 : nla_nest_end(msg, nl_tcp);
11221 : :
11222 : 0 : return 0;
11223 : : }
11224 : :
11225 : 0 : static int nl80211_send_wowlan_nd(struct sk_buff *msg,
11226 : : struct cfg80211_sched_scan_request *req)
11227 : : {
11228 : 0 : struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
11229 : 0 : int i;
11230 : :
11231 [ # # ]: 0 : if (!req)
11232 : : return 0;
11233 : :
11234 : 0 : nd = nla_nest_start_noflag(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
11235 [ # # ]: 0 : if (!nd)
11236 : : return -ENOBUFS;
11237 : :
11238 [ # # # # ]: 0 : if (req->n_scan_plans == 1 &&
11239 : 0 : nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
11240 : 0 : req->scan_plans[0].interval * 1000))
11241 : : return -ENOBUFS;
11242 : :
11243 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
11244 : : return -ENOBUFS;
11245 : :
11246 [ # # ]: 0 : if (req->relative_rssi_set) {
11247 : 0 : struct nl80211_bss_select_rssi_adjust rssi_adjust;
11248 : :
11249 [ # # ]: 0 : if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
11250 : 0 : req->relative_rssi))
11251 : 0 : return -ENOBUFS;
11252 : :
11253 : 0 : rssi_adjust.band = req->rssi_adjust.band;
11254 : 0 : rssi_adjust.delta = req->rssi_adjust.delta;
11255 [ # # ]: 0 : if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
11256 : : sizeof(rssi_adjust), &rssi_adjust))
11257 : : return -ENOBUFS;
11258 : : }
11259 : :
11260 : 0 : freqs = nla_nest_start_noflag(msg, NL80211_ATTR_SCAN_FREQUENCIES);
11261 [ # # ]: 0 : if (!freqs)
11262 : : return -ENOBUFS;
11263 : :
11264 [ # # ]: 0 : for (i = 0; i < req->n_channels; i++) {
11265 [ # # ]: 0 : if (nla_put_u32(msg, i, req->channels[i]->center_freq))
11266 : : return -ENOBUFS;
11267 : : }
11268 : :
11269 [ # # ]: 0 : nla_nest_end(msg, freqs);
11270 : :
11271 [ # # ]: 0 : if (req->n_match_sets) {
11272 : 0 : matches = nla_nest_start_noflag(msg,
11273 : : NL80211_ATTR_SCHED_SCAN_MATCH);
11274 [ # # ]: 0 : if (!matches)
11275 : : return -ENOBUFS;
11276 : :
11277 [ # # ]: 0 : for (i = 0; i < req->n_match_sets; i++) {
11278 : 0 : match = nla_nest_start_noflag(msg, i);
11279 [ # # ]: 0 : if (!match)
11280 : : return -ENOBUFS;
11281 : :
11282 [ # # ]: 0 : if (nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
11283 : 0 : req->match_sets[i].ssid.ssid_len,
11284 : 0 : req->match_sets[i].ssid.ssid))
11285 : : return -ENOBUFS;
11286 : 0 : nla_nest_end(msg, match);
11287 : : }
11288 : 0 : nla_nest_end(msg, matches);
11289 : : }
11290 : :
11291 : 0 : scan_plans = nla_nest_start_noflag(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
11292 [ # # ]: 0 : if (!scan_plans)
11293 : : return -ENOBUFS;
11294 : :
11295 [ # # ]: 0 : for (i = 0; i < req->n_scan_plans; i++) {
11296 : 0 : scan_plan = nla_nest_start_noflag(msg, i + 1);
11297 [ # # ]: 0 : if (!scan_plan)
11298 : : return -ENOBUFS;
11299 : :
11300 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
11301 : 0 : req->scan_plans[i].interval) ||
11302 [ # # # # ]: 0 : (req->scan_plans[i].iterations &&
11303 : : nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
11304 : : req->scan_plans[i].iterations)))
11305 : 0 : return -ENOBUFS;
11306 : 0 : nla_nest_end(msg, scan_plan);
11307 : : }
11308 : 0 : nla_nest_end(msg, scan_plans);
11309 : :
11310 : 0 : nla_nest_end(msg, nd);
11311 : :
11312 : 0 : return 0;
11313 : : }
11314 : :
11315 : 0 : static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
11316 : : {
11317 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
11318 : 0 : struct sk_buff *msg;
11319 : 0 : void *hdr;
11320 : 0 : u32 size = NLMSG_DEFAULT_SIZE;
11321 : :
11322 [ # # ]: 0 : if (!rdev->wiphy.wowlan)
11323 : : return -EOPNOTSUPP;
11324 : :
11325 [ # # # # ]: 0 : if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
11326 : : /* adjust size to have room for all the data */
11327 : 0 : size += rdev->wiphy.wowlan_config->tcp->tokens_size +
11328 : 0 : rdev->wiphy.wowlan_config->tcp->payload_len +
11329 : 0 : rdev->wiphy.wowlan_config->tcp->wake_len +
11330 : 0 : rdev->wiphy.wowlan_config->tcp->wake_len / 8;
11331 : : }
11332 : :
11333 : 0 : msg = nlmsg_new(size, GFP_KERNEL);
11334 [ # # ]: 0 : if (!msg)
11335 : : return -ENOMEM;
11336 : :
11337 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11338 : : NL80211_CMD_GET_WOWLAN);
11339 [ # # ]: 0 : if (!hdr)
11340 : 0 : goto nla_put_failure;
11341 : :
11342 [ # # ]: 0 : if (rdev->wiphy.wowlan_config) {
11343 : 0 : struct nlattr *nl_wowlan;
11344 : :
11345 : 0 : nl_wowlan = nla_nest_start_noflag(msg,
11346 : : NL80211_ATTR_WOWLAN_TRIGGERS);
11347 [ # # ]: 0 : if (!nl_wowlan)
11348 : 0 : goto nla_put_failure;
11349 : :
11350 [ # # # # ]: 0 : if ((rdev->wiphy.wowlan_config->any &&
11351 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
11352 [ # # # # ]: 0 : (rdev->wiphy.wowlan_config->disconnect &&
11353 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
11354 [ # # # # ]: 0 : (rdev->wiphy.wowlan_config->magic_pkt &&
11355 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
11356 [ # # # # ]: 0 : (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
11357 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
11358 [ # # # # ]: 0 : (rdev->wiphy.wowlan_config->eap_identity_req &&
11359 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
11360 [ # # # # ]: 0 : (rdev->wiphy.wowlan_config->four_way_handshake &&
11361 : 0 : nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
11362 [ # # # # ]: 0 : (rdev->wiphy.wowlan_config->rfkill_release &&
11363 : : nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
11364 : 0 : goto nla_put_failure;
11365 : :
11366 [ # # ]: 0 : if (nl80211_send_wowlan_patterns(msg, rdev))
11367 : 0 : goto nla_put_failure;
11368 : :
11369 [ # # ]: 0 : if (nl80211_send_wowlan_tcp(msg,
11370 : 0 : rdev->wiphy.wowlan_config->tcp))
11371 : 0 : goto nla_put_failure;
11372 : :
11373 [ # # ]: 0 : if (nl80211_send_wowlan_nd(
11374 : : msg,
11375 : 0 : rdev->wiphy.wowlan_config->nd_config))
11376 : 0 : goto nla_put_failure;
11377 : :
11378 : 0 : nla_nest_end(msg, nl_wowlan);
11379 : : }
11380 : :
11381 : 0 : genlmsg_end(msg, hdr);
11382 : 0 : return genlmsg_reply(msg, info);
11383 : :
11384 : 0 : nla_put_failure:
11385 : 0 : nlmsg_free(msg);
11386 : 0 : return -ENOBUFS;
11387 : : }
11388 : :
11389 : : static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
11390 : : struct nlattr *attr,
11391 : : struct cfg80211_wowlan *trig)
11392 : : {
11393 : : struct nlattr *tb[NUM_NL80211_WOWLAN_TCP];
11394 : : struct cfg80211_wowlan_tcp *cfg;
11395 : : struct nl80211_wowlan_tcp_data_token *tok = NULL;
11396 : : struct nl80211_wowlan_tcp_data_seq *seq = NULL;
11397 : : u32 size;
11398 : : u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
11399 : : int err, port;
11400 : :
11401 : : if (!rdev->wiphy.wowlan->tcp)
11402 : : return -EINVAL;
11403 : :
11404 : : err = nla_parse_nested_deprecated(tb, MAX_NL80211_WOWLAN_TCP, attr,
11405 : : nl80211_wowlan_tcp_policy, NULL);
11406 : : if (err)
11407 : : return err;
11408 : :
11409 : : if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] ||
11410 : : !tb[NL80211_WOWLAN_TCP_DST_IPV4] ||
11411 : : !tb[NL80211_WOWLAN_TCP_DST_MAC] ||
11412 : : !tb[NL80211_WOWLAN_TCP_DST_PORT] ||
11413 : : !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] ||
11414 : : !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] ||
11415 : : !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] ||
11416 : : !tb[NL80211_WOWLAN_TCP_WAKE_MASK])
11417 : : return -EINVAL;
11418 : :
11419 : : data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
11420 : : if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
11421 : : return -EINVAL;
11422 : :
11423 : : if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
11424 : : rdev->wiphy.wowlan->tcp->data_interval_max ||
11425 : : nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
11426 : : return -EINVAL;
11427 : :
11428 : : wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
11429 : : if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
11430 : : return -EINVAL;
11431 : :
11432 : : wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
11433 : : if (wake_mask_size != DIV_ROUND_UP(wake_size, 8))
11434 : : return -EINVAL;
11435 : :
11436 : : if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) {
11437 : : u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
11438 : :
11439 : : tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
11440 : : tokens_size = tokln - sizeof(*tok);
11441 : :
11442 : : if (!tok->len || tokens_size % tok->len)
11443 : : return -EINVAL;
11444 : : if (!rdev->wiphy.wowlan->tcp->tok)
11445 : : return -EINVAL;
11446 : : if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
11447 : : return -EINVAL;
11448 : : if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
11449 : : return -EINVAL;
11450 : : if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
11451 : : return -EINVAL;
11452 : : if (tok->offset + tok->len > data_size)
11453 : : return -EINVAL;
11454 : : }
11455 : :
11456 : : if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
11457 : : seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
11458 : : if (!rdev->wiphy.wowlan->tcp->seq)
11459 : : return -EINVAL;
11460 : : if (seq->len == 0 || seq->len > 4)
11461 : : return -EINVAL;
11462 : : if (seq->len + seq->offset > data_size)
11463 : : return -EINVAL;
11464 : : }
11465 : :
11466 : : size = sizeof(*cfg);
11467 : : size += data_size;
11468 : : size += wake_size + wake_mask_size;
11469 : : size += tokens_size;
11470 : :
11471 : : cfg = kzalloc(size, GFP_KERNEL);
11472 : : if (!cfg)
11473 : : return -ENOMEM;
11474 : : cfg->src = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
11475 : : cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
11476 : : memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
11477 : : ETH_ALEN);
11478 : : if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
11479 : : port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
11480 : : else
11481 : : port = 0;
11482 : : #ifdef CONFIG_INET
11483 : : /* allocate a socket and port for it and use it */
11484 : : err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
11485 : : IPPROTO_TCP, &cfg->sock, 1);
11486 : : if (err) {
11487 : : kfree(cfg);
11488 : : return err;
11489 : : }
11490 : : if (inet_csk_get_port(cfg->sock->sk, port)) {
11491 : : sock_release(cfg->sock);
11492 : : kfree(cfg);
11493 : : return -EADDRINUSE;
11494 : : }
11495 : : cfg->src_port = inet_sk(cfg->sock->sk)->inet_num;
11496 : : #else
11497 : : if (!port) {
11498 : : kfree(cfg);
11499 : : return -EINVAL;
11500 : : }
11501 : : cfg->src_port = port;
11502 : : #endif
11503 : :
11504 : : cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]);
11505 : : cfg->payload_len = data_size;
11506 : : cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size;
11507 : : memcpy((void *)cfg->payload,
11508 : : nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]),
11509 : : data_size);
11510 : : if (seq)
11511 : : cfg->payload_seq = *seq;
11512 : : cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]);
11513 : : cfg->wake_len = wake_size;
11514 : : cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size;
11515 : : memcpy((void *)cfg->wake_data,
11516 : : nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]),
11517 : : wake_size);
11518 : : cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size +
11519 : : data_size + wake_size;
11520 : : memcpy((void *)cfg->wake_mask,
11521 : : nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]),
11522 : : wake_mask_size);
11523 : : if (tok) {
11524 : : cfg->tokens_size = tokens_size;
11525 : : memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size);
11526 : : }
11527 : :
11528 : : trig->tcp = cfg;
11529 : :
11530 : : return 0;
11531 : : }
11532 : :
11533 : : static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
11534 : : const struct wiphy_wowlan_support *wowlan,
11535 : : struct nlattr *attr,
11536 : : struct cfg80211_wowlan *trig)
11537 : : {
11538 : : struct nlattr **tb;
11539 : : int err;
11540 : :
11541 : : tb = kcalloc(NUM_NL80211_ATTR, sizeof(*tb), GFP_KERNEL);
11542 : : if (!tb)
11543 : : return -ENOMEM;
11544 : :
11545 : : if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) {
11546 : : err = -EOPNOTSUPP;
11547 : : goto out;
11548 : : }
11549 : :
11550 : : err = nla_parse_nested_deprecated(tb, NL80211_ATTR_MAX, attr,
11551 : : nl80211_policy, NULL);
11552 : : if (err)
11553 : : goto out;
11554 : :
11555 : : trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb,
11556 : : wowlan->max_nd_match_sets);
11557 : : err = PTR_ERR_OR_ZERO(trig->nd_config);
11558 : : if (err)
11559 : : trig->nd_config = NULL;
11560 : :
11561 : : out:
11562 : : kfree(tb);
11563 : : return err;
11564 : : }
11565 : :
11566 : 0 : static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
11567 : : {
11568 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
11569 : 0 : struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
11570 : 0 : struct cfg80211_wowlan new_triggers = {};
11571 : 0 : struct cfg80211_wowlan *ntrig;
11572 : 0 : const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
11573 : 0 : int err, i;
11574 : 0 : bool prev_enabled = rdev->wiphy.wowlan_config;
11575 : 0 : bool regular = false;
11576 : :
11577 [ # # ]: 0 : if (!wowlan)
11578 : : return -EOPNOTSUPP;
11579 : :
11580 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
11581 : 0 : cfg80211_rdev_free_wowlan(rdev);
11582 : 0 : rdev->wiphy.wowlan_config = NULL;
11583 : 0 : goto set_wakeup;
11584 : : }
11585 : :
11586 : 0 : err = nla_parse_nested_deprecated(tb, MAX_NL80211_WOWLAN_TRIG,
11587 : : info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS],
11588 : : nl80211_wowlan_policy, info->extack);
11589 [ # # ]: 0 : if (err)
11590 : : return err;
11591 : :
11592 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_ANY]) {
11593 [ # # ]: 0 : if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
11594 : : return -EINVAL;
11595 : 0 : new_triggers.any = true;
11596 : : }
11597 : :
11598 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
11599 [ # # ]: 0 : if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
11600 : : return -EINVAL;
11601 : 0 : new_triggers.disconnect = true;
11602 : 0 : regular = true;
11603 : : }
11604 : :
11605 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
11606 [ # # ]: 0 : if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
11607 : : return -EINVAL;
11608 : 0 : new_triggers.magic_pkt = true;
11609 : 0 : regular = true;
11610 : : }
11611 : :
11612 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
11613 : : return -EINVAL;
11614 : :
11615 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) {
11616 [ # # ]: 0 : if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
11617 : : return -EINVAL;
11618 : 0 : new_triggers.gtk_rekey_failure = true;
11619 : 0 : regular = true;
11620 : : }
11621 : :
11622 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
11623 [ # # ]: 0 : if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
11624 : : return -EINVAL;
11625 : 0 : new_triggers.eap_identity_req = true;
11626 : 0 : regular = true;
11627 : : }
11628 : :
11629 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
11630 [ # # ]: 0 : if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
11631 : : return -EINVAL;
11632 : 0 : new_triggers.four_way_handshake = true;
11633 : 0 : regular = true;
11634 : : }
11635 : :
11636 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
11637 [ # # ]: 0 : if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
11638 : : return -EINVAL;
11639 : 0 : new_triggers.rfkill_release = true;
11640 : 0 : regular = true;
11641 : : }
11642 : :
11643 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
11644 : 0 : struct nlattr *pat;
11645 : 0 : int n_patterns = 0;
11646 : 0 : int rem, pat_len, mask_len, pkt_offset;
11647 : 0 : struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
11648 : :
11649 : 0 : regular = true;
11650 : :
11651 [ # # ]: 0 : nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
11652 : : rem)
11653 : 0 : n_patterns++;
11654 [ # # ]: 0 : if (n_patterns > wowlan->n_patterns)
11655 : 0 : return -EINVAL;
11656 : :
11657 : 0 : new_triggers.patterns = kcalloc(n_patterns,
11658 : : sizeof(new_triggers.patterns[0]),
11659 : : GFP_KERNEL);
11660 [ # # ]: 0 : if (!new_triggers.patterns)
11661 : : return -ENOMEM;
11662 : :
11663 : 0 : new_triggers.n_patterns = n_patterns;
11664 : 0 : i = 0;
11665 : :
11666 [ # # ]: 0 : nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
11667 : : rem) {
11668 : 0 : u8 *mask_pat;
11669 : :
11670 : 0 : err = nla_parse_nested_deprecated(pat_tb,
11671 : : MAX_NL80211_PKTPAT,
11672 : : pat,
11673 : : nl80211_packet_pattern_policy,
11674 : : info->extack);
11675 [ # # ]: 0 : if (err)
11676 : 0 : goto error;
11677 : :
11678 : 0 : err = -EINVAL;
11679 [ # # ]: 0 : if (!pat_tb[NL80211_PKTPAT_MASK] ||
11680 [ # # ]: 0 : !pat_tb[NL80211_PKTPAT_PATTERN])
11681 : 0 : goto error;
11682 [ # # ]: 0 : pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
11683 : 0 : mask_len = DIV_ROUND_UP(pat_len, 8);
11684 [ # # ]: 0 : if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
11685 : 0 : goto error;
11686 [ # # ]: 0 : if (pat_len > wowlan->pattern_max_len ||
11687 [ # # ]: 0 : pat_len < wowlan->pattern_min_len)
11688 : 0 : goto error;
11689 : :
11690 [ # # ]: 0 : if (!pat_tb[NL80211_PKTPAT_OFFSET])
11691 : : pkt_offset = 0;
11692 : : else
11693 : 0 : pkt_offset = nla_get_u32(
11694 : : pat_tb[NL80211_PKTPAT_OFFSET]);
11695 [ # # ]: 0 : if (pkt_offset > wowlan->max_pkt_offset)
11696 : 0 : goto error;
11697 : 0 : new_triggers.patterns[i].pkt_offset = pkt_offset;
11698 : :
11699 [ # # ]: 0 : mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
11700 [ # # ]: 0 : if (!mask_pat) {
11701 : 0 : err = -ENOMEM;
11702 : 0 : goto error;
11703 : : }
11704 : 0 : new_triggers.patterns[i].mask = mask_pat;
11705 : 0 : memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
11706 : : mask_len);
11707 : 0 : mask_pat += mask_len;
11708 : 0 : new_triggers.patterns[i].pattern = mask_pat;
11709 : 0 : new_triggers.patterns[i].pattern_len = pat_len;
11710 : 0 : memcpy(mask_pat,
11711 : 0 : nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
11712 : : pat_len);
11713 : 0 : i++;
11714 : : }
11715 : : }
11716 : :
11717 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
11718 : 0 : regular = true;
11719 : 0 : err = nl80211_parse_wowlan_tcp(
11720 : : rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
11721 : : &new_triggers);
11722 [ # # ]: 0 : if (err)
11723 : 0 : goto error;
11724 : : }
11725 : :
11726 [ # # ]: 0 : if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
11727 : 0 : regular = true;
11728 : 0 : err = nl80211_parse_wowlan_nd(
11729 : : rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
11730 : : &new_triggers);
11731 [ # # ]: 0 : if (err)
11732 : 0 : goto error;
11733 : : }
11734 : :
11735 : : /* The 'any' trigger means the device continues operating more or less
11736 : : * as in its normal operation mode and wakes up the host on most of the
11737 : : * normal interrupts (like packet RX, ...)
11738 : : * It therefore makes little sense to combine with the more constrained
11739 : : * wakeup trigger modes.
11740 : : */
11741 [ # # # # ]: 0 : if (new_triggers.any && regular) {
11742 : 0 : err = -EINVAL;
11743 : 0 : goto error;
11744 : : }
11745 : :
11746 : 0 : ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
11747 [ # # ]: 0 : if (!ntrig) {
11748 : 0 : err = -ENOMEM;
11749 : 0 : goto error;
11750 : : }
11751 : 0 : cfg80211_rdev_free_wowlan(rdev);
11752 : 0 : rdev->wiphy.wowlan_config = ntrig;
11753 : :
11754 : 0 : set_wakeup:
11755 [ # # ]: 0 : if (rdev->ops->set_wakeup &&
11756 [ # # ]: 0 : prev_enabled != !!rdev->wiphy.wowlan_config)
11757 : 0 : rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
11758 : :
11759 : : return 0;
11760 : 0 : error:
11761 [ # # ]: 0 : for (i = 0; i < new_triggers.n_patterns; i++)
11762 : 0 : kfree(new_triggers.patterns[i].mask);
11763 : 0 : kfree(new_triggers.patterns);
11764 [ # # # # ]: 0 : if (new_triggers.tcp && new_triggers.tcp->sock)
11765 : 0 : sock_release(new_triggers.tcp->sock);
11766 : 0 : kfree(new_triggers.tcp);
11767 : 0 : kfree(new_triggers.nd_config);
11768 : 0 : return err;
11769 : : }
11770 : : #endif
11771 : :
11772 : : static int nl80211_send_coalesce_rules(struct sk_buff *msg,
11773 : : struct cfg80211_registered_device *rdev)
11774 : : {
11775 : : struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
11776 : : int i, j, pat_len;
11777 : : struct cfg80211_coalesce_rules *rule;
11778 : :
11779 : : if (!rdev->coalesce->n_rules)
11780 : : return 0;
11781 : :
11782 : : nl_rules = nla_nest_start_noflag(msg, NL80211_ATTR_COALESCE_RULE);
11783 : : if (!nl_rules)
11784 : : return -ENOBUFS;
11785 : :
11786 : : for (i = 0; i < rdev->coalesce->n_rules; i++) {
11787 : : nl_rule = nla_nest_start_noflag(msg, i + 1);
11788 : : if (!nl_rule)
11789 : : return -ENOBUFS;
11790 : :
11791 : : rule = &rdev->coalesce->rules[i];
11792 : : if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
11793 : : rule->delay))
11794 : : return -ENOBUFS;
11795 : :
11796 : : if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
11797 : : rule->condition))
11798 : : return -ENOBUFS;
11799 : :
11800 : : nl_pats = nla_nest_start_noflag(msg,
11801 : : NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
11802 : : if (!nl_pats)
11803 : : return -ENOBUFS;
11804 : :
11805 : : for (j = 0; j < rule->n_patterns; j++) {
11806 : : nl_pat = nla_nest_start_noflag(msg, j + 1);
11807 : : if (!nl_pat)
11808 : : return -ENOBUFS;
11809 : : pat_len = rule->patterns[j].pattern_len;
11810 : : if (nla_put(msg, NL80211_PKTPAT_MASK,
11811 : : DIV_ROUND_UP(pat_len, 8),
11812 : : rule->patterns[j].mask) ||
11813 : : nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
11814 : : rule->patterns[j].pattern) ||
11815 : : nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
11816 : : rule->patterns[j].pkt_offset))
11817 : : return -ENOBUFS;
11818 : : nla_nest_end(msg, nl_pat);
11819 : : }
11820 : : nla_nest_end(msg, nl_pats);
11821 : : nla_nest_end(msg, nl_rule);
11822 : : }
11823 : : nla_nest_end(msg, nl_rules);
11824 : :
11825 : : return 0;
11826 : : }
11827 : :
11828 : 0 : static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
11829 : : {
11830 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
11831 : 0 : struct sk_buff *msg;
11832 : 0 : void *hdr;
11833 : :
11834 [ # # ]: 0 : if (!rdev->wiphy.coalesce)
11835 : : return -EOPNOTSUPP;
11836 : :
11837 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11838 [ # # ]: 0 : if (!msg)
11839 : : return -ENOMEM;
11840 : :
11841 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11842 : : NL80211_CMD_GET_COALESCE);
11843 [ # # ]: 0 : if (!hdr)
11844 : 0 : goto nla_put_failure;
11845 : :
11846 [ # # # # ]: 0 : if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
11847 : 0 : goto nla_put_failure;
11848 : :
11849 : 0 : genlmsg_end(msg, hdr);
11850 : 0 : return genlmsg_reply(msg, info);
11851 : :
11852 : 0 : nla_put_failure:
11853 : 0 : nlmsg_free(msg);
11854 : 0 : return -ENOBUFS;
11855 : : }
11856 : :
11857 : 0 : void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
11858 : : {
11859 : 0 : struct cfg80211_coalesce *coalesce = rdev->coalesce;
11860 : 0 : int i, j;
11861 : 0 : struct cfg80211_coalesce_rules *rule;
11862 : :
11863 [ # # ]: 0 : if (!coalesce)
11864 : : return;
11865 : :
11866 [ # # ]: 0 : for (i = 0; i < coalesce->n_rules; i++) {
11867 : 0 : rule = &coalesce->rules[i];
11868 [ # # ]: 0 : for (j = 0; j < rule->n_patterns; j++)
11869 : 0 : kfree(rule->patterns[j].mask);
11870 : 0 : kfree(rule->patterns);
11871 : : }
11872 : 0 : kfree(coalesce->rules);
11873 : 0 : kfree(coalesce);
11874 : 0 : rdev->coalesce = NULL;
11875 : : }
11876 : :
11877 : : static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
11878 : : struct nlattr *rule,
11879 : : struct cfg80211_coalesce_rules *new_rule)
11880 : : {
11881 : : int err, i;
11882 : : const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
11883 : : struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
11884 : : int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
11885 : : struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
11886 : :
11887 : : err = nla_parse_nested_deprecated(tb, NL80211_ATTR_COALESCE_RULE_MAX,
11888 : : rule, nl80211_coalesce_policy, NULL);
11889 : : if (err)
11890 : : return err;
11891 : :
11892 : : if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
11893 : : new_rule->delay =
11894 : : nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
11895 : : if (new_rule->delay > coalesce->max_delay)
11896 : : return -EINVAL;
11897 : :
11898 : : if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
11899 : : new_rule->condition =
11900 : : nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
11901 : :
11902 : : if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
11903 : : return -EINVAL;
11904 : :
11905 : : nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
11906 : : rem)
11907 : : n_patterns++;
11908 : : if (n_patterns > coalesce->n_patterns)
11909 : : return -EINVAL;
11910 : :
11911 : : new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
11912 : : GFP_KERNEL);
11913 : : if (!new_rule->patterns)
11914 : : return -ENOMEM;
11915 : :
11916 : : new_rule->n_patterns = n_patterns;
11917 : : i = 0;
11918 : :
11919 : : nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
11920 : : rem) {
11921 : : u8 *mask_pat;
11922 : :
11923 : : err = nla_parse_nested_deprecated(pat_tb, MAX_NL80211_PKTPAT,
11924 : : pat,
11925 : : nl80211_packet_pattern_policy,
11926 : : NULL);
11927 : : if (err)
11928 : : return err;
11929 : :
11930 : : if (!pat_tb[NL80211_PKTPAT_MASK] ||
11931 : : !pat_tb[NL80211_PKTPAT_PATTERN])
11932 : : return -EINVAL;
11933 : : pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
11934 : : mask_len = DIV_ROUND_UP(pat_len, 8);
11935 : : if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
11936 : : return -EINVAL;
11937 : : if (pat_len > coalesce->pattern_max_len ||
11938 : : pat_len < coalesce->pattern_min_len)
11939 : : return -EINVAL;
11940 : :
11941 : : if (!pat_tb[NL80211_PKTPAT_OFFSET])
11942 : : pkt_offset = 0;
11943 : : else
11944 : : pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
11945 : : if (pkt_offset > coalesce->max_pkt_offset)
11946 : : return -EINVAL;
11947 : : new_rule->patterns[i].pkt_offset = pkt_offset;
11948 : :
11949 : : mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
11950 : : if (!mask_pat)
11951 : : return -ENOMEM;
11952 : :
11953 : : new_rule->patterns[i].mask = mask_pat;
11954 : : memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
11955 : : mask_len);
11956 : :
11957 : : mask_pat += mask_len;
11958 : : new_rule->patterns[i].pattern = mask_pat;
11959 : : new_rule->patterns[i].pattern_len = pat_len;
11960 : : memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
11961 : : pat_len);
11962 : : i++;
11963 : : }
11964 : :
11965 : : return 0;
11966 : : }
11967 : :
11968 : 0 : static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
11969 : : {
11970 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
11971 : 0 : const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
11972 : 0 : struct cfg80211_coalesce new_coalesce = {};
11973 : 0 : struct cfg80211_coalesce *n_coalesce;
11974 : 0 : int err, rem_rule, n_rules = 0, i, j;
11975 : 0 : struct nlattr *rule;
11976 : 0 : struct cfg80211_coalesce_rules *tmp_rule;
11977 : :
11978 [ # # # # ]: 0 : if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
11979 : : return -EOPNOTSUPP;
11980 : :
11981 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
11982 : 0 : cfg80211_rdev_free_coalesce(rdev);
11983 : 0 : rdev_set_coalesce(rdev, NULL);
11984 : 0 : return 0;
11985 : : }
11986 : :
11987 [ # # ]: 0 : nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
11988 : : rem_rule)
11989 : 0 : n_rules++;
11990 [ # # ]: 0 : if (n_rules > coalesce->n_rules)
11991 : : return -EINVAL;
11992 : :
11993 : 0 : new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
11994 : : GFP_KERNEL);
11995 [ # # ]: 0 : if (!new_coalesce.rules)
11996 : : return -ENOMEM;
11997 : :
11998 : 0 : new_coalesce.n_rules = n_rules;
11999 : 0 : i = 0;
12000 : :
12001 [ # # ]: 0 : nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
12002 : : rem_rule) {
12003 : 0 : err = nl80211_parse_coalesce_rule(rdev, rule,
12004 : 0 : &new_coalesce.rules[i]);
12005 [ # # ]: 0 : if (err)
12006 : 0 : goto error;
12007 : :
12008 : 0 : i++;
12009 : : }
12010 : :
12011 : 0 : err = rdev_set_coalesce(rdev, &new_coalesce);
12012 [ # # ]: 0 : if (err)
12013 : 0 : goto error;
12014 : :
12015 : 0 : n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
12016 [ # # ]: 0 : if (!n_coalesce) {
12017 : 0 : err = -ENOMEM;
12018 : 0 : goto error;
12019 : : }
12020 : 0 : cfg80211_rdev_free_coalesce(rdev);
12021 : 0 : rdev->coalesce = n_coalesce;
12022 : :
12023 : 0 : return 0;
12024 : 0 : error:
12025 [ # # ]: 0 : for (i = 0; i < new_coalesce.n_rules; i++) {
12026 : 0 : tmp_rule = &new_coalesce.rules[i];
12027 [ # # ]: 0 : for (j = 0; j < tmp_rule->n_patterns; j++)
12028 : 0 : kfree(tmp_rule->patterns[j].mask);
12029 : 0 : kfree(tmp_rule->patterns);
12030 : : }
12031 : 0 : kfree(new_coalesce.rules);
12032 : :
12033 : 0 : return err;
12034 : : }
12035 : :
12036 : 0 : static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
12037 : : {
12038 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12039 : 0 : struct net_device *dev = info->user_ptr[1];
12040 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
12041 : 0 : struct nlattr *tb[NUM_NL80211_REKEY_DATA];
12042 : 0 : struct cfg80211_gtk_rekey_data rekey_data;
12043 : 0 : int err;
12044 : :
12045 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_REKEY_DATA])
12046 : : return -EINVAL;
12047 : :
12048 : 0 : err = nla_parse_nested_deprecated(tb, MAX_NL80211_REKEY_DATA,
12049 : : info->attrs[NL80211_ATTR_REKEY_DATA],
12050 : : nl80211_rekey_policy, info->extack);
12051 [ # # ]: 0 : if (err)
12052 : : return err;
12053 : :
12054 [ # # # # ]: 0 : if (!tb[NL80211_REKEY_DATA_REPLAY_CTR] || !tb[NL80211_REKEY_DATA_KEK] ||
12055 [ # # ]: 0 : !tb[NL80211_REKEY_DATA_KCK])
12056 : : return -EINVAL;
12057 [ # # ]: 0 : if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
12058 : : return -ERANGE;
12059 [ # # ]: 0 : if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
12060 : : return -ERANGE;
12061 [ # # ]: 0 : if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
12062 : : return -ERANGE;
12063 : :
12064 : 0 : rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
12065 : 0 : rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
12066 : 0 : rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
12067 : :
12068 : 0 : wdev_lock(wdev);
12069 [ # # ]: 0 : if (!wdev->current_bss) {
12070 : 0 : err = -ENOTCONN;
12071 : 0 : goto out;
12072 : : }
12073 : :
12074 [ # # ]: 0 : if (!rdev->ops->set_rekey_data) {
12075 : 0 : err = -EOPNOTSUPP;
12076 : 0 : goto out;
12077 : : }
12078 : :
12079 : 0 : err = rdev_set_rekey_data(rdev, dev, &rekey_data);
12080 : 0 : out:
12081 : 0 : wdev_unlock(wdev);
12082 : 0 : return err;
12083 : : }
12084 : :
12085 : 0 : static int nl80211_register_unexpected_frame(struct sk_buff *skb,
12086 : : struct genl_info *info)
12087 : : {
12088 : 0 : struct net_device *dev = info->user_ptr[1];
12089 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
12090 : :
12091 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_AP &&
12092 : : wdev->iftype != NL80211_IFTYPE_P2P_GO)
12093 : : return -EINVAL;
12094 : :
12095 [ # # ]: 0 : if (wdev->ap_unexpected_nlportid)
12096 : : return -EBUSY;
12097 : :
12098 : 0 : wdev->ap_unexpected_nlportid = info->snd_portid;
12099 : 0 : return 0;
12100 : : }
12101 : :
12102 : 0 : static int nl80211_probe_client(struct sk_buff *skb,
12103 : : struct genl_info *info)
12104 : : {
12105 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12106 : 0 : struct net_device *dev = info->user_ptr[1];
12107 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
12108 : 0 : struct sk_buff *msg;
12109 : 0 : void *hdr;
12110 : 0 : const u8 *addr;
12111 : 0 : u64 cookie;
12112 : 0 : int err;
12113 : :
12114 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_AP &&
12115 : : wdev->iftype != NL80211_IFTYPE_P2P_GO)
12116 : : return -EOPNOTSUPP;
12117 : :
12118 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
12119 : : return -EINVAL;
12120 : :
12121 [ # # ]: 0 : if (!rdev->ops->probe_client)
12122 : : return -EOPNOTSUPP;
12123 : :
12124 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12125 [ # # ]: 0 : if (!msg)
12126 : : return -ENOMEM;
12127 : :
12128 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
12129 : : NL80211_CMD_PROBE_CLIENT);
12130 [ # # ]: 0 : if (!hdr) {
12131 : 0 : err = -ENOBUFS;
12132 : 0 : goto free_msg;
12133 : : }
12134 : :
12135 : 0 : addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
12136 : :
12137 : 0 : err = rdev_probe_client(rdev, dev, addr, &cookie);
12138 [ # # ]: 0 : if (err)
12139 : 0 : goto free_msg;
12140 : :
12141 [ # # ]: 0 : if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
12142 : : NL80211_ATTR_PAD))
12143 : 0 : goto nla_put_failure;
12144 : :
12145 : 0 : genlmsg_end(msg, hdr);
12146 : :
12147 : 0 : return genlmsg_reply(msg, info);
12148 : :
12149 : : nla_put_failure:
12150 : 0 : err = -ENOBUFS;
12151 : 0 : free_msg:
12152 : 0 : nlmsg_free(msg);
12153 : 0 : return err;
12154 : : }
12155 : :
12156 : 0 : static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
12157 : : {
12158 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12159 : 0 : struct cfg80211_beacon_registration *reg, *nreg;
12160 : 0 : int rv;
12161 : :
12162 [ # # ]: 0 : if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
12163 : : return -EOPNOTSUPP;
12164 : :
12165 : 0 : nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
12166 [ # # ]: 0 : if (!nreg)
12167 : : return -ENOMEM;
12168 : :
12169 : : /* First, check if already registered. */
12170 : 0 : spin_lock_bh(&rdev->beacon_registrations_lock);
12171 [ # # ]: 0 : list_for_each_entry(reg, &rdev->beacon_registrations, list) {
12172 [ # # ]: 0 : if (reg->nlportid == info->snd_portid) {
12173 : 0 : rv = -EALREADY;
12174 : 0 : goto out_err;
12175 : : }
12176 : : }
12177 : : /* Add it to the list */
12178 : 0 : nreg->nlportid = info->snd_portid;
12179 : 0 : list_add(&nreg->list, &rdev->beacon_registrations);
12180 : :
12181 : 0 : spin_unlock_bh(&rdev->beacon_registrations_lock);
12182 : :
12183 : 0 : return 0;
12184 : : out_err:
12185 : 0 : spin_unlock_bh(&rdev->beacon_registrations_lock);
12186 : 0 : kfree(nreg);
12187 : 0 : return rv;
12188 : : }
12189 : :
12190 : 0 : static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
12191 : : {
12192 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12193 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
12194 : 0 : int err;
12195 : :
12196 [ # # ]: 0 : if (!rdev->ops->start_p2p_device)
12197 : : return -EOPNOTSUPP;
12198 : :
12199 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
12200 : : return -EOPNOTSUPP;
12201 : :
12202 [ # # # # ]: 0 : if (wdev_running(wdev))
12203 : : return 0;
12204 : :
12205 [ # # ]: 0 : if (rfkill_blocked(rdev->rfkill))
12206 : : return -ERFKILL;
12207 : :
12208 : 0 : err = rdev_start_p2p_device(rdev, wdev);
12209 [ # # ]: 0 : if (err)
12210 : : return err;
12211 : :
12212 : 0 : wdev->is_running = true;
12213 : 0 : rdev->opencount++;
12214 : :
12215 : 0 : return 0;
12216 : : }
12217 : :
12218 : 0 : static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
12219 : : {
12220 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12221 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
12222 : :
12223 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
12224 : : return -EOPNOTSUPP;
12225 : :
12226 [ # # ]: 0 : if (!rdev->ops->stop_p2p_device)
12227 : : return -EOPNOTSUPP;
12228 : :
12229 : 0 : cfg80211_stop_p2p_device(rdev, wdev);
12230 : :
12231 : 0 : return 0;
12232 : : }
12233 : :
12234 : 0 : static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
12235 : : {
12236 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12237 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
12238 : 0 : struct cfg80211_nan_conf conf = {};
12239 : 0 : int err;
12240 : :
12241 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_NAN)
12242 : : return -EOPNOTSUPP;
12243 : :
12244 [ # # # # ]: 0 : if (wdev_running(wdev))
12245 : : return -EEXIST;
12246 : :
12247 [ # # ]: 0 : if (rfkill_blocked(rdev->rfkill))
12248 : : return -ERFKILL;
12249 : :
12250 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
12251 : : return -EINVAL;
12252 : :
12253 [ # # ]: 0 : conf.master_pref =
12254 : : nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
12255 : :
12256 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BANDS]) {
12257 [ # # ]: 0 : u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
12258 : :
12259 [ # # ]: 0 : if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
12260 : : return -EOPNOTSUPP;
12261 : :
12262 [ # # # # ]: 0 : if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
12263 : : return -EINVAL;
12264 : :
12265 : 0 : conf.bands = bands;
12266 : : }
12267 : :
12268 : 0 : err = rdev_start_nan(rdev, wdev, &conf);
12269 [ # # ]: 0 : if (err)
12270 : : return err;
12271 : :
12272 : 0 : wdev->is_running = true;
12273 : 0 : rdev->opencount++;
12274 : :
12275 : 0 : return 0;
12276 : : }
12277 : :
12278 : 0 : static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
12279 : : {
12280 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12281 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
12282 : :
12283 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_NAN)
12284 : : return -EOPNOTSUPP;
12285 : :
12286 : 0 : cfg80211_stop_nan(rdev, wdev);
12287 : :
12288 : 0 : return 0;
12289 : : }
12290 : :
12291 : 0 : static int validate_nan_filter(struct nlattr *filter_attr)
12292 : : {
12293 : 0 : struct nlattr *attr;
12294 : 0 : int len = 0, n_entries = 0, rem;
12295 : :
12296 [ # # ]: 0 : nla_for_each_nested(attr, filter_attr, rem) {
12297 : 0 : len += nla_len(attr);
12298 : 0 : n_entries++;
12299 : : }
12300 : :
12301 [ # # ]: 0 : if (len >= U8_MAX)
12302 : 0 : return -EINVAL;
12303 : :
12304 : : return n_entries;
12305 : : }
12306 : :
12307 : 0 : static int handle_nan_filter(struct nlattr *attr_filter,
12308 : : struct cfg80211_nan_func *func,
12309 : : bool tx)
12310 : : {
12311 : 0 : struct nlattr *attr;
12312 : 0 : int n_entries, rem, i;
12313 : 0 : struct cfg80211_nan_func_filter *filter;
12314 : :
12315 : 0 : n_entries = validate_nan_filter(attr_filter);
12316 [ # # ]: 0 : if (n_entries < 0)
12317 : : return n_entries;
12318 : :
12319 : 0 : BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters));
12320 : :
12321 : 0 : filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL);
12322 [ # # ]: 0 : if (!filter)
12323 : : return -ENOMEM;
12324 : :
12325 : 0 : i = 0;
12326 [ # # ]: 0 : nla_for_each_nested(attr, attr_filter, rem) {
12327 : 0 : filter[i].filter = nla_memdup(attr, GFP_KERNEL);
12328 : 0 : filter[i].len = nla_len(attr);
12329 : 0 : i++;
12330 : : }
12331 [ # # ]: 0 : if (tx) {
12332 : 0 : func->num_tx_filters = n_entries;
12333 : 0 : func->tx_filters = filter;
12334 : : } else {
12335 : 0 : func->num_rx_filters = n_entries;
12336 : 0 : func->rx_filters = filter;
12337 : : }
12338 : :
12339 : : return 0;
12340 : : }
12341 : :
12342 : 0 : static int nl80211_nan_add_func(struct sk_buff *skb,
12343 : : struct genl_info *info)
12344 : : {
12345 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12346 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
12347 : 0 : struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR], *func_attr;
12348 : 0 : struct cfg80211_nan_func *func;
12349 : 0 : struct sk_buff *msg = NULL;
12350 : 0 : void *hdr = NULL;
12351 : 0 : int err = 0;
12352 : :
12353 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_NAN)
12354 : : return -EOPNOTSUPP;
12355 : :
12356 [ # # # # ]: 0 : if (!wdev_running(wdev))
12357 : : return -ENOTCONN;
12358 : :
12359 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_NAN_FUNC])
12360 : : return -EINVAL;
12361 : :
12362 : 0 : err = nla_parse_nested_deprecated(tb, NL80211_NAN_FUNC_ATTR_MAX,
12363 : : info->attrs[NL80211_ATTR_NAN_FUNC],
12364 : : nl80211_nan_func_policy,
12365 : : info->extack);
12366 [ # # ]: 0 : if (err)
12367 : : return err;
12368 : :
12369 : 0 : func = kzalloc(sizeof(*func), GFP_KERNEL);
12370 [ # # ]: 0 : if (!func)
12371 : : return -ENOMEM;
12372 : :
12373 [ # # ]: 0 : func->cookie = cfg80211_assign_cookie(rdev);
12374 : :
12375 [ # # # # ]: 0 : if (!tb[NL80211_NAN_FUNC_TYPE] ||
12376 : : nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]) > NL80211_NAN_FUNC_MAX_TYPE) {
12377 : 0 : err = -EINVAL;
12378 : 0 : goto out;
12379 : : }
12380 : :
12381 : :
12382 [ # # ]: 0 : func->type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]);
12383 : :
12384 [ # # ]: 0 : if (!tb[NL80211_NAN_FUNC_SERVICE_ID]) {
12385 : 0 : err = -EINVAL;
12386 : 0 : goto out;
12387 : : }
12388 : :
12389 [ # # ]: 0 : memcpy(func->service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]),
12390 : : sizeof(func->service_id));
12391 : :
12392 : 0 : func->close_range =
12393 [ # # ]: 0 : nla_get_flag(tb[NL80211_NAN_FUNC_CLOSE_RANGE]);
12394 : :
12395 [ # # ]: 0 : if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) {
12396 : 0 : func->serv_spec_info_len =
12397 : 0 : nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
12398 : 0 : func->serv_spec_info =
12399 : 0 : kmemdup(nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]),
12400 : : func->serv_spec_info_len,
12401 : : GFP_KERNEL);
12402 [ # # ]: 0 : if (!func->serv_spec_info) {
12403 : 0 : err = -ENOMEM;
12404 : 0 : goto out;
12405 : : }
12406 : : }
12407 : :
12408 [ # # ]: 0 : if (tb[NL80211_NAN_FUNC_TTL])
12409 : 0 : func->ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]);
12410 : :
12411 [ # # # # ]: 0 : switch (func->type) {
12412 : 0 : case NL80211_NAN_FUNC_PUBLISH:
12413 [ # # ]: 0 : if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE]) {
12414 : 0 : err = -EINVAL;
12415 : 0 : goto out;
12416 : : }
12417 : :
12418 [ # # ]: 0 : func->publish_type =
12419 : : nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]);
12420 : 0 : func->publish_bcast =
12421 [ # # ]: 0 : nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]);
12422 : :
12423 [ # # # # ]: 0 : if ((!(func->publish_type & NL80211_NAN_SOLICITED_PUBLISH)) &&
12424 : : func->publish_bcast) {
12425 : 0 : err = -EINVAL;
12426 : 0 : goto out;
12427 : : }
12428 : : break;
12429 : 0 : case NL80211_NAN_FUNC_SUBSCRIBE:
12430 : 0 : func->subscribe_active =
12431 : 0 : nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]);
12432 : 0 : break;
12433 : 0 : case NL80211_NAN_FUNC_FOLLOW_UP:
12434 [ # # ]: 0 : if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] ||
12435 [ # # ]: 0 : !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] ||
12436 [ # # ]: 0 : !tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]) {
12437 : 0 : err = -EINVAL;
12438 : 0 : goto out;
12439 : : }
12440 : :
12441 [ # # ]: 0 : func->followup_id =
12442 : : nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]);
12443 : 0 : func->followup_reqid =
12444 : : nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]);
12445 : 0 : memcpy(func->followup_dest.addr,
12446 : : nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]),
12447 : : sizeof(func->followup_dest.addr));
12448 [ # # ]: 0 : if (func->ttl) {
12449 : 0 : err = -EINVAL;
12450 : 0 : goto out;
12451 : : }
12452 : : break;
12453 : 0 : default:
12454 : 0 : err = -EINVAL;
12455 : 0 : goto out;
12456 : : }
12457 : :
12458 [ # # ]: 0 : if (tb[NL80211_NAN_FUNC_SRF]) {
12459 : 0 : struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
12460 : :
12461 : 0 : err = nla_parse_nested_deprecated(srf_tb,
12462 : : NL80211_NAN_SRF_ATTR_MAX,
12463 : : tb[NL80211_NAN_FUNC_SRF],
12464 : : nl80211_nan_srf_policy,
12465 : : info->extack);
12466 [ # # ]: 0 : if (err)
12467 : 0 : goto out;
12468 : :
12469 : 0 : func->srf_include =
12470 [ # # ]: 0 : nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]);
12471 : :
12472 [ # # ]: 0 : if (srf_tb[NL80211_NAN_SRF_BF]) {
12473 [ # # ]: 0 : if (srf_tb[NL80211_NAN_SRF_MAC_ADDRS] ||
12474 [ # # ]: 0 : !srf_tb[NL80211_NAN_SRF_BF_IDX]) {
12475 : 0 : err = -EINVAL;
12476 : 0 : goto out;
12477 : : }
12478 : :
12479 : 0 : func->srf_bf_len =
12480 : 0 : nla_len(srf_tb[NL80211_NAN_SRF_BF]);
12481 : 0 : func->srf_bf =
12482 : 0 : kmemdup(nla_data(srf_tb[NL80211_NAN_SRF_BF]),
12483 : : func->srf_bf_len, GFP_KERNEL);
12484 [ # # ]: 0 : if (!func->srf_bf) {
12485 : 0 : err = -ENOMEM;
12486 : 0 : goto out;
12487 : : }
12488 : :
12489 : 0 : func->srf_bf_idx =
12490 : 0 : nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]);
12491 : : } else {
12492 : 0 : struct nlattr *attr, *mac_attr =
12493 : : srf_tb[NL80211_NAN_SRF_MAC_ADDRS];
12494 : 0 : int n_entries, rem, i = 0;
12495 : :
12496 [ # # ]: 0 : if (!mac_attr) {
12497 : 0 : err = -EINVAL;
12498 : 0 : goto out;
12499 : : }
12500 : :
12501 : 0 : n_entries = validate_acl_mac_addrs(mac_attr);
12502 [ # # ]: 0 : if (n_entries <= 0) {
12503 : 0 : err = -EINVAL;
12504 : 0 : goto out;
12505 : : }
12506 : :
12507 : 0 : func->srf_num_macs = n_entries;
12508 : 0 : func->srf_macs =
12509 : 0 : kcalloc(n_entries, sizeof(*func->srf_macs),
12510 : : GFP_KERNEL);
12511 [ # # ]: 0 : if (!func->srf_macs) {
12512 : 0 : err = -ENOMEM;
12513 : 0 : goto out;
12514 : : }
12515 : :
12516 [ # # ]: 0 : nla_for_each_nested(attr, mac_attr, rem)
12517 : 0 : memcpy(func->srf_macs[i++].addr, nla_data(attr),
12518 : : sizeof(*func->srf_macs));
12519 : : }
12520 : : }
12521 : :
12522 [ # # ]: 0 : if (tb[NL80211_NAN_FUNC_TX_MATCH_FILTER]) {
12523 : 0 : err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER],
12524 : : func, true);
12525 [ # # ]: 0 : if (err)
12526 : 0 : goto out;
12527 : : }
12528 : :
12529 [ # # ]: 0 : if (tb[NL80211_NAN_FUNC_RX_MATCH_FILTER]) {
12530 : 0 : err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER],
12531 : : func, false);
12532 [ # # ]: 0 : if (err)
12533 : 0 : goto out;
12534 : : }
12535 : :
12536 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12537 [ # # ]: 0 : if (!msg) {
12538 : 0 : err = -ENOMEM;
12539 : 0 : goto out;
12540 : : }
12541 : :
12542 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
12543 : : NL80211_CMD_ADD_NAN_FUNCTION);
12544 : : /* This can't really happen - we just allocated 4KB */
12545 [ # # # # ]: 0 : if (WARN_ON(!hdr)) {
12546 : 0 : err = -ENOMEM;
12547 : 0 : goto out;
12548 : : }
12549 : :
12550 : 0 : err = rdev_add_nan_func(rdev, wdev, func);
12551 : 0 : out:
12552 [ # # ]: 0 : if (err < 0) {
12553 : 0 : cfg80211_free_nan_func(func);
12554 : 0 : nlmsg_free(msg);
12555 : 0 : return err;
12556 : : }
12557 : :
12558 : : /* propagate the instance id and cookie to userspace */
12559 [ # # ]: 0 : if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, func->cookie,
12560 : : NL80211_ATTR_PAD))
12561 : 0 : goto nla_put_failure;
12562 : :
12563 : 0 : func_attr = nla_nest_start_noflag(msg, NL80211_ATTR_NAN_FUNC);
12564 [ # # ]: 0 : if (!func_attr)
12565 : 0 : goto nla_put_failure;
12566 : :
12567 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID,
12568 : 0 : func->instance_id))
12569 : 0 : goto nla_put_failure;
12570 : :
12571 : 0 : nla_nest_end(msg, func_attr);
12572 : :
12573 : 0 : genlmsg_end(msg, hdr);
12574 : 0 : return genlmsg_reply(msg, info);
12575 : :
12576 : 0 : nla_put_failure:
12577 : 0 : nlmsg_free(msg);
12578 : 0 : return -ENOBUFS;
12579 : : }
12580 : :
12581 : 0 : static int nl80211_nan_del_func(struct sk_buff *skb,
12582 : : struct genl_info *info)
12583 : : {
12584 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12585 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
12586 : 0 : u64 cookie;
12587 : :
12588 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_NAN)
12589 : : return -EOPNOTSUPP;
12590 : :
12591 [ # # # # ]: 0 : if (!wdev_running(wdev))
12592 : : return -ENOTCONN;
12593 : :
12594 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_COOKIE])
12595 : : return -EINVAL;
12596 : :
12597 : 0 : cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
12598 : :
12599 : 0 : rdev_del_nan_func(rdev, wdev, cookie);
12600 : :
12601 : 0 : return 0;
12602 : : }
12603 : :
12604 : 0 : static int nl80211_nan_change_config(struct sk_buff *skb,
12605 : : struct genl_info *info)
12606 : : {
12607 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12608 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
12609 : 0 : struct cfg80211_nan_conf conf = {};
12610 : 0 : u32 changed = 0;
12611 : :
12612 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_NAN)
12613 : : return -EOPNOTSUPP;
12614 : :
12615 [ # # # # ]: 0 : if (!wdev_running(wdev))
12616 : : return -ENOTCONN;
12617 : :
12618 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
12619 [ # # ]: 0 : conf.master_pref =
12620 : : nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
12621 [ # # ]: 0 : if (conf.master_pref <= 1 || conf.master_pref == 255)
12622 : : return -EINVAL;
12623 : :
12624 : : changed |= CFG80211_NAN_CONF_CHANGED_PREF;
12625 : : }
12626 : :
12627 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_BANDS]) {
12628 [ # # ]: 0 : u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
12629 : :
12630 [ # # ]: 0 : if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
12631 : : return -EOPNOTSUPP;
12632 : :
12633 [ # # # # ]: 0 : if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
12634 : : return -EINVAL;
12635 : :
12636 : 0 : conf.bands = bands;
12637 : 0 : changed |= CFG80211_NAN_CONF_CHANGED_BANDS;
12638 : : }
12639 : :
12640 [ # # ]: 0 : if (!changed)
12641 : : return -EINVAL;
12642 : :
12643 : 0 : return rdev_nan_change_conf(rdev, wdev, &conf, changed);
12644 : : }
12645 : :
12646 : 0 : void cfg80211_nan_match(struct wireless_dev *wdev,
12647 : : struct cfg80211_nan_match_params *match, gfp_t gfp)
12648 : : {
12649 : 0 : struct wiphy *wiphy = wdev->wiphy;
12650 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
12651 : 0 : struct nlattr *match_attr, *local_func_attr, *peer_func_attr;
12652 : 0 : struct sk_buff *msg;
12653 : 0 : void *hdr;
12654 : :
12655 [ # # # # : 0 : if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr))
# # # # #
# ]
12656 : : return;
12657 : :
12658 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
12659 [ # # ]: 0 : if (!msg)
12660 : : return;
12661 : :
12662 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH);
12663 [ # # ]: 0 : if (!hdr) {
12664 : 0 : nlmsg_free(msg);
12665 : 0 : return;
12666 : : }
12667 : :
12668 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
12669 [ # # # # ]: 0 : (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
12670 [ # # ]: 0 : wdev->netdev->ifindex)) ||
12671 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
12672 : : NL80211_ATTR_PAD))
12673 : 0 : goto nla_put_failure;
12674 : :
12675 [ # # ]: 0 : if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie,
12676 [ # # ]: 0 : NL80211_ATTR_PAD) ||
12677 : 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr))
12678 : 0 : goto nla_put_failure;
12679 : :
12680 : 0 : match_attr = nla_nest_start_noflag(msg, NL80211_ATTR_NAN_MATCH);
12681 [ # # ]: 0 : if (!match_attr)
12682 : 0 : goto nla_put_failure;
12683 : :
12684 : 0 : local_func_attr = nla_nest_start_noflag(msg,
12685 : : NL80211_NAN_MATCH_FUNC_LOCAL);
12686 [ # # ]: 0 : if (!local_func_attr)
12687 : 0 : goto nla_put_failure;
12688 : :
12689 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id))
12690 : 0 : goto nla_put_failure;
12691 : :
12692 : 0 : nla_nest_end(msg, local_func_attr);
12693 : :
12694 : 0 : peer_func_attr = nla_nest_start_noflag(msg,
12695 : : NL80211_NAN_MATCH_FUNC_PEER);
12696 [ # # ]: 0 : if (!peer_func_attr)
12697 : 0 : goto nla_put_failure;
12698 : :
12699 [ # # # # ]: 0 : if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) ||
12700 : 0 : nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id))
12701 : 0 : goto nla_put_failure;
12702 : :
12703 [ # # # # : 0 : if (match->info && match->info_len &&
# # ]
12704 : 0 : nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len,
12705 : : match->info))
12706 : 0 : goto nla_put_failure;
12707 : :
12708 [ # # ]: 0 : nla_nest_end(msg, peer_func_attr);
12709 : 0 : nla_nest_end(msg, match_attr);
12710 [ # # ]: 0 : genlmsg_end(msg, hdr);
12711 : :
12712 [ # # ]: 0 : if (!wdev->owner_nlportid)
12713 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
12714 : : msg, 0, NL80211_MCGRP_NAN, gfp);
12715 : : else
12716 : 0 : genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
12717 : : wdev->owner_nlportid);
12718 : :
12719 : : return;
12720 : :
12721 : 0 : nla_put_failure:
12722 : 0 : nlmsg_free(msg);
12723 : : }
12724 : : EXPORT_SYMBOL(cfg80211_nan_match);
12725 : :
12726 : 0 : void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
12727 : : u8 inst_id,
12728 : : enum nl80211_nan_func_term_reason reason,
12729 : : u64 cookie, gfp_t gfp)
12730 : : {
12731 : 0 : struct wiphy *wiphy = wdev->wiphy;
12732 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
12733 : 0 : struct sk_buff *msg;
12734 : 0 : struct nlattr *func_attr;
12735 : 0 : void *hdr;
12736 : :
12737 [ # # # # ]: 0 : if (WARN_ON(!inst_id))
12738 : : return;
12739 : :
12740 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
12741 [ # # ]: 0 : if (!msg)
12742 : : return;
12743 : :
12744 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_NAN_FUNCTION);
12745 [ # # ]: 0 : if (!hdr) {
12746 : 0 : nlmsg_free(msg);
12747 : 0 : return;
12748 : : }
12749 : :
12750 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
12751 [ # # # # ]: 0 : (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
12752 [ # # ]: 0 : wdev->netdev->ifindex)) ||
12753 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
12754 : : NL80211_ATTR_PAD))
12755 : 0 : goto nla_put_failure;
12756 : :
12757 [ # # ]: 0 : if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
12758 : : NL80211_ATTR_PAD))
12759 : 0 : goto nla_put_failure;
12760 : :
12761 : 0 : func_attr = nla_nest_start_noflag(msg, NL80211_ATTR_NAN_FUNC);
12762 [ # # ]: 0 : if (!func_attr)
12763 : 0 : goto nla_put_failure;
12764 : :
12765 [ # # # # ]: 0 : if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, inst_id) ||
12766 : 0 : nla_put_u8(msg, NL80211_NAN_FUNC_TERM_REASON, reason))
12767 : 0 : goto nla_put_failure;
12768 : :
12769 [ # # ]: 0 : nla_nest_end(msg, func_attr);
12770 [ # # ]: 0 : genlmsg_end(msg, hdr);
12771 : :
12772 [ # # ]: 0 : if (!wdev->owner_nlportid)
12773 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
12774 : : msg, 0, NL80211_MCGRP_NAN, gfp);
12775 : : else
12776 : 0 : genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
12777 : : wdev->owner_nlportid);
12778 : :
12779 : : return;
12780 : :
12781 : 0 : nla_put_failure:
12782 : 0 : nlmsg_free(msg);
12783 : : }
12784 : : EXPORT_SYMBOL(cfg80211_nan_func_terminated);
12785 : :
12786 : 0 : static int nl80211_get_protocol_features(struct sk_buff *skb,
12787 : : struct genl_info *info)
12788 : : {
12789 : 0 : void *hdr;
12790 : 0 : struct sk_buff *msg;
12791 : :
12792 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12793 [ # # ]: 0 : if (!msg)
12794 : : return -ENOMEM;
12795 : :
12796 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
12797 : : NL80211_CMD_GET_PROTOCOL_FEATURES);
12798 [ # # ]: 0 : if (!hdr)
12799 : 0 : goto nla_put_failure;
12800 : :
12801 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
12802 : : NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
12803 : 0 : goto nla_put_failure;
12804 : :
12805 : 0 : genlmsg_end(msg, hdr);
12806 : 0 : return genlmsg_reply(msg, info);
12807 : :
12808 : 0 : nla_put_failure:
12809 : 0 : kfree_skb(msg);
12810 : 0 : return -ENOBUFS;
12811 : : }
12812 : :
12813 : 0 : static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
12814 : : {
12815 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12816 : 0 : struct cfg80211_update_ft_ies_params ft_params;
12817 : 0 : struct net_device *dev = info->user_ptr[1];
12818 : :
12819 [ # # ]: 0 : if (!rdev->ops->update_ft_ies)
12820 : : return -EOPNOTSUPP;
12821 : :
12822 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MDID] ||
12823 [ # # ]: 0 : !info->attrs[NL80211_ATTR_IE])
12824 : : return -EINVAL;
12825 : :
12826 : 0 : memset(&ft_params, 0, sizeof(ft_params));
12827 : 0 : ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
12828 : 0 : ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
12829 : 0 : ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
12830 : :
12831 : 0 : return rdev_update_ft_ies(rdev, dev, &ft_params);
12832 : : }
12833 : :
12834 : 0 : static int nl80211_crit_protocol_start(struct sk_buff *skb,
12835 : : struct genl_info *info)
12836 : : {
12837 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12838 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
12839 : 0 : enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
12840 : 0 : u16 duration;
12841 : 0 : int ret;
12842 : :
12843 [ # # ]: 0 : if (!rdev->ops->crit_proto_start)
12844 : : return -EOPNOTSUPP;
12845 : :
12846 [ # # # # ]: 0 : if (WARN_ON(!rdev->ops->crit_proto_stop))
12847 : : return -EINVAL;
12848 : :
12849 [ # # ]: 0 : if (rdev->crit_proto_nlportid)
12850 : : return -EBUSY;
12851 : :
12852 : : /* determine protocol if provided */
12853 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
12854 [ # # ]: 0 : proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
12855 : :
12856 [ # # ]: 0 : if (proto >= NUM_NL80211_CRIT_PROTO)
12857 : : return -EINVAL;
12858 : :
12859 : : /* timeout must be provided */
12860 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
12861 : : return -EINVAL;
12862 : :
12863 [ # # ]: 0 : duration =
12864 : : nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
12865 : :
12866 [ # # ]: 0 : if (duration > NL80211_CRIT_PROTO_MAX_DURATION)
12867 : : return -ERANGE;
12868 : :
12869 : 0 : ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
12870 [ # # ]: 0 : if (!ret)
12871 : 0 : rdev->crit_proto_nlportid = info->snd_portid;
12872 : :
12873 : : return ret;
12874 : : }
12875 : :
12876 : 0 : static int nl80211_crit_protocol_stop(struct sk_buff *skb,
12877 : : struct genl_info *info)
12878 : : {
12879 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12880 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
12881 : :
12882 [ # # ]: 0 : if (!rdev->ops->crit_proto_stop)
12883 : : return -EOPNOTSUPP;
12884 : :
12885 [ # # ]: 0 : if (rdev->crit_proto_nlportid) {
12886 : 0 : rdev->crit_proto_nlportid = 0;
12887 : 0 : rdev_crit_proto_stop(rdev, wdev);
12888 : : }
12889 : : return 0;
12890 : : }
12891 : :
12892 : : static int nl80211_vendor_check_policy(const struct wiphy_vendor_command *vcmd,
12893 : : struct nlattr *attr,
12894 : : struct netlink_ext_ack *extack)
12895 : : {
12896 : : if (vcmd->policy == VENDOR_CMD_RAW_DATA) {
12897 : : if (attr->nla_type & NLA_F_NESTED) {
12898 : : NL_SET_ERR_MSG_ATTR(extack, attr,
12899 : : "unexpected nested data");
12900 : : return -EINVAL;
12901 : : }
12902 : :
12903 : : return 0;
12904 : : }
12905 : :
12906 : : if (!(attr->nla_type & NLA_F_NESTED)) {
12907 : : NL_SET_ERR_MSG_ATTR(extack, attr, "expected nested data");
12908 : : return -EINVAL;
12909 : : }
12910 : :
12911 : : return nla_validate_nested(attr, vcmd->maxattr, vcmd->policy, extack);
12912 : : }
12913 : :
12914 : 0 : static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
12915 : : {
12916 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
12917 : 0 : struct wireless_dev *wdev =
12918 : 0 : __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
12919 : 0 : int i, err;
12920 : 0 : u32 vid, subcmd;
12921 : :
12922 [ # # ]: 0 : if (!rdev->wiphy.vendor_commands)
12923 : : return -EOPNOTSUPP;
12924 : :
12925 [ # # ]: 0 : if (IS_ERR(wdev)) {
12926 [ # # ]: 0 : err = PTR_ERR(wdev);
12927 [ # # ]: 0 : if (err != -EINVAL)
12928 : : return err;
12929 : : wdev = NULL;
12930 [ # # ]: 0 : } else if (wdev->wiphy != &rdev->wiphy) {
12931 : : return -EINVAL;
12932 : : }
12933 : :
12934 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
12935 [ # # ]: 0 : !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
12936 : : return -EINVAL;
12937 : :
12938 : 0 : vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
12939 : 0 : subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
12940 [ # # ]: 0 : for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
12941 : 0 : const struct wiphy_vendor_command *vcmd;
12942 : 0 : void *data = NULL;
12943 : 0 : int len = 0;
12944 : :
12945 : 0 : vcmd = &rdev->wiphy.vendor_commands[i];
12946 : :
12947 [ # # # # ]: 0 : if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
12948 : 0 : continue;
12949 : :
12950 [ # # ]: 0 : if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
12951 : : WIPHY_VENDOR_CMD_NEED_NETDEV)) {
12952 [ # # ]: 0 : if (!wdev)
12953 : : return -EINVAL;
12954 [ # # ]: 0 : if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
12955 [ # # ]: 0 : !wdev->netdev)
12956 : : return -EINVAL;
12957 : :
12958 [ # # ]: 0 : if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
12959 [ # # # # ]: 0 : if (!wdev_running(wdev))
12960 : : return -ENETDOWN;
12961 : : }
12962 : :
12963 [ # # ]: 0 : if (!vcmd->doit)
12964 : : return -EOPNOTSUPP;
12965 : : } else {
12966 : : wdev = NULL;
12967 : : }
12968 : :
12969 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
12970 : 0 : data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
12971 : 0 : len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
12972 : :
12973 : 0 : err = nl80211_vendor_check_policy(vcmd,
12974 : : info->attrs[NL80211_ATTR_VENDOR_DATA],
12975 : : info->extack);
12976 [ # # ]: 0 : if (err)
12977 : : return err;
12978 : : }
12979 : :
12980 : 0 : rdev->cur_cmd_info = info;
12981 : 0 : err = vcmd->doit(&rdev->wiphy, wdev, data, len);
12982 : 0 : rdev->cur_cmd_info = NULL;
12983 : 0 : return err;
12984 : : }
12985 : :
12986 : : return -EOPNOTSUPP;
12987 : : }
12988 : :
12989 : : static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
12990 : : struct netlink_callback *cb,
12991 : : struct cfg80211_registered_device **rdev,
12992 : : struct wireless_dev **wdev)
12993 : : {
12994 : : struct nlattr **attrbuf;
12995 : : u32 vid, subcmd;
12996 : : unsigned int i;
12997 : : int vcmd_idx = -1;
12998 : : int err;
12999 : : void *data = NULL;
13000 : : unsigned int data_len = 0;
13001 : :
13002 : : if (cb->args[0]) {
13003 : : /* subtract the 1 again here */
13004 : : struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
13005 : : struct wireless_dev *tmp;
13006 : :
13007 : : if (!wiphy)
13008 : : return -ENODEV;
13009 : : *rdev = wiphy_to_rdev(wiphy);
13010 : : *wdev = NULL;
13011 : :
13012 : : if (cb->args[1]) {
13013 : : list_for_each_entry(tmp, &wiphy->wdev_list, list) {
13014 : : if (tmp->identifier == cb->args[1] - 1) {
13015 : : *wdev = tmp;
13016 : : break;
13017 : : }
13018 : : }
13019 : : }
13020 : :
13021 : : /* keep rtnl locked in successful case */
13022 : : return 0;
13023 : : }
13024 : :
13025 : : attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
13026 : : if (!attrbuf)
13027 : : return -ENOMEM;
13028 : :
13029 : : err = nlmsg_parse_deprecated(cb->nlh,
13030 : : GENL_HDRLEN + nl80211_fam.hdrsize,
13031 : : attrbuf, nl80211_fam.maxattr,
13032 : : nl80211_policy, NULL);
13033 : : if (err)
13034 : : goto out;
13035 : :
13036 : : if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
13037 : : !attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
13038 : : err = -EINVAL;
13039 : : goto out;
13040 : : }
13041 : :
13042 : : *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
13043 : : if (IS_ERR(*wdev))
13044 : : *wdev = NULL;
13045 : :
13046 : : *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
13047 : : if (IS_ERR(*rdev)) {
13048 : : err = PTR_ERR(*rdev);
13049 : : goto out;
13050 : : }
13051 : :
13052 : : vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
13053 : : subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
13054 : :
13055 : : for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
13056 : : const struct wiphy_vendor_command *vcmd;
13057 : :
13058 : : vcmd = &(*rdev)->wiphy.vendor_commands[i];
13059 : :
13060 : : if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
13061 : : continue;
13062 : :
13063 : : if (!vcmd->dumpit) {
13064 : : err = -EOPNOTSUPP;
13065 : : goto out;
13066 : : }
13067 : :
13068 : : vcmd_idx = i;
13069 : : break;
13070 : : }
13071 : :
13072 : : if (vcmd_idx < 0) {
13073 : : err = -EOPNOTSUPP;
13074 : : goto out;
13075 : : }
13076 : :
13077 : : if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
13078 : : data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
13079 : : data_len = nla_len(attrbuf[NL80211_ATTR_VENDOR_DATA]);
13080 : :
13081 : : err = nl80211_vendor_check_policy(
13082 : : &(*rdev)->wiphy.vendor_commands[vcmd_idx],
13083 : : attrbuf[NL80211_ATTR_VENDOR_DATA],
13084 : : cb->extack);
13085 : : if (err)
13086 : : goto out;
13087 : : }
13088 : :
13089 : : /* 0 is the first index - add 1 to parse only once */
13090 : : cb->args[0] = (*rdev)->wiphy_idx + 1;
13091 : : /* add 1 to know if it was NULL */
13092 : : cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
13093 : : cb->args[2] = vcmd_idx;
13094 : : cb->args[3] = (unsigned long)data;
13095 : : cb->args[4] = data_len;
13096 : :
13097 : : /* keep rtnl locked in successful case */
13098 : : err = 0;
13099 : : out:
13100 : : kfree(attrbuf);
13101 : : return err;
13102 : : }
13103 : :
13104 : 0 : static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
13105 : : struct netlink_callback *cb)
13106 : : {
13107 : 0 : struct cfg80211_registered_device *rdev;
13108 : 0 : struct wireless_dev *wdev;
13109 : 0 : unsigned int vcmd_idx;
13110 : 0 : const struct wiphy_vendor_command *vcmd;
13111 : 0 : void *data;
13112 : 0 : int data_len;
13113 : 0 : int err;
13114 : 0 : struct nlattr *vendor_data;
13115 : :
13116 : 0 : rtnl_lock();
13117 : 0 : err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
13118 [ # # ]: 0 : if (err)
13119 : 0 : goto out;
13120 : :
13121 : 0 : vcmd_idx = cb->args[2];
13122 : 0 : data = (void *)cb->args[3];
13123 : 0 : data_len = cb->args[4];
13124 : 0 : vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
13125 : :
13126 [ # # ]: 0 : if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
13127 : : WIPHY_VENDOR_CMD_NEED_NETDEV)) {
13128 [ # # ]: 0 : if (!wdev) {
13129 : 0 : err = -EINVAL;
13130 : 0 : goto out;
13131 : : }
13132 [ # # ]: 0 : if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
13133 [ # # ]: 0 : !wdev->netdev) {
13134 : 0 : err = -EINVAL;
13135 : 0 : goto out;
13136 : : }
13137 : :
13138 [ # # ]: 0 : if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
13139 [ # # # # ]: 0 : if (!wdev_running(wdev)) {
13140 : 0 : err = -ENETDOWN;
13141 : 0 : goto out;
13142 : : }
13143 : : }
13144 : : }
13145 : :
13146 : 0 : while (1) {
13147 : 0 : void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
13148 : 0 : cb->nlh->nlmsg_seq, NLM_F_MULTI,
13149 : : NL80211_CMD_VENDOR);
13150 [ # # ]: 0 : if (!hdr)
13151 : : break;
13152 : :
13153 [ # # ]: 0 : if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13154 [ # # # # : 0 : (wdev && nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
# # ]
13155 : : wdev_id(wdev),
13156 : : NL80211_ATTR_PAD))) {
13157 : 0 : genlmsg_cancel(skb, hdr);
13158 : : break;
13159 : : }
13160 : :
13161 : 0 : vendor_data = nla_nest_start_noflag(skb,
13162 : : NL80211_ATTR_VENDOR_DATA);
13163 [ # # ]: 0 : if (!vendor_data) {
13164 : 0 : genlmsg_cancel(skb, hdr);
13165 : : break;
13166 : : }
13167 : :
13168 : 0 : err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
13169 : 0 : (unsigned long *)&cb->args[5]);
13170 [ # # ]: 0 : nla_nest_end(skb, vendor_data);
13171 : :
13172 [ # # ]: 0 : if (err == -ENOBUFS || err == -ENOENT) {
13173 : 0 : genlmsg_cancel(skb, hdr);
13174 : : break;
13175 [ # # ]: 0 : } else if (err) {
13176 : 0 : genlmsg_cancel(skb, hdr);
13177 : 0 : goto out;
13178 : : }
13179 : :
13180 : 0 : genlmsg_end(skb, hdr);
13181 : : }
13182 : :
13183 : 0 : err = skb->len;
13184 : 0 : out:
13185 : 0 : rtnl_unlock();
13186 : 0 : return err;
13187 : : }
13188 : :
13189 : 0 : struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
13190 : : enum nl80211_commands cmd,
13191 : : enum nl80211_attrs attr,
13192 : : int approxlen)
13193 : : {
13194 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
13195 : :
13196 [ # # # # ]: 0 : if (WARN_ON(!rdev->cur_cmd_info))
13197 : : return NULL;
13198 : :
13199 : 0 : return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
13200 : : rdev->cur_cmd_info->snd_portid,
13201 : : rdev->cur_cmd_info->snd_seq,
13202 : : cmd, attr, NULL, GFP_KERNEL);
13203 : : }
13204 : : EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
13205 : :
13206 : 0 : int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
13207 : : {
13208 : 0 : struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
13209 : 0 : void *hdr = ((void **)skb->cb)[1];
13210 : 0 : struct nlattr *data = ((void **)skb->cb)[2];
13211 : :
13212 : : /* clear CB data for netlink core to own from now on */
13213 : 0 : memset(skb->cb, 0, sizeof(skb->cb));
13214 : :
13215 [ # # # # ]: 0 : if (WARN_ON(!rdev->cur_cmd_info)) {
13216 : 0 : kfree_skb(skb);
13217 : 0 : return -EINVAL;
13218 : : }
13219 : :
13220 : 0 : nla_nest_end(skb, data);
13221 : 0 : genlmsg_end(skb, hdr);
13222 : 0 : return genlmsg_reply(skb, rdev->cur_cmd_info);
13223 : : }
13224 : : EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
13225 : :
13226 : 0 : unsigned int cfg80211_vendor_cmd_get_sender(struct wiphy *wiphy)
13227 : : {
13228 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
13229 : :
13230 [ # # # # ]: 0 : if (WARN_ON(!rdev->cur_cmd_info))
13231 : : return 0;
13232 : :
13233 : 0 : return rdev->cur_cmd_info->snd_portid;
13234 : : }
13235 : : EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_get_sender);
13236 : :
13237 : 0 : static int nl80211_set_qos_map(struct sk_buff *skb,
13238 : : struct genl_info *info)
13239 : : {
13240 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13241 : 0 : struct cfg80211_qos_map *qos_map = NULL;
13242 : 0 : struct net_device *dev = info->user_ptr[1];
13243 : 0 : u8 *pos, len, num_des, des_len, des;
13244 : 0 : int ret;
13245 : :
13246 [ # # ]: 0 : if (!rdev->ops->set_qos_map)
13247 : : return -EOPNOTSUPP;
13248 : :
13249 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_QOS_MAP]) {
13250 [ # # ]: 0 : pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
13251 [ # # ]: 0 : len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
13252 : :
13253 [ # # # # ]: 0 : if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
13254 : : len > IEEE80211_QOS_MAP_LEN_MAX)
13255 : : return -EINVAL;
13256 : :
13257 : 0 : qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
13258 [ # # ]: 0 : if (!qos_map)
13259 : : return -ENOMEM;
13260 : :
13261 : 0 : num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
13262 [ # # ]: 0 : if (num_des) {
13263 : 0 : des_len = num_des *
13264 : : sizeof(struct cfg80211_dscp_exception);
13265 : 0 : memcpy(qos_map->dscp_exception, pos, des_len);
13266 : 0 : qos_map->num_des = num_des;
13267 [ # # ]: 0 : for (des = 0; des < num_des; des++) {
13268 [ # # ]: 0 : if (qos_map->dscp_exception[des].up > 7) {
13269 : 0 : kfree(qos_map);
13270 : 0 : return -EINVAL;
13271 : : }
13272 : : }
13273 : 0 : pos += des_len;
13274 : : }
13275 : 0 : memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
13276 : : }
13277 : :
13278 : 0 : wdev_lock(dev->ieee80211_ptr);
13279 [ # # # ]: 0 : ret = nl80211_key_allowed(dev->ieee80211_ptr);
13280 : 0 : if (!ret)
13281 : 0 : ret = rdev_set_qos_map(rdev, dev, qos_map);
13282 : 0 : wdev_unlock(dev->ieee80211_ptr);
13283 : :
13284 : 0 : kfree(qos_map);
13285 : 0 : return ret;
13286 : : }
13287 : :
13288 : 0 : static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
13289 : : {
13290 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13291 : 0 : struct net_device *dev = info->user_ptr[1];
13292 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
13293 : 0 : const u8 *peer;
13294 : 0 : u8 tsid, up;
13295 : 0 : u16 admitted_time = 0;
13296 : 0 : int err;
13297 : :
13298 [ # # ]: 0 : if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
13299 : : return -EOPNOTSUPP;
13300 : :
13301 [ # # # # ]: 0 : if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
13302 [ # # ]: 0 : !info->attrs[NL80211_ATTR_USER_PRIO])
13303 : : return -EINVAL;
13304 : :
13305 [ # # ]: 0 : tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
13306 : 0 : up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
13307 : :
13308 : : /* WMM uses TIDs 0-7 even for TSPEC */
13309 [ # # ]: 0 : if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
13310 : : /* TODO: handle 802.11 TSPEC/admission control
13311 : : * need more attributes for that (e.g. BA session requirement);
13312 : : * change the WMM adminssion test above to allow both then
13313 : : */
13314 : : return -EINVAL;
13315 : : }
13316 : :
13317 [ # # ]: 0 : peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
13318 : :
13319 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
13320 [ # # ]: 0 : admitted_time =
13321 : : nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
13322 [ # # ]: 0 : if (!admitted_time)
13323 : : return -EINVAL;
13324 : : }
13325 : :
13326 : 0 : wdev_lock(wdev);
13327 [ # # ]: 0 : switch (wdev->iftype) {
13328 : 0 : case NL80211_IFTYPE_STATION:
13329 : : case NL80211_IFTYPE_P2P_CLIENT:
13330 [ # # ]: 0 : if (wdev->current_bss)
13331 : : break;
13332 : 0 : err = -ENOTCONN;
13333 : 0 : goto out;
13334 : 0 : default:
13335 : 0 : err = -EOPNOTSUPP;
13336 : 0 : goto out;
13337 : : }
13338 : :
13339 : 0 : err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
13340 : :
13341 : 0 : out:
13342 : 0 : wdev_unlock(wdev);
13343 : 0 : return err;
13344 : : }
13345 : :
13346 : 0 : static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
13347 : : {
13348 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13349 : 0 : struct net_device *dev = info->user_ptr[1];
13350 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
13351 : 0 : const u8 *peer;
13352 : 0 : u8 tsid;
13353 : 0 : int err;
13354 : :
13355 [ # # # # ]: 0 : if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
13356 : : return -EINVAL;
13357 : :
13358 : 0 : tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
13359 : 0 : peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
13360 : :
13361 : 0 : wdev_lock(wdev);
13362 : 0 : err = rdev_del_tx_ts(rdev, dev, tsid, peer);
13363 : 0 : wdev_unlock(wdev);
13364 : :
13365 : 0 : return err;
13366 : : }
13367 : :
13368 : 0 : static int nl80211_tdls_channel_switch(struct sk_buff *skb,
13369 : : struct genl_info *info)
13370 : : {
13371 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13372 : 0 : struct net_device *dev = info->user_ptr[1];
13373 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
13374 : 0 : struct cfg80211_chan_def chandef = {};
13375 : 0 : const u8 *addr;
13376 : 0 : u8 oper_class;
13377 : 0 : int err;
13378 : :
13379 [ # # ]: 0 : if (!rdev->ops->tdls_channel_switch ||
13380 [ # # ]: 0 : !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
13381 : : return -EOPNOTSUPP;
13382 : :
13383 [ # # ]: 0 : switch (dev->ieee80211_ptr->iftype) {
13384 : : case NL80211_IFTYPE_STATION:
13385 : : case NL80211_IFTYPE_P2P_CLIENT:
13386 : 0 : break;
13387 : : default:
13388 : : return -EOPNOTSUPP;
13389 : : }
13390 : :
13391 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC] ||
13392 [ # # ]: 0 : !info->attrs[NL80211_ATTR_OPER_CLASS])
13393 : : return -EINVAL;
13394 : :
13395 : 0 : err = nl80211_parse_chandef(rdev, info, &chandef);
13396 [ # # ]: 0 : if (err)
13397 : : return err;
13398 : :
13399 : : /*
13400 : : * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012
13401 : : * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the
13402 : : * specification is not defined for them.
13403 : : */
13404 [ # # ]: 0 : if (chandef.chan->band == NL80211_BAND_2GHZ &&
13405 [ # # # # ]: 0 : chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
13406 : : chandef.width != NL80211_CHAN_WIDTH_20)
13407 : : return -EINVAL;
13408 : :
13409 : : /* we will be active on the TDLS link */
13410 [ # # ]: 0 : if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
13411 : : wdev->iftype))
13412 : : return -EINVAL;
13413 : :
13414 : : /* don't allow switching to DFS channels */
13415 [ # # ]: 0 : if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype))
13416 : : return -EINVAL;
13417 : :
13418 : 0 : addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
13419 : 0 : oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]);
13420 : :
13421 : 0 : wdev_lock(wdev);
13422 : 0 : err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef);
13423 : 0 : wdev_unlock(wdev);
13424 : :
13425 : 0 : return err;
13426 : : }
13427 : :
13428 : 0 : static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
13429 : : struct genl_info *info)
13430 : : {
13431 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13432 : 0 : struct net_device *dev = info->user_ptr[1];
13433 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
13434 : 0 : const u8 *addr;
13435 : :
13436 [ # # ]: 0 : if (!rdev->ops->tdls_channel_switch ||
13437 [ # # ]: 0 : !rdev->ops->tdls_cancel_channel_switch ||
13438 [ # # ]: 0 : !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
13439 : : return -EOPNOTSUPP;
13440 : :
13441 [ # # ]: 0 : switch (dev->ieee80211_ptr->iftype) {
13442 : : case NL80211_IFTYPE_STATION:
13443 : : case NL80211_IFTYPE_P2P_CLIENT:
13444 : 0 : break;
13445 : : default:
13446 : : return -EOPNOTSUPP;
13447 : : }
13448 : :
13449 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
13450 : : return -EINVAL;
13451 : :
13452 : 0 : addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
13453 : :
13454 : 0 : wdev_lock(wdev);
13455 : 0 : rdev_tdls_cancel_channel_switch(rdev, dev, addr);
13456 : 0 : wdev_unlock(wdev);
13457 : :
13458 : 0 : return 0;
13459 : : }
13460 : :
13461 : 0 : static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
13462 : : struct genl_info *info)
13463 : : {
13464 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13465 : 0 : struct net_device *dev = info->user_ptr[1];
13466 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
13467 : 0 : const struct nlattr *nla;
13468 : 0 : bool enabled;
13469 : :
13470 [ # # ]: 0 : if (!rdev->ops->set_multicast_to_unicast)
13471 : : return -EOPNOTSUPP;
13472 : :
13473 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_AP &&
13474 : : wdev->iftype != NL80211_IFTYPE_P2P_GO)
13475 : : return -EOPNOTSUPP;
13476 : :
13477 : 0 : nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
13478 : 0 : enabled = nla_get_flag(nla);
13479 : :
13480 : 0 : return rdev_set_multicast_to_unicast(rdev, dev, enabled);
13481 : : }
13482 : :
13483 : 0 : static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
13484 : : {
13485 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13486 : 0 : struct net_device *dev = info->user_ptr[1];
13487 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
13488 : 0 : struct cfg80211_pmk_conf pmk_conf = {};
13489 : 0 : int ret;
13490 : :
13491 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_STATION &&
13492 : : wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
13493 : : return -EOPNOTSUPP;
13494 : :
13495 [ # # ]: 0 : if (!wiphy_ext_feature_isset(&rdev->wiphy,
13496 : : NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
13497 : : return -EOPNOTSUPP;
13498 : :
13499 [ # # # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC] || !info->attrs[NL80211_ATTR_PMK])
13500 : : return -EINVAL;
13501 : :
13502 : 0 : wdev_lock(wdev);
13503 [ # # ]: 0 : if (!wdev->current_bss) {
13504 : 0 : ret = -ENOTCONN;
13505 : 0 : goto out;
13506 : : }
13507 : :
13508 [ # # ]: 0 : pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
13509 [ # # ]: 0 : if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) {
13510 : 0 : ret = -EINVAL;
13511 : 0 : goto out;
13512 : : }
13513 : :
13514 [ # # ]: 0 : pmk_conf.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
13515 [ # # ]: 0 : pmk_conf.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
13516 [ # # ]: 0 : if (pmk_conf.pmk_len != WLAN_PMK_LEN &&
13517 : : pmk_conf.pmk_len != WLAN_PMK_LEN_SUITE_B_192) {
13518 : 0 : ret = -EINVAL;
13519 : 0 : goto out;
13520 : : }
13521 : :
13522 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_PMKR0_NAME]) {
13523 [ # # ]: 0 : int r0_name_len = nla_len(info->attrs[NL80211_ATTR_PMKR0_NAME]);
13524 : :
13525 [ # # ]: 0 : if (r0_name_len != WLAN_PMK_NAME_LEN) {
13526 : 0 : ret = -EINVAL;
13527 : 0 : goto out;
13528 : : }
13529 : :
13530 : 0 : pmk_conf.pmk_r0_name =
13531 : : nla_data(info->attrs[NL80211_ATTR_PMKR0_NAME]);
13532 : : }
13533 : :
13534 : 0 : ret = rdev_set_pmk(rdev, dev, &pmk_conf);
13535 : 0 : out:
13536 : 0 : wdev_unlock(wdev);
13537 : 0 : return ret;
13538 : : }
13539 : :
13540 : 0 : static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
13541 : : {
13542 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13543 : 0 : struct net_device *dev = info->user_ptr[1];
13544 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
13545 : 0 : const u8 *aa;
13546 : 0 : int ret;
13547 : :
13548 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_STATION &&
13549 : : wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
13550 : : return -EOPNOTSUPP;
13551 : :
13552 [ # # ]: 0 : if (!wiphy_ext_feature_isset(&rdev->wiphy,
13553 : : NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
13554 : : return -EOPNOTSUPP;
13555 : :
13556 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC])
13557 : : return -EINVAL;
13558 : :
13559 : 0 : wdev_lock(wdev);
13560 : 0 : aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
13561 : 0 : ret = rdev_del_pmk(rdev, dev, aa);
13562 : 0 : wdev_unlock(wdev);
13563 : :
13564 : 0 : return ret;
13565 : : }
13566 : :
13567 : 0 : static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info)
13568 : : {
13569 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13570 : 0 : struct net_device *dev = info->user_ptr[1];
13571 : 0 : struct cfg80211_external_auth_params params;
13572 : :
13573 [ # # ]: 0 : if (!rdev->ops->external_auth)
13574 : : return -EOPNOTSUPP;
13575 : :
13576 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_SSID] &&
13577 [ # # # # ]: 0 : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
13578 : : dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
13579 : : return -EINVAL;
13580 : :
13581 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_BSSID])
13582 : : return -EINVAL;
13583 : :
13584 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_STATUS_CODE])
13585 : : return -EINVAL;
13586 : :
13587 : 0 : memset(¶ms, 0, sizeof(params));
13588 : :
13589 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_SSID]) {
13590 [ # # ]: 0 : params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
13591 [ # # ]: 0 : if (params.ssid.ssid_len == 0 ||
13592 : : params.ssid.ssid_len > IEEE80211_MAX_SSID_LEN)
13593 : : return -EINVAL;
13594 : 0 : memcpy(params.ssid.ssid,
13595 : : nla_data(info->attrs[NL80211_ATTR_SSID]),
13596 : : params.ssid.ssid_len);
13597 : : }
13598 : :
13599 [ # # ]: 0 : memcpy(params.bssid, nla_data(info->attrs[NL80211_ATTR_BSSID]),
13600 : : ETH_ALEN);
13601 : :
13602 [ # # ]: 0 : params.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
13603 : :
13604 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_PMKID])
13605 : 0 : params.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
13606 : :
13607 : 0 : return rdev_external_auth(rdev, dev, ¶ms);
13608 : : }
13609 : :
13610 : 0 : static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
13611 : : {
13612 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13613 : 0 : struct net_device *dev = info->user_ptr[1];
13614 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
13615 : 0 : const u8 *buf;
13616 : 0 : size_t len;
13617 : 0 : u8 *dest;
13618 : 0 : u16 proto;
13619 : 0 : bool noencrypt;
13620 : 0 : int err;
13621 : :
13622 [ # # ]: 0 : if (!wiphy_ext_feature_isset(&rdev->wiphy,
13623 : : NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
13624 : : return -EOPNOTSUPP;
13625 : :
13626 [ # # ]: 0 : if (!rdev->ops->tx_control_port)
13627 : : return -EOPNOTSUPP;
13628 : :
13629 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_FRAME] ||
13630 [ # # ]: 0 : !info->attrs[NL80211_ATTR_MAC] ||
13631 [ # # ]: 0 : !info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
13632 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "Frame, MAC or ethertype missing");
13633 : 0 : return -EINVAL;
13634 : : }
13635 : :
13636 : 0 : wdev_lock(wdev);
13637 : :
13638 [ # # # ]: 0 : switch (wdev->iftype) {
13639 : : case NL80211_IFTYPE_AP:
13640 : : case NL80211_IFTYPE_P2P_GO:
13641 : : case NL80211_IFTYPE_MESH_POINT:
13642 : : break;
13643 : 0 : case NL80211_IFTYPE_ADHOC:
13644 : : case NL80211_IFTYPE_STATION:
13645 : : case NL80211_IFTYPE_P2P_CLIENT:
13646 [ # # ]: 0 : if (wdev->current_bss)
13647 : : break;
13648 : 0 : err = -ENOTCONN;
13649 : 0 : goto out;
13650 : 0 : default:
13651 : 0 : err = -EOPNOTSUPP;
13652 : 0 : goto out;
13653 : : }
13654 : :
13655 : 0 : wdev_unlock(wdev);
13656 : :
13657 : 0 : buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
13658 : 0 : len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
13659 : 0 : dest = nla_data(info->attrs[NL80211_ATTR_MAC]);
13660 : 0 : proto = nla_get_u16(info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
13661 : 0 : noencrypt =
13662 : 0 : nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);
13663 : :
13664 : 0 : return rdev_tx_control_port(rdev, dev, buf, len,
13665 : 0 : dest, cpu_to_be16(proto), noencrypt);
13666 : :
13667 : 0 : out:
13668 : 0 : wdev_unlock(wdev);
13669 : 0 : return err;
13670 : : }
13671 : :
13672 : 0 : static int nl80211_get_ftm_responder_stats(struct sk_buff *skb,
13673 : : struct genl_info *info)
13674 : : {
13675 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13676 : 0 : struct net_device *dev = info->user_ptr[1];
13677 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
13678 : 0 : struct cfg80211_ftm_responder_stats ftm_stats = {};
13679 : 0 : struct sk_buff *msg;
13680 : 0 : void *hdr;
13681 : 0 : struct nlattr *ftm_stats_attr;
13682 : 0 : int err;
13683 : :
13684 [ # # # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_AP || !wdev->beacon_interval)
13685 : : return -EOPNOTSUPP;
13686 : :
13687 : 0 : err = rdev_get_ftm_responder_stats(rdev, dev, &ftm_stats);
13688 [ # # ]: 0 : if (err)
13689 : : return err;
13690 : :
13691 [ # # ]: 0 : if (!ftm_stats.filled)
13692 : : return -ENODATA;
13693 : :
13694 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13695 [ # # ]: 0 : if (!msg)
13696 : : return -ENOMEM;
13697 : :
13698 : 0 : hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
13699 : : NL80211_CMD_GET_FTM_RESPONDER_STATS);
13700 [ # # ]: 0 : if (!hdr)
13701 : 0 : goto nla_put_failure;
13702 : :
13703 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
13704 : 0 : goto nla_put_failure;
13705 : :
13706 : 0 : ftm_stats_attr = nla_nest_start_noflag(msg,
13707 : : NL80211_ATTR_FTM_RESPONDER_STATS);
13708 [ # # ]: 0 : if (!ftm_stats_attr)
13709 : 0 : goto nla_put_failure;
13710 : :
13711 : : #define SET_FTM(field, name, type) \
13712 : : do { if ((ftm_stats.filled & BIT(NL80211_FTM_STATS_ ## name)) && \
13713 : : nla_put_ ## type(msg, NL80211_FTM_STATS_ ## name, \
13714 : : ftm_stats.field)) \
13715 : : goto nla_put_failure; } while (0)
13716 : : #define SET_FTM_U64(field, name) \
13717 : : do { if ((ftm_stats.filled & BIT(NL80211_FTM_STATS_ ## name)) && \
13718 : : nla_put_u64_64bit(msg, NL80211_FTM_STATS_ ## name, \
13719 : : ftm_stats.field, NL80211_FTM_STATS_PAD)) \
13720 : : goto nla_put_failure; } while (0)
13721 : :
13722 [ # # # # ]: 0 : SET_FTM(success_num, SUCCESS_NUM, u32);
13723 [ # # # # ]: 0 : SET_FTM(partial_num, PARTIAL_NUM, u32);
13724 [ # # # # ]: 0 : SET_FTM(failed_num, FAILED_NUM, u32);
13725 [ # # # # ]: 0 : SET_FTM(asap_num, ASAP_NUM, u32);
13726 [ # # # # ]: 0 : SET_FTM(non_asap_num, NON_ASAP_NUM, u32);
13727 [ # # # # ]: 0 : SET_FTM_U64(total_duration_ms, TOTAL_DURATION_MSEC);
13728 [ # # # # ]: 0 : SET_FTM(unknown_triggers_num, UNKNOWN_TRIGGERS_NUM, u32);
13729 [ # # # # ]: 0 : SET_FTM(reschedule_requests_num, RESCHEDULE_REQUESTS_NUM, u32);
13730 [ # # # # ]: 0 : SET_FTM(out_of_window_triggers_num, OUT_OF_WINDOW_TRIGGERS_NUM, u32);
13731 : : #undef SET_FTM
13732 : :
13733 : 0 : nla_nest_end(msg, ftm_stats_attr);
13734 : :
13735 : 0 : genlmsg_end(msg, hdr);
13736 : 0 : return genlmsg_reply(msg, info);
13737 : :
13738 : 0 : nla_put_failure:
13739 : 0 : nlmsg_free(msg);
13740 : 0 : return -ENOBUFS;
13741 : : }
13742 : :
13743 : 0 : static int nl80211_update_owe_info(struct sk_buff *skb, struct genl_info *info)
13744 : : {
13745 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13746 : 0 : struct cfg80211_update_owe_info owe_info;
13747 : 0 : struct net_device *dev = info->user_ptr[1];
13748 : :
13749 [ # # ]: 0 : if (!rdev->ops->update_owe_info)
13750 : : return -EOPNOTSUPP;
13751 : :
13752 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_STATUS_CODE] ||
13753 [ # # ]: 0 : !info->attrs[NL80211_ATTR_MAC])
13754 : : return -EINVAL;
13755 : :
13756 : 0 : memset(&owe_info, 0, sizeof(owe_info));
13757 : 0 : owe_info.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
13758 : 0 : nla_memcpy(owe_info.peer, info->attrs[NL80211_ATTR_MAC], ETH_ALEN);
13759 : :
13760 [ # # ]: 0 : if (info->attrs[NL80211_ATTR_IE]) {
13761 : 0 : owe_info.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
13762 : 0 : owe_info.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
13763 : : }
13764 : :
13765 : 0 : return rdev_update_owe_info(rdev, dev, &owe_info);
13766 : : }
13767 : :
13768 : 0 : static int nl80211_probe_mesh_link(struct sk_buff *skb, struct genl_info *info)
13769 : : {
13770 : 0 : struct cfg80211_registered_device *rdev = info->user_ptr[0];
13771 : 0 : struct net_device *dev = info->user_ptr[1];
13772 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
13773 : 0 : struct station_info sinfo = {};
13774 : 0 : const u8 *buf;
13775 : 0 : size_t len;
13776 : 0 : u8 *dest;
13777 : 0 : int err;
13778 : :
13779 [ # # # # ]: 0 : if (!rdev->ops->probe_mesh_link || !rdev->ops->get_station)
13780 : : return -EOPNOTSUPP;
13781 : :
13782 [ # # ]: 0 : if (!info->attrs[NL80211_ATTR_MAC] ||
13783 [ # # ]: 0 : !info->attrs[NL80211_ATTR_FRAME]) {
13784 [ # # ]: 0 : GENL_SET_ERR_MSG(info, "Frame or MAC missing");
13785 : 0 : return -EINVAL;
13786 : : }
13787 : :
13788 [ # # ]: 0 : if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
13789 : : return -EOPNOTSUPP;
13790 : :
13791 [ # # ]: 0 : dest = nla_data(info->attrs[NL80211_ATTR_MAC]);
13792 : 0 : buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
13793 [ # # ]: 0 : len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
13794 : :
13795 [ # # ]: 0 : if (len < sizeof(struct ethhdr))
13796 : : return -EINVAL;
13797 : :
13798 [ # # # # : 0 : if (!ether_addr_equal(buf, dest) || is_multicast_ether_addr(buf) ||
# # ]
13799 [ # # ]: 0 : !ether_addr_equal(buf + ETH_ALEN, dev->dev_addr))
13800 : : return -EINVAL;
13801 : :
13802 : 0 : err = rdev_get_station(rdev, dev, dest, &sinfo);
13803 [ # # ]: 0 : if (err)
13804 : : return err;
13805 : :
13806 : 0 : cfg80211_sinfo_release_content(&sinfo);
13807 : :
13808 : 0 : return rdev_probe_mesh_link(rdev, dev, dest, buf, len);
13809 : : }
13810 : :
13811 : : #define NL80211_FLAG_NEED_WIPHY 0x01
13812 : : #define NL80211_FLAG_NEED_NETDEV 0x02
13813 : : #define NL80211_FLAG_NEED_RTNL 0x04
13814 : : #define NL80211_FLAG_CHECK_NETDEV_UP 0x08
13815 : : #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
13816 : : NL80211_FLAG_CHECK_NETDEV_UP)
13817 : : #define NL80211_FLAG_NEED_WDEV 0x10
13818 : : /* If a netdev is associated, it must be UP, P2P must be started */
13819 : : #define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
13820 : : NL80211_FLAG_CHECK_NETDEV_UP)
13821 : : #define NL80211_FLAG_CLEAR_SKB 0x20
13822 : :
13823 : 0 : static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
13824 : : struct genl_info *info)
13825 : : {
13826 : 0 : struct cfg80211_registered_device *rdev;
13827 : 0 : struct wireless_dev *wdev;
13828 : 0 : struct net_device *dev;
13829 : 0 : bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
13830 : :
13831 [ # # ]: 0 : if (rtnl)
13832 : 0 : rtnl_lock();
13833 : :
13834 [ # # ]: 0 : if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
13835 : 0 : rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
13836 [ # # ]: 0 : if (IS_ERR(rdev)) {
13837 [ # # ]: 0 : if (rtnl)
13838 : 0 : rtnl_unlock();
13839 : 0 : return PTR_ERR(rdev);
13840 : : }
13841 : 0 : info->user_ptr[0] = rdev;
13842 [ # # ]: 0 : } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
13843 : : ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
13844 [ # # # # ]: 0 : ASSERT_RTNL();
13845 : :
13846 : 0 : wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
13847 : : info->attrs);
13848 [ # # ]: 0 : if (IS_ERR(wdev)) {
13849 [ # # ]: 0 : if (rtnl)
13850 : 0 : rtnl_unlock();
13851 : 0 : return PTR_ERR(wdev);
13852 : : }
13853 : :
13854 : 0 : dev = wdev->netdev;
13855 [ # # ]: 0 : rdev = wiphy_to_rdev(wdev->wiphy);
13856 : :
13857 [ # # ]: 0 : if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
13858 [ # # ]: 0 : if (!dev) {
13859 [ # # ]: 0 : if (rtnl)
13860 : 0 : rtnl_unlock();
13861 : 0 : return -EINVAL;
13862 : : }
13863 : :
13864 : 0 : info->user_ptr[1] = dev;
13865 : : } else {
13866 : 0 : info->user_ptr[1] = wdev;
13867 : : }
13868 : :
13869 [ # # # # ]: 0 : if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
13870 [ # # ]: 0 : !wdev_running(wdev)) {
13871 [ # # ]: 0 : if (rtnl)
13872 : 0 : rtnl_unlock();
13873 : 0 : return -ENETDOWN;
13874 : : }
13875 : :
13876 [ # # ]: 0 : if (dev)
13877 : 0 : dev_hold(dev);
13878 : :
13879 : 0 : info->user_ptr[0] = rdev;
13880 : : }
13881 : :
13882 : : return 0;
13883 : : }
13884 : :
13885 : 0 : static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
13886 : : struct genl_info *info)
13887 : : {
13888 [ # # ]: 0 : if (info->user_ptr[1]) {
13889 [ # # ]: 0 : if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
13890 : 0 : struct wireless_dev *wdev = info->user_ptr[1];
13891 : :
13892 [ # # ]: 0 : if (wdev->netdev)
13893 : 0 : dev_put(wdev->netdev);
13894 : : } else {
13895 : 0 : dev_put(info->user_ptr[1]);
13896 : : }
13897 : : }
13898 : :
13899 [ # # ]: 0 : if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
13900 : 0 : rtnl_unlock();
13901 : :
13902 : : /* If needed, clear the netlink message payload from the SKB
13903 : : * as it might contain key data that shouldn't stick around on
13904 : : * the heap after the SKB is freed. The netlink message header
13905 : : * is still needed for further processing, so leave it intact.
13906 : : */
13907 [ # # ]: 0 : if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) {
13908 : 0 : struct nlmsghdr *nlh = nlmsg_hdr(skb);
13909 : :
13910 : 0 : memset(nlmsg_data(nlh), 0, nlmsg_len(nlh));
13911 : : }
13912 : 0 : }
13913 : :
13914 : : static const struct genl_ops nl80211_ops[] = {
13915 : : {
13916 : : .cmd = NL80211_CMD_GET_WIPHY,
13917 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13918 : : .doit = nl80211_get_wiphy,
13919 : : .dumpit = nl80211_dump_wiphy,
13920 : : .done = nl80211_dump_wiphy_done,
13921 : : /* can be retrieved by unprivileged users */
13922 : : .internal_flags = NL80211_FLAG_NEED_WIPHY |
13923 : : NL80211_FLAG_NEED_RTNL,
13924 : : },
13925 : : {
13926 : : .cmd = NL80211_CMD_SET_WIPHY,
13927 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13928 : : .doit = nl80211_set_wiphy,
13929 : : .flags = GENL_UNS_ADMIN_PERM,
13930 : : .internal_flags = NL80211_FLAG_NEED_RTNL,
13931 : : },
13932 : : {
13933 : : .cmd = NL80211_CMD_GET_INTERFACE,
13934 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13935 : : .doit = nl80211_get_interface,
13936 : : .dumpit = nl80211_dump_interface,
13937 : : /* can be retrieved by unprivileged users */
13938 : : .internal_flags = NL80211_FLAG_NEED_WDEV |
13939 : : NL80211_FLAG_NEED_RTNL,
13940 : : },
13941 : : {
13942 : : .cmd = NL80211_CMD_SET_INTERFACE,
13943 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13944 : : .doit = nl80211_set_interface,
13945 : : .flags = GENL_UNS_ADMIN_PERM,
13946 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
13947 : : NL80211_FLAG_NEED_RTNL,
13948 : : },
13949 : : {
13950 : : .cmd = NL80211_CMD_NEW_INTERFACE,
13951 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13952 : : .doit = nl80211_new_interface,
13953 : : .flags = GENL_UNS_ADMIN_PERM,
13954 : : .internal_flags = NL80211_FLAG_NEED_WIPHY |
13955 : : NL80211_FLAG_NEED_RTNL,
13956 : : },
13957 : : {
13958 : : .cmd = NL80211_CMD_DEL_INTERFACE,
13959 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13960 : : .doit = nl80211_del_interface,
13961 : : .flags = GENL_UNS_ADMIN_PERM,
13962 : : .internal_flags = NL80211_FLAG_NEED_WDEV |
13963 : : NL80211_FLAG_NEED_RTNL,
13964 : : },
13965 : : {
13966 : : .cmd = NL80211_CMD_GET_KEY,
13967 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13968 : : .doit = nl80211_get_key,
13969 : : .flags = GENL_UNS_ADMIN_PERM,
13970 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13971 : : NL80211_FLAG_NEED_RTNL,
13972 : : },
13973 : : {
13974 : : .cmd = NL80211_CMD_SET_KEY,
13975 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13976 : : .doit = nl80211_set_key,
13977 : : .flags = GENL_UNS_ADMIN_PERM,
13978 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13979 : : NL80211_FLAG_NEED_RTNL |
13980 : : NL80211_FLAG_CLEAR_SKB,
13981 : : },
13982 : : {
13983 : : .cmd = NL80211_CMD_NEW_KEY,
13984 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13985 : : .doit = nl80211_new_key,
13986 : : .flags = GENL_UNS_ADMIN_PERM,
13987 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13988 : : NL80211_FLAG_NEED_RTNL |
13989 : : NL80211_FLAG_CLEAR_SKB,
13990 : : },
13991 : : {
13992 : : .cmd = NL80211_CMD_DEL_KEY,
13993 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13994 : : .doit = nl80211_del_key,
13995 : : .flags = GENL_UNS_ADMIN_PERM,
13996 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13997 : : NL80211_FLAG_NEED_RTNL,
13998 : : },
13999 : : {
14000 : : .cmd = NL80211_CMD_SET_BEACON,
14001 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14002 : : .flags = GENL_UNS_ADMIN_PERM,
14003 : : .doit = nl80211_set_beacon,
14004 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14005 : : NL80211_FLAG_NEED_RTNL,
14006 : : },
14007 : : {
14008 : : .cmd = NL80211_CMD_START_AP,
14009 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14010 : : .flags = GENL_UNS_ADMIN_PERM,
14011 : : .doit = nl80211_start_ap,
14012 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14013 : : NL80211_FLAG_NEED_RTNL,
14014 : : },
14015 : : {
14016 : : .cmd = NL80211_CMD_STOP_AP,
14017 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14018 : : .flags = GENL_UNS_ADMIN_PERM,
14019 : : .doit = nl80211_stop_ap,
14020 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14021 : : NL80211_FLAG_NEED_RTNL,
14022 : : },
14023 : : {
14024 : : .cmd = NL80211_CMD_GET_STATION,
14025 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14026 : : .doit = nl80211_get_station,
14027 : : .dumpit = nl80211_dump_station,
14028 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14029 : : NL80211_FLAG_NEED_RTNL,
14030 : : },
14031 : : {
14032 : : .cmd = NL80211_CMD_SET_STATION,
14033 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14034 : : .doit = nl80211_set_station,
14035 : : .flags = GENL_UNS_ADMIN_PERM,
14036 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14037 : : NL80211_FLAG_NEED_RTNL,
14038 : : },
14039 : : {
14040 : : .cmd = NL80211_CMD_NEW_STATION,
14041 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14042 : : .doit = nl80211_new_station,
14043 : : .flags = GENL_UNS_ADMIN_PERM,
14044 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14045 : : NL80211_FLAG_NEED_RTNL,
14046 : : },
14047 : : {
14048 : : .cmd = NL80211_CMD_DEL_STATION,
14049 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14050 : : .doit = nl80211_del_station,
14051 : : .flags = GENL_UNS_ADMIN_PERM,
14052 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14053 : : NL80211_FLAG_NEED_RTNL,
14054 : : },
14055 : : {
14056 : : .cmd = NL80211_CMD_GET_MPATH,
14057 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14058 : : .doit = nl80211_get_mpath,
14059 : : .dumpit = nl80211_dump_mpath,
14060 : : .flags = GENL_UNS_ADMIN_PERM,
14061 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14062 : : NL80211_FLAG_NEED_RTNL,
14063 : : },
14064 : : {
14065 : : .cmd = NL80211_CMD_GET_MPP,
14066 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14067 : : .doit = nl80211_get_mpp,
14068 : : .dumpit = nl80211_dump_mpp,
14069 : : .flags = GENL_UNS_ADMIN_PERM,
14070 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14071 : : NL80211_FLAG_NEED_RTNL,
14072 : : },
14073 : : {
14074 : : .cmd = NL80211_CMD_SET_MPATH,
14075 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14076 : : .doit = nl80211_set_mpath,
14077 : : .flags = GENL_UNS_ADMIN_PERM,
14078 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14079 : : NL80211_FLAG_NEED_RTNL,
14080 : : },
14081 : : {
14082 : : .cmd = NL80211_CMD_NEW_MPATH,
14083 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14084 : : .doit = nl80211_new_mpath,
14085 : : .flags = GENL_UNS_ADMIN_PERM,
14086 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14087 : : NL80211_FLAG_NEED_RTNL,
14088 : : },
14089 : : {
14090 : : .cmd = NL80211_CMD_DEL_MPATH,
14091 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14092 : : .doit = nl80211_del_mpath,
14093 : : .flags = GENL_UNS_ADMIN_PERM,
14094 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14095 : : NL80211_FLAG_NEED_RTNL,
14096 : : },
14097 : : {
14098 : : .cmd = NL80211_CMD_SET_BSS,
14099 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14100 : : .doit = nl80211_set_bss,
14101 : : .flags = GENL_UNS_ADMIN_PERM,
14102 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14103 : : NL80211_FLAG_NEED_RTNL,
14104 : : },
14105 : : {
14106 : : .cmd = NL80211_CMD_GET_REG,
14107 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14108 : : .doit = nl80211_get_reg_do,
14109 : : .dumpit = nl80211_get_reg_dump,
14110 : : .internal_flags = NL80211_FLAG_NEED_RTNL,
14111 : : /* can be retrieved by unprivileged users */
14112 : : },
14113 : : #ifdef CONFIG_CFG80211_CRDA_SUPPORT
14114 : : {
14115 : : .cmd = NL80211_CMD_SET_REG,
14116 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14117 : : .doit = nl80211_set_reg,
14118 : : .flags = GENL_ADMIN_PERM,
14119 : : .internal_flags = NL80211_FLAG_NEED_RTNL,
14120 : : },
14121 : : #endif
14122 : : {
14123 : : .cmd = NL80211_CMD_REQ_SET_REG,
14124 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14125 : : .doit = nl80211_req_set_reg,
14126 : : .flags = GENL_ADMIN_PERM,
14127 : : },
14128 : : {
14129 : : .cmd = NL80211_CMD_RELOAD_REGDB,
14130 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14131 : : .doit = nl80211_reload_regdb,
14132 : : .flags = GENL_ADMIN_PERM,
14133 : : },
14134 : : {
14135 : : .cmd = NL80211_CMD_GET_MESH_CONFIG,
14136 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14137 : : .doit = nl80211_get_mesh_config,
14138 : : /* can be retrieved by unprivileged users */
14139 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14140 : : NL80211_FLAG_NEED_RTNL,
14141 : : },
14142 : : {
14143 : : .cmd = NL80211_CMD_SET_MESH_CONFIG,
14144 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14145 : : .doit = nl80211_update_mesh_config,
14146 : : .flags = GENL_UNS_ADMIN_PERM,
14147 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14148 : : NL80211_FLAG_NEED_RTNL,
14149 : : },
14150 : : {
14151 : : .cmd = NL80211_CMD_TRIGGER_SCAN,
14152 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14153 : : .doit = nl80211_trigger_scan,
14154 : : .flags = GENL_UNS_ADMIN_PERM,
14155 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14156 : : NL80211_FLAG_NEED_RTNL,
14157 : : },
14158 : : {
14159 : : .cmd = NL80211_CMD_ABORT_SCAN,
14160 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14161 : : .doit = nl80211_abort_scan,
14162 : : .flags = GENL_UNS_ADMIN_PERM,
14163 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14164 : : NL80211_FLAG_NEED_RTNL,
14165 : : },
14166 : : {
14167 : : .cmd = NL80211_CMD_GET_SCAN,
14168 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14169 : : .dumpit = nl80211_dump_scan,
14170 : : },
14171 : : {
14172 : : .cmd = NL80211_CMD_START_SCHED_SCAN,
14173 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14174 : : .doit = nl80211_start_sched_scan,
14175 : : .flags = GENL_UNS_ADMIN_PERM,
14176 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14177 : : NL80211_FLAG_NEED_RTNL,
14178 : : },
14179 : : {
14180 : : .cmd = NL80211_CMD_STOP_SCHED_SCAN,
14181 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14182 : : .doit = nl80211_stop_sched_scan,
14183 : : .flags = GENL_UNS_ADMIN_PERM,
14184 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14185 : : NL80211_FLAG_NEED_RTNL,
14186 : : },
14187 : : {
14188 : : .cmd = NL80211_CMD_AUTHENTICATE,
14189 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14190 : : .doit = nl80211_authenticate,
14191 : : .flags = GENL_UNS_ADMIN_PERM,
14192 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14193 : : NL80211_FLAG_NEED_RTNL |
14194 : : NL80211_FLAG_CLEAR_SKB,
14195 : : },
14196 : : {
14197 : : .cmd = NL80211_CMD_ASSOCIATE,
14198 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14199 : : .doit = nl80211_associate,
14200 : : .flags = GENL_UNS_ADMIN_PERM,
14201 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14202 : : NL80211_FLAG_NEED_RTNL |
14203 : : NL80211_FLAG_CLEAR_SKB,
14204 : : },
14205 : : {
14206 : : .cmd = NL80211_CMD_DEAUTHENTICATE,
14207 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14208 : : .doit = nl80211_deauthenticate,
14209 : : .flags = GENL_UNS_ADMIN_PERM,
14210 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14211 : : NL80211_FLAG_NEED_RTNL,
14212 : : },
14213 : : {
14214 : : .cmd = NL80211_CMD_DISASSOCIATE,
14215 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14216 : : .doit = nl80211_disassociate,
14217 : : .flags = GENL_UNS_ADMIN_PERM,
14218 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14219 : : NL80211_FLAG_NEED_RTNL,
14220 : : },
14221 : : {
14222 : : .cmd = NL80211_CMD_JOIN_IBSS,
14223 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14224 : : .doit = nl80211_join_ibss,
14225 : : .flags = GENL_UNS_ADMIN_PERM,
14226 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14227 : : NL80211_FLAG_NEED_RTNL,
14228 : : },
14229 : : {
14230 : : .cmd = NL80211_CMD_LEAVE_IBSS,
14231 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14232 : : .doit = nl80211_leave_ibss,
14233 : : .flags = GENL_UNS_ADMIN_PERM,
14234 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14235 : : NL80211_FLAG_NEED_RTNL,
14236 : : },
14237 : : #ifdef CONFIG_NL80211_TESTMODE
14238 : : {
14239 : : .cmd = NL80211_CMD_TESTMODE,
14240 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14241 : : .doit = nl80211_testmode_do,
14242 : : .dumpit = nl80211_testmode_dump,
14243 : : .flags = GENL_UNS_ADMIN_PERM,
14244 : : .internal_flags = NL80211_FLAG_NEED_WIPHY |
14245 : : NL80211_FLAG_NEED_RTNL,
14246 : : },
14247 : : #endif
14248 : : {
14249 : : .cmd = NL80211_CMD_CONNECT,
14250 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14251 : : .doit = nl80211_connect,
14252 : : .flags = GENL_UNS_ADMIN_PERM,
14253 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14254 : : NL80211_FLAG_NEED_RTNL |
14255 : : NL80211_FLAG_CLEAR_SKB,
14256 : : },
14257 : : {
14258 : : .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
14259 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14260 : : .doit = nl80211_update_connect_params,
14261 : : .flags = GENL_ADMIN_PERM,
14262 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14263 : : NL80211_FLAG_NEED_RTNL |
14264 : : NL80211_FLAG_CLEAR_SKB,
14265 : : },
14266 : : {
14267 : : .cmd = NL80211_CMD_DISCONNECT,
14268 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14269 : : .doit = nl80211_disconnect,
14270 : : .flags = GENL_UNS_ADMIN_PERM,
14271 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14272 : : NL80211_FLAG_NEED_RTNL,
14273 : : },
14274 : : {
14275 : : .cmd = NL80211_CMD_SET_WIPHY_NETNS,
14276 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14277 : : .doit = nl80211_wiphy_netns,
14278 : : .flags = GENL_UNS_ADMIN_PERM,
14279 : : .internal_flags = NL80211_FLAG_NEED_WIPHY |
14280 : : NL80211_FLAG_NEED_RTNL,
14281 : : },
14282 : : {
14283 : : .cmd = NL80211_CMD_GET_SURVEY,
14284 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14285 : : .dumpit = nl80211_dump_survey,
14286 : : },
14287 : : {
14288 : : .cmd = NL80211_CMD_SET_PMKSA,
14289 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14290 : : .doit = nl80211_setdel_pmksa,
14291 : : .flags = GENL_UNS_ADMIN_PERM,
14292 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14293 : : NL80211_FLAG_NEED_RTNL |
14294 : : NL80211_FLAG_CLEAR_SKB,
14295 : : },
14296 : : {
14297 : : .cmd = NL80211_CMD_DEL_PMKSA,
14298 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14299 : : .doit = nl80211_setdel_pmksa,
14300 : : .flags = GENL_UNS_ADMIN_PERM,
14301 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14302 : : NL80211_FLAG_NEED_RTNL,
14303 : : },
14304 : : {
14305 : : .cmd = NL80211_CMD_FLUSH_PMKSA,
14306 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14307 : : .doit = nl80211_flush_pmksa,
14308 : : .flags = GENL_UNS_ADMIN_PERM,
14309 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14310 : : NL80211_FLAG_NEED_RTNL,
14311 : : },
14312 : : {
14313 : : .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
14314 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14315 : : .doit = nl80211_remain_on_channel,
14316 : : .flags = GENL_UNS_ADMIN_PERM,
14317 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14318 : : NL80211_FLAG_NEED_RTNL,
14319 : : },
14320 : : {
14321 : : .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
14322 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14323 : : .doit = nl80211_cancel_remain_on_channel,
14324 : : .flags = GENL_UNS_ADMIN_PERM,
14325 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14326 : : NL80211_FLAG_NEED_RTNL,
14327 : : },
14328 : : {
14329 : : .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
14330 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14331 : : .doit = nl80211_set_tx_bitrate_mask,
14332 : : .flags = GENL_UNS_ADMIN_PERM,
14333 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14334 : : NL80211_FLAG_NEED_RTNL,
14335 : : },
14336 : : {
14337 : : .cmd = NL80211_CMD_REGISTER_FRAME,
14338 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14339 : : .doit = nl80211_register_mgmt,
14340 : : .flags = GENL_UNS_ADMIN_PERM,
14341 : : .internal_flags = NL80211_FLAG_NEED_WDEV |
14342 : : NL80211_FLAG_NEED_RTNL,
14343 : : },
14344 : : {
14345 : : .cmd = NL80211_CMD_FRAME,
14346 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14347 : : .doit = nl80211_tx_mgmt,
14348 : : .flags = GENL_UNS_ADMIN_PERM,
14349 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14350 : : NL80211_FLAG_NEED_RTNL,
14351 : : },
14352 : : {
14353 : : .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
14354 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14355 : : .doit = nl80211_tx_mgmt_cancel_wait,
14356 : : .flags = GENL_UNS_ADMIN_PERM,
14357 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14358 : : NL80211_FLAG_NEED_RTNL,
14359 : : },
14360 : : {
14361 : : .cmd = NL80211_CMD_SET_POWER_SAVE,
14362 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14363 : : .doit = nl80211_set_power_save,
14364 : : .flags = GENL_UNS_ADMIN_PERM,
14365 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14366 : : NL80211_FLAG_NEED_RTNL,
14367 : : },
14368 : : {
14369 : : .cmd = NL80211_CMD_GET_POWER_SAVE,
14370 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14371 : : .doit = nl80211_get_power_save,
14372 : : /* can be retrieved by unprivileged users */
14373 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14374 : : NL80211_FLAG_NEED_RTNL,
14375 : : },
14376 : : {
14377 : : .cmd = NL80211_CMD_SET_CQM,
14378 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14379 : : .doit = nl80211_set_cqm,
14380 : : .flags = GENL_UNS_ADMIN_PERM,
14381 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14382 : : NL80211_FLAG_NEED_RTNL,
14383 : : },
14384 : : {
14385 : : .cmd = NL80211_CMD_SET_CHANNEL,
14386 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14387 : : .doit = nl80211_set_channel,
14388 : : .flags = GENL_UNS_ADMIN_PERM,
14389 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14390 : : NL80211_FLAG_NEED_RTNL,
14391 : : },
14392 : : {
14393 : : .cmd = NL80211_CMD_SET_WDS_PEER,
14394 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14395 : : .doit = nl80211_set_wds_peer,
14396 : : .flags = GENL_UNS_ADMIN_PERM,
14397 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14398 : : NL80211_FLAG_NEED_RTNL,
14399 : : },
14400 : : {
14401 : : .cmd = NL80211_CMD_JOIN_MESH,
14402 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14403 : : .doit = nl80211_join_mesh,
14404 : : .flags = GENL_UNS_ADMIN_PERM,
14405 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14406 : : NL80211_FLAG_NEED_RTNL,
14407 : : },
14408 : : {
14409 : : .cmd = NL80211_CMD_LEAVE_MESH,
14410 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14411 : : .doit = nl80211_leave_mesh,
14412 : : .flags = GENL_UNS_ADMIN_PERM,
14413 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14414 : : NL80211_FLAG_NEED_RTNL,
14415 : : },
14416 : : {
14417 : : .cmd = NL80211_CMD_JOIN_OCB,
14418 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14419 : : .doit = nl80211_join_ocb,
14420 : : .flags = GENL_UNS_ADMIN_PERM,
14421 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14422 : : NL80211_FLAG_NEED_RTNL,
14423 : : },
14424 : : {
14425 : : .cmd = NL80211_CMD_LEAVE_OCB,
14426 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14427 : : .doit = nl80211_leave_ocb,
14428 : : .flags = GENL_UNS_ADMIN_PERM,
14429 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14430 : : NL80211_FLAG_NEED_RTNL,
14431 : : },
14432 : : #ifdef CONFIG_PM
14433 : : {
14434 : : .cmd = NL80211_CMD_GET_WOWLAN,
14435 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14436 : : .doit = nl80211_get_wowlan,
14437 : : /* can be retrieved by unprivileged users */
14438 : : .internal_flags = NL80211_FLAG_NEED_WIPHY |
14439 : : NL80211_FLAG_NEED_RTNL,
14440 : : },
14441 : : {
14442 : : .cmd = NL80211_CMD_SET_WOWLAN,
14443 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14444 : : .doit = nl80211_set_wowlan,
14445 : : .flags = GENL_UNS_ADMIN_PERM,
14446 : : .internal_flags = NL80211_FLAG_NEED_WIPHY |
14447 : : NL80211_FLAG_NEED_RTNL,
14448 : : },
14449 : : #endif
14450 : : {
14451 : : .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
14452 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14453 : : .doit = nl80211_set_rekey_data,
14454 : : .flags = GENL_UNS_ADMIN_PERM,
14455 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14456 : : NL80211_FLAG_NEED_RTNL |
14457 : : NL80211_FLAG_CLEAR_SKB,
14458 : : },
14459 : : {
14460 : : .cmd = NL80211_CMD_TDLS_MGMT,
14461 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14462 : : .doit = nl80211_tdls_mgmt,
14463 : : .flags = GENL_UNS_ADMIN_PERM,
14464 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14465 : : NL80211_FLAG_NEED_RTNL,
14466 : : },
14467 : : {
14468 : : .cmd = NL80211_CMD_TDLS_OPER,
14469 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14470 : : .doit = nl80211_tdls_oper,
14471 : : .flags = GENL_UNS_ADMIN_PERM,
14472 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14473 : : NL80211_FLAG_NEED_RTNL,
14474 : : },
14475 : : {
14476 : : .cmd = NL80211_CMD_UNEXPECTED_FRAME,
14477 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14478 : : .doit = nl80211_register_unexpected_frame,
14479 : : .flags = GENL_UNS_ADMIN_PERM,
14480 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14481 : : NL80211_FLAG_NEED_RTNL,
14482 : : },
14483 : : {
14484 : : .cmd = NL80211_CMD_PROBE_CLIENT,
14485 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14486 : : .doit = nl80211_probe_client,
14487 : : .flags = GENL_UNS_ADMIN_PERM,
14488 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14489 : : NL80211_FLAG_NEED_RTNL,
14490 : : },
14491 : : {
14492 : : .cmd = NL80211_CMD_REGISTER_BEACONS,
14493 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14494 : : .doit = nl80211_register_beacons,
14495 : : .flags = GENL_UNS_ADMIN_PERM,
14496 : : .internal_flags = NL80211_FLAG_NEED_WIPHY |
14497 : : NL80211_FLAG_NEED_RTNL,
14498 : : },
14499 : : {
14500 : : .cmd = NL80211_CMD_SET_NOACK_MAP,
14501 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14502 : : .doit = nl80211_set_noack_map,
14503 : : .flags = GENL_UNS_ADMIN_PERM,
14504 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14505 : : NL80211_FLAG_NEED_RTNL,
14506 : : },
14507 : : {
14508 : : .cmd = NL80211_CMD_START_P2P_DEVICE,
14509 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14510 : : .doit = nl80211_start_p2p_device,
14511 : : .flags = GENL_UNS_ADMIN_PERM,
14512 : : .internal_flags = NL80211_FLAG_NEED_WDEV |
14513 : : NL80211_FLAG_NEED_RTNL,
14514 : : },
14515 : : {
14516 : : .cmd = NL80211_CMD_STOP_P2P_DEVICE,
14517 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14518 : : .doit = nl80211_stop_p2p_device,
14519 : : .flags = GENL_UNS_ADMIN_PERM,
14520 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14521 : : NL80211_FLAG_NEED_RTNL,
14522 : : },
14523 : : {
14524 : : .cmd = NL80211_CMD_START_NAN,
14525 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14526 : : .doit = nl80211_start_nan,
14527 : : .flags = GENL_ADMIN_PERM,
14528 : : .internal_flags = NL80211_FLAG_NEED_WDEV |
14529 : : NL80211_FLAG_NEED_RTNL,
14530 : : },
14531 : : {
14532 : : .cmd = NL80211_CMD_STOP_NAN,
14533 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14534 : : .doit = nl80211_stop_nan,
14535 : : .flags = GENL_ADMIN_PERM,
14536 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14537 : : NL80211_FLAG_NEED_RTNL,
14538 : : },
14539 : : {
14540 : : .cmd = NL80211_CMD_ADD_NAN_FUNCTION,
14541 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14542 : : .doit = nl80211_nan_add_func,
14543 : : .flags = GENL_ADMIN_PERM,
14544 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14545 : : NL80211_FLAG_NEED_RTNL,
14546 : : },
14547 : : {
14548 : : .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
14549 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14550 : : .doit = nl80211_nan_del_func,
14551 : : .flags = GENL_ADMIN_PERM,
14552 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14553 : : NL80211_FLAG_NEED_RTNL,
14554 : : },
14555 : : {
14556 : : .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
14557 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14558 : : .doit = nl80211_nan_change_config,
14559 : : .flags = GENL_ADMIN_PERM,
14560 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14561 : : NL80211_FLAG_NEED_RTNL,
14562 : : },
14563 : : {
14564 : : .cmd = NL80211_CMD_SET_MCAST_RATE,
14565 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14566 : : .doit = nl80211_set_mcast_rate,
14567 : : .flags = GENL_UNS_ADMIN_PERM,
14568 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14569 : : NL80211_FLAG_NEED_RTNL,
14570 : : },
14571 : : {
14572 : : .cmd = NL80211_CMD_SET_MAC_ACL,
14573 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14574 : : .doit = nl80211_set_mac_acl,
14575 : : .flags = GENL_UNS_ADMIN_PERM,
14576 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14577 : : NL80211_FLAG_NEED_RTNL,
14578 : : },
14579 : : {
14580 : : .cmd = NL80211_CMD_RADAR_DETECT,
14581 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14582 : : .doit = nl80211_start_radar_detection,
14583 : : .flags = GENL_UNS_ADMIN_PERM,
14584 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14585 : : NL80211_FLAG_NEED_RTNL,
14586 : : },
14587 : : {
14588 : : .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
14589 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14590 : : .doit = nl80211_get_protocol_features,
14591 : : },
14592 : : {
14593 : : .cmd = NL80211_CMD_UPDATE_FT_IES,
14594 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14595 : : .doit = nl80211_update_ft_ies,
14596 : : .flags = GENL_UNS_ADMIN_PERM,
14597 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14598 : : NL80211_FLAG_NEED_RTNL,
14599 : : },
14600 : : {
14601 : : .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
14602 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14603 : : .doit = nl80211_crit_protocol_start,
14604 : : .flags = GENL_UNS_ADMIN_PERM,
14605 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14606 : : NL80211_FLAG_NEED_RTNL,
14607 : : },
14608 : : {
14609 : : .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
14610 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14611 : : .doit = nl80211_crit_protocol_stop,
14612 : : .flags = GENL_UNS_ADMIN_PERM,
14613 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14614 : : NL80211_FLAG_NEED_RTNL,
14615 : : },
14616 : : {
14617 : : .cmd = NL80211_CMD_GET_COALESCE,
14618 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14619 : : .doit = nl80211_get_coalesce,
14620 : : .internal_flags = NL80211_FLAG_NEED_WIPHY |
14621 : : NL80211_FLAG_NEED_RTNL,
14622 : : },
14623 : : {
14624 : : .cmd = NL80211_CMD_SET_COALESCE,
14625 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14626 : : .doit = nl80211_set_coalesce,
14627 : : .flags = GENL_UNS_ADMIN_PERM,
14628 : : .internal_flags = NL80211_FLAG_NEED_WIPHY |
14629 : : NL80211_FLAG_NEED_RTNL,
14630 : : },
14631 : : {
14632 : : .cmd = NL80211_CMD_CHANNEL_SWITCH,
14633 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14634 : : .doit = nl80211_channel_switch,
14635 : : .flags = GENL_UNS_ADMIN_PERM,
14636 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14637 : : NL80211_FLAG_NEED_RTNL,
14638 : : },
14639 : : {
14640 : : .cmd = NL80211_CMD_VENDOR,
14641 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14642 : : .doit = nl80211_vendor_cmd,
14643 : : .dumpit = nl80211_vendor_cmd_dump,
14644 : : .flags = GENL_UNS_ADMIN_PERM,
14645 : : .internal_flags = NL80211_FLAG_NEED_WIPHY |
14646 : : NL80211_FLAG_NEED_RTNL |
14647 : : NL80211_FLAG_CLEAR_SKB,
14648 : : },
14649 : : {
14650 : : .cmd = NL80211_CMD_SET_QOS_MAP,
14651 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14652 : : .doit = nl80211_set_qos_map,
14653 : : .flags = GENL_UNS_ADMIN_PERM,
14654 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14655 : : NL80211_FLAG_NEED_RTNL,
14656 : : },
14657 : : {
14658 : : .cmd = NL80211_CMD_ADD_TX_TS,
14659 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14660 : : .doit = nl80211_add_tx_ts,
14661 : : .flags = GENL_UNS_ADMIN_PERM,
14662 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14663 : : NL80211_FLAG_NEED_RTNL,
14664 : : },
14665 : : {
14666 : : .cmd = NL80211_CMD_DEL_TX_TS,
14667 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14668 : : .doit = nl80211_del_tx_ts,
14669 : : .flags = GENL_UNS_ADMIN_PERM,
14670 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14671 : : NL80211_FLAG_NEED_RTNL,
14672 : : },
14673 : : {
14674 : : .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
14675 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14676 : : .doit = nl80211_tdls_channel_switch,
14677 : : .flags = GENL_UNS_ADMIN_PERM,
14678 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14679 : : NL80211_FLAG_NEED_RTNL,
14680 : : },
14681 : : {
14682 : : .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
14683 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14684 : : .doit = nl80211_tdls_cancel_channel_switch,
14685 : : .flags = GENL_UNS_ADMIN_PERM,
14686 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14687 : : NL80211_FLAG_NEED_RTNL,
14688 : : },
14689 : : {
14690 : : .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
14691 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14692 : : .doit = nl80211_set_multicast_to_unicast,
14693 : : .flags = GENL_UNS_ADMIN_PERM,
14694 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14695 : : NL80211_FLAG_NEED_RTNL,
14696 : : },
14697 : : {
14698 : : .cmd = NL80211_CMD_SET_PMK,
14699 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14700 : : .doit = nl80211_set_pmk,
14701 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14702 : : NL80211_FLAG_NEED_RTNL |
14703 : : NL80211_FLAG_CLEAR_SKB,
14704 : : },
14705 : : {
14706 : : .cmd = NL80211_CMD_DEL_PMK,
14707 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14708 : : .doit = nl80211_del_pmk,
14709 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14710 : : NL80211_FLAG_NEED_RTNL,
14711 : : },
14712 : : {
14713 : : .cmd = NL80211_CMD_EXTERNAL_AUTH,
14714 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14715 : : .doit = nl80211_external_auth,
14716 : : .flags = GENL_ADMIN_PERM,
14717 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14718 : : NL80211_FLAG_NEED_RTNL,
14719 : : },
14720 : : {
14721 : : .cmd = NL80211_CMD_CONTROL_PORT_FRAME,
14722 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14723 : : .doit = nl80211_tx_control_port,
14724 : : .flags = GENL_UNS_ADMIN_PERM,
14725 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14726 : : NL80211_FLAG_NEED_RTNL,
14727 : : },
14728 : : {
14729 : : .cmd = NL80211_CMD_GET_FTM_RESPONDER_STATS,
14730 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14731 : : .doit = nl80211_get_ftm_responder_stats,
14732 : : .internal_flags = NL80211_FLAG_NEED_NETDEV |
14733 : : NL80211_FLAG_NEED_RTNL,
14734 : : },
14735 : : {
14736 : : .cmd = NL80211_CMD_PEER_MEASUREMENT_START,
14737 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14738 : : .doit = nl80211_pmsr_start,
14739 : : .flags = GENL_UNS_ADMIN_PERM,
14740 : : .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
14741 : : NL80211_FLAG_NEED_RTNL,
14742 : : },
14743 : : {
14744 : : .cmd = NL80211_CMD_NOTIFY_RADAR,
14745 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14746 : : .doit = nl80211_notify_radar_detection,
14747 : : .flags = GENL_UNS_ADMIN_PERM,
14748 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14749 : : NL80211_FLAG_NEED_RTNL,
14750 : : },
14751 : : {
14752 : : .cmd = NL80211_CMD_UPDATE_OWE_INFO,
14753 : : .doit = nl80211_update_owe_info,
14754 : : .flags = GENL_ADMIN_PERM,
14755 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14756 : : NL80211_FLAG_NEED_RTNL,
14757 : : },
14758 : : {
14759 : : .cmd = NL80211_CMD_PROBE_MESH_LINK,
14760 : : .doit = nl80211_probe_mesh_link,
14761 : : .flags = GENL_UNS_ADMIN_PERM,
14762 : : .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
14763 : : NL80211_FLAG_NEED_RTNL,
14764 : : },
14765 : : };
14766 : :
14767 : : static struct genl_family nl80211_fam __ro_after_init = {
14768 : : .name = NL80211_GENL_NAME, /* have users key off the name instead */
14769 : : .hdrsize = 0, /* no private header */
14770 : : .version = 1, /* no particular meaning now */
14771 : : .maxattr = NL80211_ATTR_MAX,
14772 : : .policy = nl80211_policy,
14773 : : .netnsok = true,
14774 : : .pre_doit = nl80211_pre_doit,
14775 : : .post_doit = nl80211_post_doit,
14776 : : .module = THIS_MODULE,
14777 : : .ops = nl80211_ops,
14778 : : .n_ops = ARRAY_SIZE(nl80211_ops),
14779 : : .mcgrps = nl80211_mcgrps,
14780 : : .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
14781 : : .parallel_ops = true,
14782 : : };
14783 : :
14784 : : /* notification functions */
14785 : :
14786 : 0 : void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
14787 : : enum nl80211_commands cmd)
14788 : : {
14789 : 0 : struct sk_buff *msg;
14790 : 0 : struct nl80211_dump_wiphy_state state = {};
14791 : :
14792 [ # # ]: 0 : WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
14793 : : cmd != NL80211_CMD_DEL_WIPHY);
14794 : :
14795 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
14796 [ # # ]: 0 : if (!msg)
14797 : 0 : return;
14798 : :
14799 [ # # ]: 0 : if (nl80211_send_wiphy(rdev, cmd, msg, 0, 0, 0, &state) < 0) {
14800 : 0 : nlmsg_free(msg);
14801 : 0 : return;
14802 : : }
14803 : :
14804 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
14805 : : NL80211_MCGRP_CONFIG, GFP_KERNEL);
14806 : : }
14807 : :
14808 : 0 : void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
14809 : : struct wireless_dev *wdev,
14810 : : enum nl80211_commands cmd)
14811 : : {
14812 : 0 : struct sk_buff *msg;
14813 : :
14814 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
14815 [ # # ]: 0 : if (!msg)
14816 : : return;
14817 : :
14818 [ # # ]: 0 : if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, cmd) < 0) {
14819 : 0 : nlmsg_free(msg);
14820 : 0 : return;
14821 : : }
14822 : :
14823 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
14824 : : NL80211_MCGRP_CONFIG, GFP_KERNEL);
14825 : : }
14826 : :
14827 : : static int nl80211_add_scan_req(struct sk_buff *msg,
14828 : : struct cfg80211_registered_device *rdev)
14829 : : {
14830 : : struct cfg80211_scan_request *req = rdev->scan_req;
14831 : : struct nlattr *nest;
14832 : : int i;
14833 : :
14834 : : if (WARN_ON(!req))
14835 : : return 0;
14836 : :
14837 : : nest = nla_nest_start_noflag(msg, NL80211_ATTR_SCAN_SSIDS);
14838 : : if (!nest)
14839 : : goto nla_put_failure;
14840 : : for (i = 0; i < req->n_ssids; i++) {
14841 : : if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
14842 : : goto nla_put_failure;
14843 : : }
14844 : : nla_nest_end(msg, nest);
14845 : :
14846 : : nest = nla_nest_start_noflag(msg, NL80211_ATTR_SCAN_FREQUENCIES);
14847 : : if (!nest)
14848 : : goto nla_put_failure;
14849 : : for (i = 0; i < req->n_channels; i++) {
14850 : : if (nla_put_u32(msg, i, req->channels[i]->center_freq))
14851 : : goto nla_put_failure;
14852 : : }
14853 : : nla_nest_end(msg, nest);
14854 : :
14855 : : if (req->ie &&
14856 : : nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
14857 : : goto nla_put_failure;
14858 : :
14859 : : if (req->flags &&
14860 : : nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
14861 : : goto nla_put_failure;
14862 : :
14863 : : if (req->info.scan_start_tsf &&
14864 : : (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
14865 : : req->info.scan_start_tsf, NL80211_BSS_PAD) ||
14866 : : nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
14867 : : req->info.tsf_bssid)))
14868 : : goto nla_put_failure;
14869 : :
14870 : : return 0;
14871 : : nla_put_failure:
14872 : : return -ENOBUFS;
14873 : : }
14874 : :
14875 : 0 : static int nl80211_prep_scan_msg(struct sk_buff *msg,
14876 : : struct cfg80211_registered_device *rdev,
14877 : : struct wireless_dev *wdev,
14878 : : u32 portid, u32 seq, int flags,
14879 : : u32 cmd)
14880 : : {
14881 : 0 : void *hdr;
14882 : :
14883 : 0 : hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
14884 [ # # ]: 0 : if (!hdr)
14885 : : return -1;
14886 : :
14887 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14888 [ # # # # ]: 0 : (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14889 [ # # ]: 0 : wdev->netdev->ifindex)) ||
14890 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14891 : : NL80211_ATTR_PAD))
14892 : 0 : goto nla_put_failure;
14893 : :
14894 : : /* ignore errors and send incomplete event anyway */
14895 : 0 : nl80211_add_scan_req(msg, rdev);
14896 : :
14897 : 0 : genlmsg_end(msg, hdr);
14898 : 0 : return 0;
14899 : :
14900 : : nla_put_failure:
14901 : 0 : genlmsg_cancel(msg, hdr);
14902 : 0 : return -EMSGSIZE;
14903 : : }
14904 : :
14905 : : static int
14906 : 0 : nl80211_prep_sched_scan_msg(struct sk_buff *msg,
14907 : : struct cfg80211_sched_scan_request *req, u32 cmd)
14908 : : {
14909 : 0 : void *hdr;
14910 : :
14911 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
14912 [ # # ]: 0 : if (!hdr)
14913 : : return -1;
14914 : :
14915 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY,
14916 [ # # # # ]: 0 : wiphy_to_rdev(req->wiphy)->wiphy_idx) ||
14917 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, req->dev->ifindex) ||
14918 : 0 : nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->reqid,
14919 : : NL80211_ATTR_PAD))
14920 : 0 : goto nla_put_failure;
14921 : :
14922 : 0 : genlmsg_end(msg, hdr);
14923 : 0 : return 0;
14924 : :
14925 : : nla_put_failure:
14926 : 0 : genlmsg_cancel(msg, hdr);
14927 : 0 : return -EMSGSIZE;
14928 : : }
14929 : :
14930 : 0 : void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
14931 : : struct wireless_dev *wdev)
14932 : : {
14933 : 0 : struct sk_buff *msg;
14934 : :
14935 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
14936 [ # # ]: 0 : if (!msg)
14937 : : return;
14938 : :
14939 [ # # ]: 0 : if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
14940 : : NL80211_CMD_TRIGGER_SCAN) < 0) {
14941 : 0 : nlmsg_free(msg);
14942 : 0 : return;
14943 : : }
14944 : :
14945 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
14946 : : NL80211_MCGRP_SCAN, GFP_KERNEL);
14947 : : }
14948 : :
14949 : 0 : struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
14950 : : struct wireless_dev *wdev, bool aborted)
14951 : : {
14952 : 0 : struct sk_buff *msg;
14953 : :
14954 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
14955 [ # # ]: 0 : if (!msg)
14956 : : return NULL;
14957 : :
14958 [ # # # # ]: 0 : if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
14959 : : aborted ? NL80211_CMD_SCAN_ABORTED :
14960 : : NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
14961 : 0 : nlmsg_free(msg);
14962 : 0 : return NULL;
14963 : : }
14964 : :
14965 : : return msg;
14966 : : }
14967 : :
14968 : : /* send message created by nl80211_build_scan_msg() */
14969 : 0 : void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
14970 : : struct sk_buff *msg)
14971 : : {
14972 [ # # ]: 0 : if (!msg)
14973 : : return;
14974 : :
14975 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
14976 : : NL80211_MCGRP_SCAN, GFP_KERNEL);
14977 : : }
14978 : :
14979 : 0 : void nl80211_send_sched_scan(struct cfg80211_sched_scan_request *req, u32 cmd)
14980 : : {
14981 : 0 : struct sk_buff *msg;
14982 : :
14983 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
14984 [ # # ]: 0 : if (!msg)
14985 : : return;
14986 : :
14987 [ # # ]: 0 : if (nl80211_prep_sched_scan_msg(msg, req, cmd) < 0) {
14988 : 0 : nlmsg_free(msg);
14989 : 0 : return;
14990 : : }
14991 : :
14992 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(req->wiphy), msg, 0,
14993 : : NL80211_MCGRP_SCAN, GFP_KERNEL);
14994 : : }
14995 : :
14996 : 0 : static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
14997 : : struct regulatory_request *request)
14998 : : {
14999 : : /* Userspace can always count this one always being set */
15000 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
15001 : 0 : goto nla_put_failure;
15002 : :
15003 [ # # ]: 0 : if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
15004 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
15005 : : NL80211_REGDOM_TYPE_WORLD))
15006 : 0 : goto nla_put_failure;
15007 [ # # ]: 0 : } else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
15008 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
15009 : : NL80211_REGDOM_TYPE_CUSTOM_WORLD))
15010 : 0 : goto nla_put_failure;
15011 [ # # ]: 0 : } else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
15012 [ # # ]: 0 : request->intersect) {
15013 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
15014 : : NL80211_REGDOM_TYPE_INTERSECTION))
15015 : 0 : goto nla_put_failure;
15016 : : } else {
15017 [ # # ]: 0 : if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
15018 [ # # ]: 0 : NL80211_REGDOM_TYPE_COUNTRY) ||
15019 : 0 : nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
15020 : 0 : request->alpha2))
15021 : 0 : goto nla_put_failure;
15022 : : }
15023 : :
15024 [ # # ]: 0 : if (request->wiphy_idx != WIPHY_IDX_INVALID) {
15025 : 0 : struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
15026 : :
15027 [ # # # # ]: 0 : if (wiphy &&
15028 : 0 : nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
15029 : 0 : goto nla_put_failure;
15030 : :
15031 [ # # ]: 0 : if (wiphy &&
15032 [ # # # # ]: 0 : wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
15033 : : nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
15034 : 0 : goto nla_put_failure;
15035 : : }
15036 : :
15037 : : return true;
15038 : :
15039 : : nla_put_failure:
15040 : : return false;
15041 : : }
15042 : :
15043 : : /*
15044 : : * This can happen on global regulatory changes or device specific settings
15045 : : * based on custom regulatory domains.
15046 : : */
15047 : 0 : void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
15048 : : struct regulatory_request *request)
15049 : : {
15050 : 0 : struct sk_buff *msg;
15051 : 0 : void *hdr;
15052 : :
15053 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
15054 [ # # ]: 0 : if (!msg)
15055 : : return;
15056 : :
15057 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
15058 [ # # ]: 0 : if (!hdr)
15059 : 0 : goto nla_put_failure;
15060 : :
15061 [ # # ]: 0 : if (!nl80211_reg_change_event_fill(msg, request))
15062 : 0 : goto nla_put_failure;
15063 : :
15064 : 0 : genlmsg_end(msg, hdr);
15065 : :
15066 : 0 : rcu_read_lock();
15067 : 0 : genlmsg_multicast_allns(&nl80211_fam, msg, 0,
15068 : : NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
15069 : 0 : rcu_read_unlock();
15070 : :
15071 : : return;
15072 : :
15073 : 0 : nla_put_failure:
15074 : 0 : nlmsg_free(msg);
15075 : : }
15076 : :
15077 : : static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
15078 : : struct net_device *netdev,
15079 : : const u8 *buf, size_t len,
15080 : : enum nl80211_commands cmd, gfp_t gfp,
15081 : : int uapsd_queues, const u8 *req_ies,
15082 : : size_t req_ies_len)
15083 : : {
15084 : : struct sk_buff *msg;
15085 : : void *hdr;
15086 : :
15087 : : msg = nlmsg_new(100 + len + req_ies_len, gfp);
15088 : : if (!msg)
15089 : : return;
15090 : :
15091 : : hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
15092 : : if (!hdr) {
15093 : : nlmsg_free(msg);
15094 : : return;
15095 : : }
15096 : :
15097 : : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15098 : : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15099 : : nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
15100 : : (req_ies &&
15101 : : nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies)))
15102 : : goto nla_put_failure;
15103 : :
15104 : : if (uapsd_queues >= 0) {
15105 : : struct nlattr *nla_wmm =
15106 : : nla_nest_start_noflag(msg, NL80211_ATTR_STA_WME);
15107 : : if (!nla_wmm)
15108 : : goto nla_put_failure;
15109 : :
15110 : : if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
15111 : : uapsd_queues))
15112 : : goto nla_put_failure;
15113 : :
15114 : : nla_nest_end(msg, nla_wmm);
15115 : : }
15116 : :
15117 : : genlmsg_end(msg, hdr);
15118 : :
15119 : : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15120 : : NL80211_MCGRP_MLME, gfp);
15121 : : return;
15122 : :
15123 : : nla_put_failure:
15124 : : nlmsg_free(msg);
15125 : : }
15126 : :
15127 : 0 : void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
15128 : : struct net_device *netdev, const u8 *buf,
15129 : : size_t len, gfp_t gfp)
15130 : : {
15131 : 0 : nl80211_send_mlme_event(rdev, netdev, buf, len,
15132 : : NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0);
15133 : 0 : }
15134 : :
15135 : 0 : void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
15136 : : struct net_device *netdev, const u8 *buf,
15137 : : size_t len, gfp_t gfp, int uapsd_queues,
15138 : : const u8 *req_ies, size_t req_ies_len)
15139 : : {
15140 : 0 : nl80211_send_mlme_event(rdev, netdev, buf, len,
15141 : : NL80211_CMD_ASSOCIATE, gfp, uapsd_queues,
15142 : : req_ies, req_ies_len);
15143 : 0 : }
15144 : :
15145 : 0 : void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
15146 : : struct net_device *netdev, const u8 *buf,
15147 : : size_t len, gfp_t gfp)
15148 : : {
15149 : 0 : nl80211_send_mlme_event(rdev, netdev, buf, len,
15150 : : NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0);
15151 : 0 : }
15152 : :
15153 : 0 : void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
15154 : : struct net_device *netdev, const u8 *buf,
15155 : : size_t len, gfp_t gfp)
15156 : : {
15157 : 0 : nl80211_send_mlme_event(rdev, netdev, buf, len,
15158 : : NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0);
15159 : 0 : }
15160 : :
15161 : 0 : void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
15162 : : size_t len)
15163 : : {
15164 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
15165 : 0 : struct wiphy *wiphy = wdev->wiphy;
15166 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
15167 : 0 : const struct ieee80211_mgmt *mgmt = (void *)buf;
15168 : 0 : u32 cmd;
15169 : :
15170 [ # # # # ]: 0 : if (WARN_ON(len < 2))
15171 : : return;
15172 : :
15173 [ # # ]: 0 : if (ieee80211_is_deauth(mgmt->frame_control))
15174 : : cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
15175 : : else
15176 : 0 : cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
15177 : :
15178 : 0 : trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
15179 : 0 : nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1,
15180 : : NULL, 0);
15181 : : }
15182 : : EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
15183 : :
15184 : : static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
15185 : : struct net_device *netdev, int cmd,
15186 : : const u8 *addr, gfp_t gfp)
15187 : : {
15188 : : struct sk_buff *msg;
15189 : : void *hdr;
15190 : :
15191 : : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15192 : : if (!msg)
15193 : : return;
15194 : :
15195 : : hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
15196 : : if (!hdr) {
15197 : : nlmsg_free(msg);
15198 : : return;
15199 : : }
15200 : :
15201 : : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15202 : : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15203 : : nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
15204 : : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
15205 : : goto nla_put_failure;
15206 : :
15207 : : genlmsg_end(msg, hdr);
15208 : :
15209 : : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15210 : : NL80211_MCGRP_MLME, gfp);
15211 : : return;
15212 : :
15213 : : nla_put_failure:
15214 : : nlmsg_free(msg);
15215 : : }
15216 : :
15217 : 0 : void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
15218 : : struct net_device *netdev, const u8 *addr,
15219 : : gfp_t gfp)
15220 : : {
15221 : 0 : nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
15222 : : addr, gfp);
15223 : 0 : }
15224 : :
15225 : 0 : void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
15226 : : struct net_device *netdev, const u8 *addr,
15227 : : gfp_t gfp)
15228 : : {
15229 : 0 : nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
15230 : : addr, gfp);
15231 : 0 : }
15232 : :
15233 : 0 : void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
15234 : : struct net_device *netdev,
15235 : : struct cfg80211_connect_resp_params *cr,
15236 : : gfp_t gfp)
15237 : : {
15238 : 0 : struct sk_buff *msg;
15239 : 0 : void *hdr;
15240 : :
15241 : 0 : msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
15242 : 0 : cr->fils.kek_len + cr->fils.pmk_len +
15243 [ # # ]: 0 : (cr->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp);
15244 [ # # ]: 0 : if (!msg)
15245 : : return;
15246 : :
15247 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
15248 [ # # ]: 0 : if (!hdr) {
15249 : 0 : nlmsg_free(msg);
15250 : 0 : return;
15251 : : }
15252 : :
15253 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15254 : 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15255 [ # # # # ]: 0 : (cr->bssid &&
15256 [ # # ]: 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
15257 : 0 : nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
15258 [ # # ]: 0 : cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
15259 : 0 : cr->status) ||
15260 [ # # # # ]: 0 : (cr->status < 0 &&
15261 [ # # ]: 0 : (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
15262 : : nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
15263 : 0 : cr->timeout_reason))) ||
15264 [ # # # # ]: 0 : (cr->req_ie &&
15265 : 0 : nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
15266 [ # # # # ]: 0 : (cr->resp_ie &&
15267 : 0 : nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
15268 : 0 : cr->resp_ie)) ||
15269 [ # # # # ]: 0 : (cr->fils.update_erp_next_seq_num &&
15270 : : nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
15271 : 0 : cr->fils.erp_next_seq_num)) ||
15272 [ # # ]: 0 : (cr->status == WLAN_STATUS_SUCCESS &&
15273 [ # # # # ]: 0 : ((cr->fils.kek &&
15274 : 0 : nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils.kek_len,
15275 : 0 : cr->fils.kek)) ||
15276 [ # # # # ]: 0 : (cr->fils.pmk &&
15277 : 0 : nla_put(msg, NL80211_ATTR_PMK, cr->fils.pmk_len, cr->fils.pmk)) ||
15278 [ # # # # ]: 0 : (cr->fils.pmkid &&
15279 : 0 : nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->fils.pmkid)))))
15280 : 0 : goto nla_put_failure;
15281 : :
15282 : 0 : genlmsg_end(msg, hdr);
15283 : :
15284 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15285 : : NL80211_MCGRP_MLME, gfp);
15286 : 0 : return;
15287 : :
15288 : : nla_put_failure:
15289 : 0 : nlmsg_free(msg);
15290 : : }
15291 : :
15292 : 0 : void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
15293 : : struct net_device *netdev,
15294 : : struct cfg80211_roam_info *info, gfp_t gfp)
15295 : : {
15296 : 0 : struct sk_buff *msg;
15297 : 0 : void *hdr;
15298 [ # # ]: 0 : const u8 *bssid = info->bss ? info->bss->bssid : info->bssid;
15299 : :
15300 : 0 : msg = nlmsg_new(100 + info->req_ie_len + info->resp_ie_len +
15301 : 0 : info->fils.kek_len + info->fils.pmk_len +
15302 [ # # ]: 0 : (info->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp);
15303 [ # # ]: 0 : if (!msg)
15304 : : return;
15305 : :
15306 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
15307 [ # # ]: 0 : if (!hdr) {
15308 : 0 : nlmsg_free(msg);
15309 : 0 : return;
15310 : : }
15311 : :
15312 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15313 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15314 : 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
15315 [ # # # # ]: 0 : (info->req_ie &&
15316 : 0 : nla_put(msg, NL80211_ATTR_REQ_IE, info->req_ie_len,
15317 : 0 : info->req_ie)) ||
15318 [ # # # # ]: 0 : (info->resp_ie &&
15319 : 0 : nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
15320 : 0 : info->resp_ie)) ||
15321 [ # # # # ]: 0 : (info->fils.update_erp_next_seq_num &&
15322 : : nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
15323 : 0 : info->fils.erp_next_seq_num)) ||
15324 [ # # # # ]: 0 : (info->fils.kek &&
15325 : 0 : nla_put(msg, NL80211_ATTR_FILS_KEK, info->fils.kek_len,
15326 : 0 : info->fils.kek)) ||
15327 [ # # # # ]: 0 : (info->fils.pmk &&
15328 : 0 : nla_put(msg, NL80211_ATTR_PMK, info->fils.pmk_len, info->fils.pmk)) ||
15329 [ # # # # ]: 0 : (info->fils.pmkid &&
15330 : 0 : nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, info->fils.pmkid)))
15331 : 0 : goto nla_put_failure;
15332 : :
15333 : 0 : genlmsg_end(msg, hdr);
15334 : :
15335 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15336 : : NL80211_MCGRP_MLME, gfp);
15337 : 0 : return;
15338 : :
15339 : : nla_put_failure:
15340 : 0 : nlmsg_free(msg);
15341 : : }
15342 : :
15343 : 0 : void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
15344 : : struct net_device *netdev, const u8 *bssid)
15345 : : {
15346 : 0 : struct sk_buff *msg;
15347 : 0 : void *hdr;
15348 : :
15349 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
15350 [ # # ]: 0 : if (!msg)
15351 : : return;
15352 : :
15353 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PORT_AUTHORIZED);
15354 [ # # ]: 0 : if (!hdr) {
15355 : 0 : nlmsg_free(msg);
15356 : 0 : return;
15357 : : }
15358 : :
15359 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15360 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15361 : 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
15362 : 0 : goto nla_put_failure;
15363 : :
15364 : 0 : genlmsg_end(msg, hdr);
15365 : :
15366 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15367 : : NL80211_MCGRP_MLME, GFP_KERNEL);
15368 : 0 : return;
15369 : :
15370 : : nla_put_failure:
15371 : 0 : nlmsg_free(msg);
15372 : : }
15373 : :
15374 : 0 : void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
15375 : : struct net_device *netdev, u16 reason,
15376 : : const u8 *ie, size_t ie_len, bool from_ap)
15377 : : {
15378 : 0 : struct sk_buff *msg;
15379 : 0 : void *hdr;
15380 : :
15381 : 0 : msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
15382 [ # # ]: 0 : if (!msg)
15383 : : return;
15384 : :
15385 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
15386 [ # # ]: 0 : if (!hdr) {
15387 : 0 : nlmsg_free(msg);
15388 : 0 : return;
15389 : : }
15390 : :
15391 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15392 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15393 [ # # ]: 0 : (reason &&
15394 [ # # ]: 0 : nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
15395 [ # # ]: 0 : (from_ap &&
15396 [ # # ]: 0 : nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
15397 [ # # ]: 0 : (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
15398 : 0 : goto nla_put_failure;
15399 : :
15400 : 0 : genlmsg_end(msg, hdr);
15401 : :
15402 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15403 : : NL80211_MCGRP_MLME, GFP_KERNEL);
15404 : 0 : return;
15405 : :
15406 : : nla_put_failure:
15407 : 0 : nlmsg_free(msg);
15408 : : }
15409 : :
15410 : 0 : void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
15411 : : struct net_device *netdev, const u8 *bssid,
15412 : : gfp_t gfp)
15413 : : {
15414 : 0 : struct sk_buff *msg;
15415 : 0 : void *hdr;
15416 : :
15417 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15418 [ # # ]: 0 : if (!msg)
15419 : : return;
15420 : :
15421 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
15422 [ # # ]: 0 : if (!hdr) {
15423 : 0 : nlmsg_free(msg);
15424 : 0 : return;
15425 : : }
15426 : :
15427 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15428 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15429 : 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
15430 : 0 : goto nla_put_failure;
15431 : :
15432 : 0 : genlmsg_end(msg, hdr);
15433 : :
15434 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15435 : : NL80211_MCGRP_MLME, gfp);
15436 : 0 : return;
15437 : :
15438 : : nla_put_failure:
15439 : 0 : nlmsg_free(msg);
15440 : : }
15441 : :
15442 : 0 : void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
15443 : : const u8 *ie, u8 ie_len,
15444 : : int sig_dbm, gfp_t gfp)
15445 : : {
15446 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
15447 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
15448 : 0 : struct sk_buff *msg;
15449 : 0 : void *hdr;
15450 : :
15451 [ # # # # ]: 0 : if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
15452 : : return;
15453 : :
15454 : 0 : trace_cfg80211_notify_new_peer_candidate(dev, addr);
15455 : :
15456 : 0 : msg = nlmsg_new(100 + ie_len, gfp);
15457 [ # # ]: 0 : if (!msg)
15458 : : return;
15459 : :
15460 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
15461 [ # # ]: 0 : if (!hdr) {
15462 : 0 : nlmsg_free(msg);
15463 : 0 : return;
15464 : : }
15465 : :
15466 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15467 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
15468 : 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
15469 [ # # # # ]: 0 : (ie_len && ie &&
15470 [ # # ]: 0 : nla_put(msg, NL80211_ATTR_IE, ie_len, ie)) ||
15471 [ # # ]: 0 : (sig_dbm &&
15472 : 0 : nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)))
15473 : 0 : goto nla_put_failure;
15474 : :
15475 : 0 : genlmsg_end(msg, hdr);
15476 : :
15477 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15478 : : NL80211_MCGRP_MLME, gfp);
15479 : 0 : return;
15480 : :
15481 : : nla_put_failure:
15482 : 0 : nlmsg_free(msg);
15483 : : }
15484 : : EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
15485 : :
15486 : 0 : void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
15487 : : struct net_device *netdev, const u8 *addr,
15488 : : enum nl80211_key_type key_type, int key_id,
15489 : : const u8 *tsc, gfp_t gfp)
15490 : : {
15491 : 0 : struct sk_buff *msg;
15492 : 0 : void *hdr;
15493 : :
15494 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15495 [ # # ]: 0 : if (!msg)
15496 : : return;
15497 : :
15498 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
15499 [ # # ]: 0 : if (!hdr) {
15500 : 0 : nlmsg_free(msg);
15501 : 0 : return;
15502 : : }
15503 : :
15504 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15505 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15506 [ # # # # ]: 0 : (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
15507 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
15508 [ # # ]: 0 : (key_id != -1 &&
15509 [ # # ]: 0 : nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
15510 [ # # ]: 0 : (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
15511 : 0 : goto nla_put_failure;
15512 : :
15513 : 0 : genlmsg_end(msg, hdr);
15514 : :
15515 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15516 : : NL80211_MCGRP_MLME, gfp);
15517 : 0 : return;
15518 : :
15519 : : nla_put_failure:
15520 : 0 : nlmsg_free(msg);
15521 : : }
15522 : :
15523 : 0 : void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
15524 : : struct ieee80211_channel *channel_before,
15525 : : struct ieee80211_channel *channel_after)
15526 : : {
15527 : 0 : struct sk_buff *msg;
15528 : 0 : void *hdr;
15529 : 0 : struct nlattr *nl_freq;
15530 : :
15531 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
15532 [ # # ]: 0 : if (!msg)
15533 : : return;
15534 : :
15535 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
15536 [ # # ]: 0 : if (!hdr) {
15537 : 0 : nlmsg_free(msg);
15538 : 0 : return;
15539 : : }
15540 : :
15541 : : /*
15542 : : * Since we are applying the beacon hint to a wiphy we know its
15543 : : * wiphy_idx is valid
15544 : : */
15545 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
15546 : 0 : goto nla_put_failure;
15547 : :
15548 : : /* Before */
15549 : 0 : nl_freq = nla_nest_start_noflag(msg, NL80211_ATTR_FREQ_BEFORE);
15550 [ # # ]: 0 : if (!nl_freq)
15551 : 0 : goto nla_put_failure;
15552 : :
15553 [ # # ]: 0 : if (nl80211_msg_put_channel(msg, wiphy, channel_before, false))
15554 : 0 : goto nla_put_failure;
15555 : 0 : nla_nest_end(msg, nl_freq);
15556 : :
15557 : : /* After */
15558 : 0 : nl_freq = nla_nest_start_noflag(msg, NL80211_ATTR_FREQ_AFTER);
15559 [ # # ]: 0 : if (!nl_freq)
15560 : 0 : goto nla_put_failure;
15561 : :
15562 [ # # ]: 0 : if (nl80211_msg_put_channel(msg, wiphy, channel_after, false))
15563 : 0 : goto nla_put_failure;
15564 : 0 : nla_nest_end(msg, nl_freq);
15565 : :
15566 : 0 : genlmsg_end(msg, hdr);
15567 : :
15568 : 0 : rcu_read_lock();
15569 : 0 : genlmsg_multicast_allns(&nl80211_fam, msg, 0,
15570 : : NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
15571 : 0 : rcu_read_unlock();
15572 : :
15573 : : return;
15574 : :
15575 : 0 : nla_put_failure:
15576 : 0 : nlmsg_free(msg);
15577 : : }
15578 : :
15579 : : static void nl80211_send_remain_on_chan_event(
15580 : : int cmd, struct cfg80211_registered_device *rdev,
15581 : : struct wireless_dev *wdev, u64 cookie,
15582 : : struct ieee80211_channel *chan,
15583 : : unsigned int duration, gfp_t gfp)
15584 : : {
15585 : : struct sk_buff *msg;
15586 : : void *hdr;
15587 : :
15588 : : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15589 : : if (!msg)
15590 : : return;
15591 : :
15592 : : hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
15593 : : if (!hdr) {
15594 : : nlmsg_free(msg);
15595 : : return;
15596 : : }
15597 : :
15598 : : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15599 : : (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
15600 : : wdev->netdev->ifindex)) ||
15601 : : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15602 : : NL80211_ATTR_PAD) ||
15603 : : nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
15604 : : nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
15605 : : NL80211_CHAN_NO_HT) ||
15606 : : nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
15607 : : NL80211_ATTR_PAD))
15608 : : goto nla_put_failure;
15609 : :
15610 : : if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
15611 : : nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
15612 : : goto nla_put_failure;
15613 : :
15614 : : genlmsg_end(msg, hdr);
15615 : :
15616 : : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15617 : : NL80211_MCGRP_MLME, gfp);
15618 : : return;
15619 : :
15620 : : nla_put_failure:
15621 : : nlmsg_free(msg);
15622 : : }
15623 : :
15624 : 0 : void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
15625 : : struct ieee80211_channel *chan,
15626 : : unsigned int duration, gfp_t gfp)
15627 : : {
15628 : 0 : struct wiphy *wiphy = wdev->wiphy;
15629 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
15630 : :
15631 : 0 : trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
15632 : 0 : nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
15633 : : rdev, wdev, cookie, chan,
15634 : : duration, gfp);
15635 : 0 : }
15636 : : EXPORT_SYMBOL(cfg80211_ready_on_channel);
15637 : :
15638 : 0 : void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
15639 : : struct ieee80211_channel *chan,
15640 : : gfp_t gfp)
15641 : : {
15642 : 0 : struct wiphy *wiphy = wdev->wiphy;
15643 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
15644 : :
15645 : 0 : trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
15646 : 0 : nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
15647 : : rdev, wdev, cookie, chan, 0, gfp);
15648 : 0 : }
15649 : : EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
15650 : :
15651 : 0 : void cfg80211_tx_mgmt_expired(struct wireless_dev *wdev, u64 cookie,
15652 : : struct ieee80211_channel *chan,
15653 : : gfp_t gfp)
15654 : : {
15655 : 0 : struct wiphy *wiphy = wdev->wiphy;
15656 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
15657 : :
15658 : 0 : trace_cfg80211_tx_mgmt_expired(wdev, cookie, chan);
15659 : 0 : nl80211_send_remain_on_chan_event(NL80211_CMD_FRAME_WAIT_CANCEL,
15660 : : rdev, wdev, cookie, chan, 0, gfp);
15661 : 0 : }
15662 : : EXPORT_SYMBOL(cfg80211_tx_mgmt_expired);
15663 : :
15664 : 0 : void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
15665 : : struct station_info *sinfo, gfp_t gfp)
15666 : : {
15667 : 0 : struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
15668 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
15669 : 0 : struct sk_buff *msg;
15670 : :
15671 : 0 : trace_cfg80211_new_sta(dev, mac_addr, sinfo);
15672 : :
15673 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15674 [ # # ]: 0 : if (!msg)
15675 : : return;
15676 : :
15677 [ # # ]: 0 : if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
15678 : : rdev, dev, mac_addr, sinfo) < 0) {
15679 : 0 : nlmsg_free(msg);
15680 : 0 : return;
15681 : : }
15682 : :
15683 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15684 : : NL80211_MCGRP_MLME, gfp);
15685 : : }
15686 : : EXPORT_SYMBOL(cfg80211_new_sta);
15687 : :
15688 : 0 : void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
15689 : : struct station_info *sinfo, gfp_t gfp)
15690 : : {
15691 : 0 : struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
15692 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
15693 : 0 : struct sk_buff *msg;
15694 : 0 : struct station_info empty_sinfo = {};
15695 : :
15696 [ # # ]: 0 : if (!sinfo)
15697 : 0 : sinfo = &empty_sinfo;
15698 : :
15699 : 0 : trace_cfg80211_del_sta(dev, mac_addr);
15700 : :
15701 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15702 [ # # ]: 0 : if (!msg) {
15703 : 0 : cfg80211_sinfo_release_content(sinfo);
15704 : 0 : return;
15705 : : }
15706 : :
15707 [ # # ]: 0 : if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
15708 : : rdev, dev, mac_addr, sinfo) < 0) {
15709 : 0 : nlmsg_free(msg);
15710 : 0 : return;
15711 : : }
15712 : :
15713 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15714 : : NL80211_MCGRP_MLME, gfp);
15715 : : }
15716 : : EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
15717 : :
15718 : 0 : void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
15719 : : enum nl80211_connect_failed_reason reason,
15720 : : gfp_t gfp)
15721 : : {
15722 : 0 : struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
15723 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
15724 : 0 : struct sk_buff *msg;
15725 : 0 : void *hdr;
15726 : :
15727 : 0 : msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
15728 [ # # ]: 0 : if (!msg)
15729 : : return;
15730 : :
15731 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED);
15732 [ # # ]: 0 : if (!hdr) {
15733 : 0 : nlmsg_free(msg);
15734 : 0 : return;
15735 : : }
15736 : :
15737 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
15738 [ # # ]: 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
15739 : : nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason))
15740 : 0 : goto nla_put_failure;
15741 : :
15742 : 0 : genlmsg_end(msg, hdr);
15743 : :
15744 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15745 : : NL80211_MCGRP_MLME, gfp);
15746 : 0 : return;
15747 : :
15748 : : nla_put_failure:
15749 : 0 : nlmsg_free(msg);
15750 : : }
15751 : : EXPORT_SYMBOL(cfg80211_conn_failed);
15752 : :
15753 : 0 : static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
15754 : : const u8 *addr, gfp_t gfp)
15755 : : {
15756 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
15757 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
15758 : 0 : struct sk_buff *msg;
15759 : 0 : void *hdr;
15760 [ # # ]: 0 : u32 nlportid = READ_ONCE(wdev->ap_unexpected_nlportid);
15761 : :
15762 [ # # ]: 0 : if (!nlportid)
15763 : : return false;
15764 : :
15765 : 0 : msg = nlmsg_new(100, gfp);
15766 [ # # ]: 0 : if (!msg)
15767 : : return true;
15768 : :
15769 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
15770 [ # # ]: 0 : if (!hdr) {
15771 : 0 : nlmsg_free(msg);
15772 : 0 : return true;
15773 : : }
15774 : :
15775 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15776 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
15777 : 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
15778 : 0 : goto nla_put_failure;
15779 : :
15780 : 0 : genlmsg_end(msg, hdr);
15781 : 0 : genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
15782 : 0 : return true;
15783 : :
15784 : : nla_put_failure:
15785 : 0 : nlmsg_free(msg);
15786 : 0 : return true;
15787 : : }
15788 : :
15789 : 0 : bool cfg80211_rx_spurious_frame(struct net_device *dev,
15790 : : const u8 *addr, gfp_t gfp)
15791 : : {
15792 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
15793 : 0 : bool ret;
15794 : :
15795 : 0 : trace_cfg80211_rx_spurious_frame(dev, addr);
15796 : :
15797 [ # # # # ]: 0 : if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
15798 : : wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
15799 : 0 : trace_cfg80211_return_bool(false);
15800 : 0 : return false;
15801 : : }
15802 : 0 : ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
15803 : : addr, gfp);
15804 : 0 : trace_cfg80211_return_bool(ret);
15805 : 0 : return ret;
15806 : : }
15807 : : EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
15808 : :
15809 : 0 : bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
15810 : : const u8 *addr, gfp_t gfp)
15811 : : {
15812 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
15813 : 0 : bool ret;
15814 : :
15815 : 0 : trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
15816 : :
15817 [ # # # # : 0 : if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
# # # # ]
15818 : : wdev->iftype != NL80211_IFTYPE_P2P_GO &&
15819 : : wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
15820 : 0 : trace_cfg80211_return_bool(false);
15821 : 0 : return false;
15822 : : }
15823 : 0 : ret = __nl80211_unexpected_frame(dev,
15824 : : NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
15825 : : addr, gfp);
15826 : 0 : trace_cfg80211_return_bool(ret);
15827 : 0 : return ret;
15828 : : }
15829 : : EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
15830 : :
15831 : 0 : int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
15832 : : struct wireless_dev *wdev, u32 nlportid,
15833 : : int freq, int sig_dbm,
15834 : : const u8 *buf, size_t len, u32 flags, gfp_t gfp)
15835 : : {
15836 : 0 : struct net_device *netdev = wdev->netdev;
15837 : 0 : struct sk_buff *msg;
15838 : 0 : void *hdr;
15839 : :
15840 : 0 : msg = nlmsg_new(100 + len, gfp);
15841 [ # # ]: 0 : if (!msg)
15842 : : return -ENOMEM;
15843 : :
15844 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
15845 [ # # ]: 0 : if (!hdr) {
15846 : 0 : nlmsg_free(msg);
15847 : 0 : return -ENOMEM;
15848 : : }
15849 : :
15850 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15851 [ # # ]: 0 : (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
15852 [ # # ]: 0 : netdev->ifindex)) ||
15853 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15854 [ # # ]: 0 : NL80211_ATTR_PAD) ||
15855 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
15856 [ # # ]: 0 : (sig_dbm &&
15857 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
15858 [ # # ]: 0 : nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
15859 [ # # ]: 0 : (flags &&
15860 : : nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
15861 : 0 : goto nla_put_failure;
15862 : :
15863 : 0 : genlmsg_end(msg, hdr);
15864 : :
15865 : 0 : return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
15866 : :
15867 : : nla_put_failure:
15868 : 0 : nlmsg_free(msg);
15869 : 0 : return -ENOBUFS;
15870 : : }
15871 : :
15872 : 0 : void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
15873 : : const u8 *buf, size_t len, bool ack, gfp_t gfp)
15874 : : {
15875 : 0 : struct wiphy *wiphy = wdev->wiphy;
15876 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
15877 : 0 : struct net_device *netdev = wdev->netdev;
15878 : 0 : struct sk_buff *msg;
15879 : 0 : void *hdr;
15880 : :
15881 : 0 : trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
15882 : :
15883 : 0 : msg = nlmsg_new(100 + len, gfp);
15884 [ # # ]: 0 : if (!msg)
15885 : : return;
15886 : :
15887 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
15888 [ # # ]: 0 : if (!hdr) {
15889 : 0 : nlmsg_free(msg);
15890 : 0 : return;
15891 : : }
15892 : :
15893 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15894 [ # # ]: 0 : (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
15895 [ # # ]: 0 : netdev->ifindex)) ||
15896 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15897 [ # # ]: 0 : NL80211_ATTR_PAD) ||
15898 [ # # ]: 0 : nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
15899 : : nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
15900 [ # # ]: 0 : NL80211_ATTR_PAD) ||
15901 [ # # ]: 0 : (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
15902 : 0 : goto nla_put_failure;
15903 : :
15904 : 0 : genlmsg_end(msg, hdr);
15905 : :
15906 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15907 : : NL80211_MCGRP_MLME, gfp);
15908 : 0 : return;
15909 : :
15910 : : nla_put_failure:
15911 : 0 : nlmsg_free(msg);
15912 : : }
15913 : : EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
15914 : :
15915 : 0 : static int __nl80211_rx_control_port(struct net_device *dev,
15916 : : struct sk_buff *skb,
15917 : : bool unencrypted, gfp_t gfp)
15918 : : {
15919 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
15920 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
15921 [ # # ]: 0 : struct ethhdr *ehdr = eth_hdr(skb);
15922 : 0 : const u8 *addr = ehdr->h_source;
15923 : 0 : u16 proto = be16_to_cpu(skb->protocol);
15924 : 0 : struct sk_buff *msg;
15925 : 0 : void *hdr;
15926 : 0 : struct nlattr *frame;
15927 : :
15928 [ # # ]: 0 : u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid);
15929 : :
15930 [ # # ]: 0 : if (!nlportid)
15931 : : return -ENOENT;
15932 : :
15933 : 0 : msg = nlmsg_new(100 + skb->len, gfp);
15934 [ # # ]: 0 : if (!msg)
15935 : : return -ENOMEM;
15936 : :
15937 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME);
15938 [ # # ]: 0 : if (!hdr) {
15939 : 0 : nlmsg_free(msg);
15940 : 0 : return -ENOBUFS;
15941 : : }
15942 : :
15943 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15944 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
15945 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15946 [ # # ]: 0 : NL80211_ATTR_PAD) ||
15947 [ # # ]: 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
15948 [ # # ]: 0 : nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
15949 [ # # ]: 0 : (unencrypted && nla_put_flag(msg,
15950 : : NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
15951 : 0 : goto nla_put_failure;
15952 : :
15953 : 0 : frame = nla_reserve(msg, NL80211_ATTR_FRAME, skb->len);
15954 [ # # ]: 0 : if (!frame)
15955 : 0 : goto nla_put_failure;
15956 : :
15957 : 0 : skb_copy_bits(skb, 0, nla_data(frame), skb->len);
15958 : 0 : genlmsg_end(msg, hdr);
15959 : :
15960 : 0 : return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
15961 : :
15962 : 0 : nla_put_failure:
15963 : 0 : nlmsg_free(msg);
15964 : 0 : return -ENOBUFS;
15965 : : }
15966 : :
15967 : 0 : bool cfg80211_rx_control_port(struct net_device *dev,
15968 : : struct sk_buff *skb, bool unencrypted)
15969 : : {
15970 : 0 : int ret;
15971 : :
15972 : 0 : trace_cfg80211_rx_control_port(dev, skb, unencrypted);
15973 : 0 : ret = __nl80211_rx_control_port(dev, skb, unencrypted, GFP_ATOMIC);
15974 : 0 : trace_cfg80211_return_bool(ret == 0);
15975 : 0 : return ret == 0;
15976 : : }
15977 : : EXPORT_SYMBOL(cfg80211_rx_control_port);
15978 : :
15979 : : static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
15980 : : const char *mac, gfp_t gfp)
15981 : : {
15982 : : struct wireless_dev *wdev = dev->ieee80211_ptr;
15983 : : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
15984 : : struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15985 : : void **cb;
15986 : :
15987 : : if (!msg)
15988 : : return NULL;
15989 : :
15990 : : cb = (void **)msg->cb;
15991 : :
15992 : : cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
15993 : : if (!cb[0]) {
15994 : : nlmsg_free(msg);
15995 : : return NULL;
15996 : : }
15997 : :
15998 : : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15999 : : nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
16000 : : goto nla_put_failure;
16001 : :
16002 : : if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
16003 : : goto nla_put_failure;
16004 : :
16005 : : cb[1] = nla_nest_start_noflag(msg, NL80211_ATTR_CQM);
16006 : : if (!cb[1])
16007 : : goto nla_put_failure;
16008 : :
16009 : : cb[2] = rdev;
16010 : :
16011 : : return msg;
16012 : : nla_put_failure:
16013 : : nlmsg_free(msg);
16014 : : return NULL;
16015 : : }
16016 : :
16017 : 0 : static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
16018 : : {
16019 : 0 : void **cb = (void **)msg->cb;
16020 : 0 : struct cfg80211_registered_device *rdev = cb[2];
16021 : :
16022 : 0 : nla_nest_end(msg, cb[1]);
16023 : 0 : genlmsg_end(msg, cb[0]);
16024 : :
16025 : 0 : memset(msg->cb, 0, sizeof(msg->cb));
16026 : :
16027 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16028 : : NL80211_MCGRP_MLME, gfp);
16029 : 0 : }
16030 : :
16031 : 0 : void cfg80211_cqm_rssi_notify(struct net_device *dev,
16032 : : enum nl80211_cqm_rssi_threshold_event rssi_event,
16033 : : s32 rssi_level, gfp_t gfp)
16034 : : {
16035 : 0 : struct sk_buff *msg;
16036 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
16037 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
16038 : :
16039 : 0 : trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
16040 : :
16041 [ # # # # ]: 0 : if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
16042 : : rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
16043 : : return;
16044 : :
16045 [ # # ]: 0 : if (wdev->cqm_config) {
16046 : 0 : wdev->cqm_config->last_rssi_event_value = rssi_level;
16047 : :
16048 : 0 : cfg80211_cqm_rssi_update(rdev, dev);
16049 : :
16050 [ # # ]: 0 : if (rssi_level == 0)
16051 : 0 : rssi_level = wdev->cqm_config->last_rssi_event_value;
16052 : : }
16053 : :
16054 : 0 : msg = cfg80211_prepare_cqm(dev, NULL, gfp);
16055 [ # # ]: 0 : if (!msg)
16056 : : return;
16057 : :
16058 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
16059 : : rssi_event))
16060 : 0 : goto nla_put_failure;
16061 : :
16062 [ # # # # ]: 0 : if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
16063 : : rssi_level))
16064 : 0 : goto nla_put_failure;
16065 : :
16066 : 0 : cfg80211_send_cqm(msg, gfp);
16067 : :
16068 : 0 : return;
16069 : :
16070 : 0 : nla_put_failure:
16071 : 0 : nlmsg_free(msg);
16072 : : }
16073 : : EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
16074 : :
16075 : 0 : void cfg80211_cqm_txe_notify(struct net_device *dev,
16076 : : const u8 *peer, u32 num_packets,
16077 : : u32 rate, u32 intvl, gfp_t gfp)
16078 : : {
16079 : 0 : struct sk_buff *msg;
16080 : :
16081 : 0 : msg = cfg80211_prepare_cqm(dev, peer, gfp);
16082 [ # # ]: 0 : if (!msg)
16083 : : return;
16084 : :
16085 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
16086 : 0 : goto nla_put_failure;
16087 : :
16088 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
16089 : 0 : goto nla_put_failure;
16090 : :
16091 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
16092 : 0 : goto nla_put_failure;
16093 : :
16094 : 0 : cfg80211_send_cqm(msg, gfp);
16095 : 0 : return;
16096 : :
16097 : 0 : nla_put_failure:
16098 : 0 : nlmsg_free(msg);
16099 : : }
16100 : : EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
16101 : :
16102 : 0 : void cfg80211_cqm_pktloss_notify(struct net_device *dev,
16103 : : const u8 *peer, u32 num_packets, gfp_t gfp)
16104 : : {
16105 : 0 : struct sk_buff *msg;
16106 : :
16107 : 0 : trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
16108 : :
16109 : 0 : msg = cfg80211_prepare_cqm(dev, peer, gfp);
16110 [ # # ]: 0 : if (!msg)
16111 : : return;
16112 : :
16113 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
16114 : 0 : goto nla_put_failure;
16115 : :
16116 : 0 : cfg80211_send_cqm(msg, gfp);
16117 : 0 : return;
16118 : :
16119 : : nla_put_failure:
16120 : 0 : nlmsg_free(msg);
16121 : : }
16122 : : EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
16123 : :
16124 : 0 : void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
16125 : : {
16126 : 0 : struct sk_buff *msg;
16127 : :
16128 : 0 : msg = cfg80211_prepare_cqm(dev, NULL, gfp);
16129 [ # # ]: 0 : if (!msg)
16130 : : return;
16131 : :
16132 [ # # ]: 0 : if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
16133 : 0 : goto nla_put_failure;
16134 : :
16135 : 0 : cfg80211_send_cqm(msg, gfp);
16136 : 0 : return;
16137 : :
16138 : : nla_put_failure:
16139 : 0 : nlmsg_free(msg);
16140 : : }
16141 : : EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
16142 : :
16143 : : static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
16144 : : struct net_device *netdev, const u8 *bssid,
16145 : : const u8 *replay_ctr, gfp_t gfp)
16146 : : {
16147 : : struct sk_buff *msg;
16148 : : struct nlattr *rekey_attr;
16149 : : void *hdr;
16150 : :
16151 : : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16152 : : if (!msg)
16153 : : return;
16154 : :
16155 : : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
16156 : : if (!hdr) {
16157 : : nlmsg_free(msg);
16158 : : return;
16159 : : }
16160 : :
16161 : : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16162 : : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
16163 : : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
16164 : : goto nla_put_failure;
16165 : :
16166 : : rekey_attr = nla_nest_start_noflag(msg, NL80211_ATTR_REKEY_DATA);
16167 : : if (!rekey_attr)
16168 : : goto nla_put_failure;
16169 : :
16170 : : if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
16171 : : NL80211_REPLAY_CTR_LEN, replay_ctr))
16172 : : goto nla_put_failure;
16173 : :
16174 : : nla_nest_end(msg, rekey_attr);
16175 : :
16176 : : genlmsg_end(msg, hdr);
16177 : :
16178 : : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16179 : : NL80211_MCGRP_MLME, gfp);
16180 : : return;
16181 : :
16182 : : nla_put_failure:
16183 : : nlmsg_free(msg);
16184 : : }
16185 : :
16186 : 0 : void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
16187 : : const u8 *replay_ctr, gfp_t gfp)
16188 : : {
16189 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
16190 : 0 : struct wiphy *wiphy = wdev->wiphy;
16191 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
16192 : :
16193 : 0 : trace_cfg80211_gtk_rekey_notify(dev, bssid);
16194 : 0 : nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
16195 : 0 : }
16196 : : EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
16197 : :
16198 : : static void
16199 : 0 : nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
16200 : : struct net_device *netdev, int index,
16201 : : const u8 *bssid, bool preauth, gfp_t gfp)
16202 : : {
16203 : 0 : struct sk_buff *msg;
16204 : 0 : struct nlattr *attr;
16205 : 0 : void *hdr;
16206 : :
16207 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16208 [ # # ]: 0 : if (!msg)
16209 : : return;
16210 : :
16211 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
16212 [ # # ]: 0 : if (!hdr) {
16213 : 0 : nlmsg_free(msg);
16214 : 0 : return;
16215 : : }
16216 : :
16217 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16218 : 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
16219 : 0 : goto nla_put_failure;
16220 : :
16221 : 0 : attr = nla_nest_start_noflag(msg, NL80211_ATTR_PMKSA_CANDIDATE);
16222 [ # # ]: 0 : if (!attr)
16223 : 0 : goto nla_put_failure;
16224 : :
16225 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
16226 [ # # ]: 0 : nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
16227 [ # # ]: 0 : (preauth &&
16228 : : nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
16229 : 0 : goto nla_put_failure;
16230 : :
16231 : 0 : nla_nest_end(msg, attr);
16232 : :
16233 : 0 : genlmsg_end(msg, hdr);
16234 : :
16235 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16236 : : NL80211_MCGRP_MLME, gfp);
16237 : 0 : return;
16238 : :
16239 : 0 : nla_put_failure:
16240 : 0 : nlmsg_free(msg);
16241 : : }
16242 : :
16243 : 0 : void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
16244 : : const u8 *bssid, bool preauth, gfp_t gfp)
16245 : : {
16246 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
16247 : 0 : struct wiphy *wiphy = wdev->wiphy;
16248 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
16249 : :
16250 : 0 : trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
16251 : 0 : nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
16252 : 0 : }
16253 : : EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
16254 : :
16255 : 0 : static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
16256 : : struct net_device *netdev,
16257 : : struct cfg80211_chan_def *chandef,
16258 : : gfp_t gfp,
16259 : : enum nl80211_commands notif,
16260 : : u8 count)
16261 : : {
16262 : 0 : struct sk_buff *msg;
16263 : 0 : void *hdr;
16264 : :
16265 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16266 [ # # ]: 0 : if (!msg)
16267 : : return;
16268 : :
16269 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, notif);
16270 [ # # ]: 0 : if (!hdr) {
16271 : 0 : nlmsg_free(msg);
16272 : 0 : return;
16273 : : }
16274 : :
16275 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
16276 : 0 : goto nla_put_failure;
16277 : :
16278 [ # # ]: 0 : if (nl80211_send_chandef(msg, chandef))
16279 : 0 : goto nla_put_failure;
16280 : :
16281 [ # # # # ]: 0 : if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) &&
16282 : 0 : (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count)))
16283 : 0 : goto nla_put_failure;
16284 : :
16285 : 0 : genlmsg_end(msg, hdr);
16286 : :
16287 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16288 : : NL80211_MCGRP_MLME, gfp);
16289 : 0 : return;
16290 : :
16291 : 0 : nla_put_failure:
16292 : 0 : nlmsg_free(msg);
16293 : : }
16294 : :
16295 : 0 : void cfg80211_ch_switch_notify(struct net_device *dev,
16296 : : struct cfg80211_chan_def *chandef)
16297 : : {
16298 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
16299 : 0 : struct wiphy *wiphy = wdev->wiphy;
16300 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
16301 : :
16302 : 0 : ASSERT_WDEV_LOCK(wdev);
16303 : :
16304 : 0 : trace_cfg80211_ch_switch_notify(dev, chandef);
16305 : :
16306 : 0 : wdev->chandef = *chandef;
16307 : 0 : wdev->preset_chandef = *chandef;
16308 : :
16309 [ # # ]: 0 : if (wdev->iftype == NL80211_IFTYPE_STATION &&
16310 [ # # # # ]: 0 : !WARN_ON(!wdev->current_bss))
16311 : 0 : cfg80211_update_assoc_bss_entry(wdev, chandef->chan);
16312 : :
16313 : 0 : cfg80211_sched_dfs_chan_update(rdev);
16314 : :
16315 : 0 : nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
16316 : : NL80211_CMD_CH_SWITCH_NOTIFY, 0);
16317 : 0 : }
16318 : : EXPORT_SYMBOL(cfg80211_ch_switch_notify);
16319 : :
16320 : 0 : void cfg80211_ch_switch_started_notify(struct net_device *dev,
16321 : : struct cfg80211_chan_def *chandef,
16322 : : u8 count)
16323 : : {
16324 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
16325 : 0 : struct wiphy *wiphy = wdev->wiphy;
16326 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
16327 : :
16328 : 0 : trace_cfg80211_ch_switch_started_notify(dev, chandef);
16329 : :
16330 : 0 : nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
16331 : : NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count);
16332 : 0 : }
16333 : : EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
16334 : :
16335 : : void
16336 : 0 : nl80211_radar_notify(struct cfg80211_registered_device *rdev,
16337 : : const struct cfg80211_chan_def *chandef,
16338 : : enum nl80211_radar_event event,
16339 : : struct net_device *netdev, gfp_t gfp)
16340 : : {
16341 : 0 : struct sk_buff *msg;
16342 : 0 : void *hdr;
16343 : :
16344 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16345 [ # # ]: 0 : if (!msg)
16346 : : return;
16347 : :
16348 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
16349 [ # # ]: 0 : if (!hdr) {
16350 : 0 : nlmsg_free(msg);
16351 : 0 : return;
16352 : : }
16353 : :
16354 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
16355 : 0 : goto nla_put_failure;
16356 : :
16357 : : /* NOP and radar events don't need a netdev parameter */
16358 [ # # ]: 0 : if (netdev) {
16359 : 0 : struct wireless_dev *wdev = netdev->ieee80211_ptr;
16360 : :
16361 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
16362 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
16363 : : NL80211_ATTR_PAD))
16364 : 0 : goto nla_put_failure;
16365 : : }
16366 : :
16367 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
16368 : 0 : goto nla_put_failure;
16369 : :
16370 [ # # ]: 0 : if (nl80211_send_chandef(msg, chandef))
16371 : 0 : goto nla_put_failure;
16372 : :
16373 : 0 : genlmsg_end(msg, hdr);
16374 : :
16375 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16376 : : NL80211_MCGRP_MLME, gfp);
16377 : 0 : return;
16378 : :
16379 : 0 : nla_put_failure:
16380 : 0 : nlmsg_free(msg);
16381 : : }
16382 : :
16383 : 0 : void cfg80211_sta_opmode_change_notify(struct net_device *dev, const u8 *mac,
16384 : : struct sta_opmode_info *sta_opmode,
16385 : : gfp_t gfp)
16386 : : {
16387 : 0 : struct sk_buff *msg;
16388 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
16389 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
16390 : 0 : void *hdr;
16391 : :
16392 [ # # # # ]: 0 : if (WARN_ON(!mac))
16393 : : return;
16394 : :
16395 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16396 [ # # ]: 0 : if (!msg)
16397 : : return;
16398 : :
16399 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STA_OPMODE_CHANGED);
16400 [ # # ]: 0 : if (!hdr) {
16401 : 0 : nlmsg_free(msg);
16402 : 0 : return;
16403 : : }
16404 : :
16405 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
16406 : 0 : goto nla_put_failure;
16407 : :
16408 [ # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
16409 : 0 : goto nla_put_failure;
16410 : :
16411 [ # # ]: 0 : if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
16412 : 0 : goto nla_put_failure;
16413 : :
16414 [ # # # # ]: 0 : if ((sta_opmode->changed & STA_OPMODE_SMPS_MODE_CHANGED) &&
16415 : 0 : nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, sta_opmode->smps_mode))
16416 : 0 : goto nla_put_failure;
16417 : :
16418 [ # # # # ]: 0 : if ((sta_opmode->changed & STA_OPMODE_MAX_BW_CHANGED) &&
16419 : 0 : nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, sta_opmode->bw))
16420 : 0 : goto nla_put_failure;
16421 : :
16422 [ # # # # ]: 0 : if ((sta_opmode->changed & STA_OPMODE_N_SS_CHANGED) &&
16423 : 0 : nla_put_u8(msg, NL80211_ATTR_NSS, sta_opmode->rx_nss))
16424 : 0 : goto nla_put_failure;
16425 : :
16426 : 0 : genlmsg_end(msg, hdr);
16427 : :
16428 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16429 : : NL80211_MCGRP_MLME, gfp);
16430 : :
16431 : 0 : return;
16432 : :
16433 : 0 : nla_put_failure:
16434 : 0 : nlmsg_free(msg);
16435 : : }
16436 : : EXPORT_SYMBOL(cfg80211_sta_opmode_change_notify);
16437 : :
16438 : 0 : void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
16439 : : u64 cookie, bool acked, s32 ack_signal,
16440 : : bool is_valid_ack_signal, gfp_t gfp)
16441 : : {
16442 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
16443 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
16444 : 0 : struct sk_buff *msg;
16445 : 0 : void *hdr;
16446 : :
16447 : 0 : trace_cfg80211_probe_status(dev, addr, cookie, acked);
16448 : :
16449 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16450 : :
16451 [ # # ]: 0 : if (!msg)
16452 : : return;
16453 : :
16454 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
16455 [ # # ]: 0 : if (!hdr) {
16456 : 0 : nlmsg_free(msg);
16457 : 0 : return;
16458 : : }
16459 : :
16460 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16461 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
16462 [ # # ]: 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
16463 : : nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
16464 [ # # ]: 0 : NL80211_ATTR_PAD) ||
16465 [ # # # # ]: 0 : (acked && nla_put_flag(msg, NL80211_ATTR_ACK)) ||
16466 [ # # ]: 0 : (is_valid_ack_signal && nla_put_s32(msg, NL80211_ATTR_ACK_SIGNAL,
16467 : : ack_signal)))
16468 : 0 : goto nla_put_failure;
16469 : :
16470 : 0 : genlmsg_end(msg, hdr);
16471 : :
16472 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16473 : : NL80211_MCGRP_MLME, gfp);
16474 : 0 : return;
16475 : :
16476 : : nla_put_failure:
16477 : 0 : nlmsg_free(msg);
16478 : : }
16479 : : EXPORT_SYMBOL(cfg80211_probe_status);
16480 : :
16481 : 0 : void cfg80211_report_obss_beacon(struct wiphy *wiphy,
16482 : : const u8 *frame, size_t len,
16483 : : int freq, int sig_dbm)
16484 : : {
16485 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
16486 : 0 : struct sk_buff *msg;
16487 : 0 : void *hdr;
16488 : 0 : struct cfg80211_beacon_registration *reg;
16489 : :
16490 : 0 : trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
16491 : :
16492 : 0 : spin_lock_bh(&rdev->beacon_registrations_lock);
16493 [ # # ]: 0 : list_for_each_entry(reg, &rdev->beacon_registrations, list) {
16494 : 0 : msg = nlmsg_new(len + 100, GFP_ATOMIC);
16495 [ # # ]: 0 : if (!msg) {
16496 : 0 : spin_unlock_bh(&rdev->beacon_registrations_lock);
16497 : 0 : return;
16498 : : }
16499 : :
16500 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
16501 [ # # ]: 0 : if (!hdr)
16502 : 0 : goto nla_put_failure;
16503 : :
16504 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16505 [ # # ]: 0 : (freq &&
16506 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
16507 [ # # ]: 0 : (sig_dbm &&
16508 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
16509 : 0 : nla_put(msg, NL80211_ATTR_FRAME, len, frame))
16510 : 0 : goto nla_put_failure;
16511 : :
16512 : 0 : genlmsg_end(msg, hdr);
16513 : :
16514 : 0 : genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
16515 : : }
16516 : 0 : spin_unlock_bh(&rdev->beacon_registrations_lock);
16517 : : return;
16518 : :
16519 : 0 : nla_put_failure:
16520 : 0 : spin_unlock_bh(&rdev->beacon_registrations_lock);
16521 : 0 : nlmsg_free(msg);
16522 : : }
16523 : : EXPORT_SYMBOL(cfg80211_report_obss_beacon);
16524 : :
16525 : : #ifdef CONFIG_PM
16526 : : static int cfg80211_net_detect_results(struct sk_buff *msg,
16527 : : struct cfg80211_wowlan_wakeup *wakeup)
16528 : : {
16529 : : struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect;
16530 : : struct nlattr *nl_results, *nl_match, *nl_freqs;
16531 : : int i, j;
16532 : :
16533 : : nl_results = nla_nest_start_noflag(msg,
16534 : : NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS);
16535 : : if (!nl_results)
16536 : : return -EMSGSIZE;
16537 : :
16538 : : for (i = 0; i < nd->n_matches; i++) {
16539 : : struct cfg80211_wowlan_nd_match *match = nd->matches[i];
16540 : :
16541 : : nl_match = nla_nest_start_noflag(msg, i);
16542 : : if (!nl_match)
16543 : : break;
16544 : :
16545 : : /* The SSID attribute is optional in nl80211, but for
16546 : : * simplicity reasons it's always present in the
16547 : : * cfg80211 structure. If a driver can't pass the
16548 : : * SSID, that needs to be changed. A zero length SSID
16549 : : * is still a valid SSID (wildcard), so it cannot be
16550 : : * used for this purpose.
16551 : : */
16552 : : if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len,
16553 : : match->ssid.ssid)) {
16554 : : nla_nest_cancel(msg, nl_match);
16555 : : goto out;
16556 : : }
16557 : :
16558 : : if (match->n_channels) {
16559 : : nl_freqs = nla_nest_start_noflag(msg,
16560 : : NL80211_ATTR_SCAN_FREQUENCIES);
16561 : : if (!nl_freqs) {
16562 : : nla_nest_cancel(msg, nl_match);
16563 : : goto out;
16564 : : }
16565 : :
16566 : : for (j = 0; j < match->n_channels; j++) {
16567 : : if (nla_put_u32(msg, j, match->channels[j])) {
16568 : : nla_nest_cancel(msg, nl_freqs);
16569 : : nla_nest_cancel(msg, nl_match);
16570 : : goto out;
16571 : : }
16572 : : }
16573 : :
16574 : : nla_nest_end(msg, nl_freqs);
16575 : : }
16576 : :
16577 : : nla_nest_end(msg, nl_match);
16578 : : }
16579 : :
16580 : : out:
16581 : : nla_nest_end(msg, nl_results);
16582 : : return 0;
16583 : : }
16584 : :
16585 : 0 : void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
16586 : : struct cfg80211_wowlan_wakeup *wakeup,
16587 : : gfp_t gfp)
16588 : : {
16589 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
16590 : 0 : struct sk_buff *msg;
16591 : 0 : void *hdr;
16592 : 0 : int size = 200;
16593 : :
16594 : 0 : trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
16595 : :
16596 [ # # ]: 0 : if (wakeup)
16597 : 0 : size += wakeup->packet_present_len;
16598 : :
16599 : 0 : msg = nlmsg_new(size, gfp);
16600 [ # # ]: 0 : if (!msg)
16601 : : return;
16602 : :
16603 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN);
16604 [ # # ]: 0 : if (!hdr)
16605 : 0 : goto free_msg;
16606 : :
16607 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16608 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
16609 : : NL80211_ATTR_PAD))
16610 : 0 : goto free_msg;
16611 : :
16612 [ # # # # ]: 0 : if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
16613 : 0 : wdev->netdev->ifindex))
16614 : 0 : goto free_msg;
16615 : :
16616 [ # # ]: 0 : if (wakeup) {
16617 : 0 : struct nlattr *reasons;
16618 : :
16619 : 0 : reasons = nla_nest_start_noflag(msg,
16620 : : NL80211_ATTR_WOWLAN_TRIGGERS);
16621 [ # # ]: 0 : if (!reasons)
16622 : 0 : goto free_msg;
16623 : :
16624 [ # # # # ]: 0 : if (wakeup->disconnect &&
16625 : : nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
16626 : 0 : goto free_msg;
16627 [ # # # # ]: 0 : if (wakeup->magic_pkt &&
16628 : : nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT))
16629 : 0 : goto free_msg;
16630 [ # # # # ]: 0 : if (wakeup->gtk_rekey_failure &&
16631 : : nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE))
16632 : 0 : goto free_msg;
16633 [ # # # # ]: 0 : if (wakeup->eap_identity_req &&
16634 : : nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST))
16635 : 0 : goto free_msg;
16636 [ # # # # ]: 0 : if (wakeup->four_way_handshake &&
16637 : : nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE))
16638 : 0 : goto free_msg;
16639 [ # # # # ]: 0 : if (wakeup->rfkill_release &&
16640 : : nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))
16641 : 0 : goto free_msg;
16642 : :
16643 [ # # # # ]: 0 : if (wakeup->pattern_idx >= 0 &&
16644 : 0 : nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
16645 : : wakeup->pattern_idx))
16646 : 0 : goto free_msg;
16647 : :
16648 [ # # # # ]: 0 : if (wakeup->tcp_match &&
16649 : : nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
16650 : 0 : goto free_msg;
16651 : :
16652 [ # # # # ]: 0 : if (wakeup->tcp_connlost &&
16653 : : nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
16654 : 0 : goto free_msg;
16655 : :
16656 [ # # # # ]: 0 : if (wakeup->tcp_nomoretokens &&
16657 : : nla_put_flag(msg,
16658 : : NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
16659 : 0 : goto free_msg;
16660 : :
16661 [ # # ]: 0 : if (wakeup->packet) {
16662 : 0 : u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
16663 : 0 : u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN;
16664 : :
16665 [ # # ]: 0 : if (!wakeup->packet_80211) {
16666 : 0 : pkt_attr =
16667 : : NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023;
16668 : 0 : len_attr =
16669 : : NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN;
16670 : : }
16671 : :
16672 [ # # # # ]: 0 : if (wakeup->packet_len &&
16673 : 0 : nla_put_u32(msg, len_attr, wakeup->packet_len))
16674 : 0 : goto free_msg;
16675 : :
16676 [ # # ]: 0 : if (nla_put(msg, pkt_attr, wakeup->packet_present_len,
16677 : : wakeup->packet))
16678 : 0 : goto free_msg;
16679 : : }
16680 : :
16681 [ # # # # ]: 0 : if (wakeup->net_detect &&
16682 : 0 : cfg80211_net_detect_results(msg, wakeup))
16683 : 0 : goto free_msg;
16684 : :
16685 : 0 : nla_nest_end(msg, reasons);
16686 : : }
16687 : :
16688 : 0 : genlmsg_end(msg, hdr);
16689 : :
16690 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16691 : : NL80211_MCGRP_MLME, gfp);
16692 : 0 : return;
16693 : :
16694 : 0 : free_msg:
16695 : 0 : nlmsg_free(msg);
16696 : : }
16697 : : EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup);
16698 : : #endif
16699 : :
16700 : 0 : void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
16701 : : enum nl80211_tdls_operation oper,
16702 : : u16 reason_code, gfp_t gfp)
16703 : : {
16704 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
16705 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
16706 : 0 : struct sk_buff *msg;
16707 : 0 : void *hdr;
16708 : :
16709 : 0 : trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
16710 : : reason_code);
16711 : :
16712 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16713 [ # # ]: 0 : if (!msg)
16714 : : return;
16715 : :
16716 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
16717 [ # # ]: 0 : if (!hdr) {
16718 : 0 : nlmsg_free(msg);
16719 : 0 : return;
16720 : : }
16721 : :
16722 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16723 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
16724 [ # # ]: 0 : nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
16725 [ # # ]: 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
16726 [ # # ]: 0 : (reason_code > 0 &&
16727 : : nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
16728 : 0 : goto nla_put_failure;
16729 : :
16730 : 0 : genlmsg_end(msg, hdr);
16731 : :
16732 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16733 : : NL80211_MCGRP_MLME, gfp);
16734 : 0 : return;
16735 : :
16736 : : nla_put_failure:
16737 : 0 : nlmsg_free(msg);
16738 : : }
16739 : : EXPORT_SYMBOL(cfg80211_tdls_oper_request);
16740 : :
16741 : 33 : static int nl80211_netlink_notify(struct notifier_block * nb,
16742 : : unsigned long state,
16743 : : void *_notify)
16744 : : {
16745 : 33 : struct netlink_notify *notify = _notify;
16746 : 33 : struct cfg80211_registered_device *rdev;
16747 : 33 : struct wireless_dev *wdev;
16748 : 33 : struct cfg80211_beacon_registration *reg, *tmp;
16749 : :
16750 [ + - - + ]: 33 : if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
16751 : : return NOTIFY_DONE;
16752 : :
16753 : 0 : rcu_read_lock();
16754 : :
16755 [ # # ]: 0 : list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
16756 : 0 : struct cfg80211_sched_scan_request *sched_scan_req;
16757 : :
16758 [ # # ]: 0 : list_for_each_entry_rcu(sched_scan_req,
16759 : : &rdev->sched_scan_req_list,
16760 : : list) {
16761 [ # # ]: 0 : if (sched_scan_req->owner_nlportid == notify->portid) {
16762 : 0 : sched_scan_req->nl_owner_dead = true;
16763 : 0 : schedule_work(&rdev->sched_scan_stop_wk);
16764 : : }
16765 : : }
16766 : :
16767 [ # # ]: 0 : list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
16768 : 0 : cfg80211_mlme_unregister_socket(wdev, notify->portid);
16769 : :
16770 [ # # ]: 0 : if (wdev->owner_nlportid == notify->portid) {
16771 : 0 : wdev->nl_owner_dead = true;
16772 : 0 : schedule_work(&rdev->destroy_work);
16773 [ # # ]: 0 : } else if (wdev->conn_owner_nlportid == notify->portid) {
16774 : 0 : schedule_work(&wdev->disconnect_wk);
16775 : : }
16776 : :
16777 : 0 : cfg80211_release_pmsr(wdev, notify->portid);
16778 : : }
16779 : :
16780 : 0 : spin_lock_bh(&rdev->beacon_registrations_lock);
16781 [ # # ]: 0 : list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
16782 : : list) {
16783 [ # # ]: 0 : if (reg->nlportid == notify->portid) {
16784 : 0 : list_del(®->list);
16785 : 0 : kfree(reg);
16786 : 0 : break;
16787 : : }
16788 : : }
16789 : 0 : spin_unlock_bh(&rdev->beacon_registrations_lock);
16790 : : }
16791 : :
16792 : 0 : rcu_read_unlock();
16793 : :
16794 : : /*
16795 : : * It is possible that the user space process that is controlling the
16796 : : * indoor setting disappeared, so notify the regulatory core.
16797 : : */
16798 : 0 : regulatory_netlink_notify(notify->portid);
16799 : 0 : return NOTIFY_OK;
16800 : : }
16801 : :
16802 : : static struct notifier_block nl80211_netlink_notifier = {
16803 : : .notifier_call = nl80211_netlink_notify,
16804 : : };
16805 : :
16806 : 0 : void cfg80211_ft_event(struct net_device *netdev,
16807 : : struct cfg80211_ft_event_params *ft_event)
16808 : : {
16809 : 0 : struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
16810 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
16811 : 0 : struct sk_buff *msg;
16812 : 0 : void *hdr;
16813 : :
16814 : 0 : trace_cfg80211_ft_event(wiphy, netdev, ft_event);
16815 : :
16816 [ # # ]: 0 : if (!ft_event->target_ap)
16817 : : return;
16818 : :
16819 : 0 : msg = nlmsg_new(100 + ft_event->ies_len + ft_event->ric_ies_len,
16820 : : GFP_KERNEL);
16821 [ # # ]: 0 : if (!msg)
16822 : : return;
16823 : :
16824 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
16825 [ # # ]: 0 : if (!hdr)
16826 : 0 : goto out;
16827 : :
16828 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16829 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
16830 : 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
16831 : 0 : goto out;
16832 : :
16833 [ # # # # ]: 0 : if (ft_event->ies &&
16834 : 0 : nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
16835 : 0 : goto out;
16836 [ # # # # ]: 0 : if (ft_event->ric_ies &&
16837 : 0 : nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
16838 : : ft_event->ric_ies))
16839 : 0 : goto out;
16840 : :
16841 : 0 : genlmsg_end(msg, hdr);
16842 : :
16843 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16844 : : NL80211_MCGRP_MLME, GFP_KERNEL);
16845 : 0 : return;
16846 : 0 : out:
16847 : 0 : nlmsg_free(msg);
16848 : : }
16849 : : EXPORT_SYMBOL(cfg80211_ft_event);
16850 : :
16851 : 0 : void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
16852 : : {
16853 : 0 : struct cfg80211_registered_device *rdev;
16854 : 0 : struct sk_buff *msg;
16855 : 0 : void *hdr;
16856 : 0 : u32 nlportid;
16857 : :
16858 [ # # ]: 0 : rdev = wiphy_to_rdev(wdev->wiphy);
16859 [ # # ]: 0 : if (!rdev->crit_proto_nlportid)
16860 : : return;
16861 : :
16862 : 0 : nlportid = rdev->crit_proto_nlportid;
16863 : 0 : rdev->crit_proto_nlportid = 0;
16864 : :
16865 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16866 [ # # ]: 0 : if (!msg)
16867 : : return;
16868 : :
16869 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
16870 [ # # ]: 0 : if (!hdr)
16871 : 0 : goto nla_put_failure;
16872 : :
16873 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16874 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
16875 : : NL80211_ATTR_PAD))
16876 : 0 : goto nla_put_failure;
16877 : :
16878 : 0 : genlmsg_end(msg, hdr);
16879 : :
16880 : 0 : genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
16881 : : return;
16882 : :
16883 : 0 : nla_put_failure:
16884 : 0 : nlmsg_free(msg);
16885 : : }
16886 : : EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
16887 : :
16888 : 0 : void nl80211_send_ap_stopped(struct wireless_dev *wdev)
16889 : : {
16890 : 0 : struct wiphy *wiphy = wdev->wiphy;
16891 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
16892 : 0 : struct sk_buff *msg;
16893 : 0 : void *hdr;
16894 : :
16895 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
16896 [ # # ]: 0 : if (!msg)
16897 : : return;
16898 : :
16899 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
16900 [ # # ]: 0 : if (!hdr)
16901 : 0 : goto out;
16902 : :
16903 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16904 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
16905 [ # # ]: 0 : nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
16906 : : NL80211_ATTR_PAD))
16907 : 0 : goto out;
16908 : :
16909 : 0 : genlmsg_end(msg, hdr);
16910 : :
16911 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
16912 : : NL80211_MCGRP_MLME, GFP_KERNEL);
16913 : 0 : return;
16914 : 0 : out:
16915 : 0 : nlmsg_free(msg);
16916 : : }
16917 : :
16918 : 0 : int cfg80211_external_auth_request(struct net_device *dev,
16919 : : struct cfg80211_external_auth_params *params,
16920 : : gfp_t gfp)
16921 : : {
16922 : 0 : struct wireless_dev *wdev = dev->ieee80211_ptr;
16923 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
16924 : 0 : struct sk_buff *msg;
16925 : 0 : void *hdr;
16926 : :
16927 [ # # ]: 0 : if (!wdev->conn_owner_nlportid)
16928 : : return -EINVAL;
16929 : :
16930 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16931 [ # # ]: 0 : if (!msg)
16932 : : return -ENOMEM;
16933 : :
16934 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_EXTERNAL_AUTH);
16935 [ # # ]: 0 : if (!hdr)
16936 : 0 : goto nla_put_failure;
16937 : :
16938 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16939 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
16940 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) ||
16941 : : nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION,
16942 [ # # ]: 0 : params->action) ||
16943 [ # # ]: 0 : nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) ||
16944 : 0 : nla_put(msg, NL80211_ATTR_SSID, params->ssid.ssid_len,
16945 : 0 : params->ssid.ssid))
16946 : 0 : goto nla_put_failure;
16947 : :
16948 : 0 : genlmsg_end(msg, hdr);
16949 : 0 : genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
16950 : : wdev->conn_owner_nlportid);
16951 : 0 : return 0;
16952 : :
16953 : 0 : nla_put_failure:
16954 : 0 : nlmsg_free(msg);
16955 : 0 : return -ENOBUFS;
16956 : : }
16957 : : EXPORT_SYMBOL(cfg80211_external_auth_request);
16958 : :
16959 : 0 : void cfg80211_update_owe_info_event(struct net_device *netdev,
16960 : : struct cfg80211_update_owe_info *owe_info,
16961 : : gfp_t gfp)
16962 : : {
16963 : 0 : struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
16964 [ # # ]: 0 : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
16965 : 0 : struct sk_buff *msg;
16966 : 0 : void *hdr;
16967 : :
16968 : 0 : trace_cfg80211_update_owe_info_event(wiphy, netdev, owe_info);
16969 : :
16970 : 0 : msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
16971 [ # # ]: 0 : if (!msg)
16972 : : return;
16973 : :
16974 : 0 : hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UPDATE_OWE_INFO);
16975 [ # # ]: 0 : if (!hdr)
16976 : 0 : goto nla_put_failure;
16977 : :
16978 [ # # # # ]: 0 : if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
16979 [ # # ]: 0 : nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
16980 : 0 : nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, owe_info->peer))
16981 : 0 : goto nla_put_failure;
16982 : :
16983 [ # # # # ]: 0 : if (!owe_info->ie_len ||
16984 : 0 : nla_put(msg, NL80211_ATTR_IE, owe_info->ie_len, owe_info->ie))
16985 : 0 : goto nla_put_failure;
16986 : :
16987 : 0 : genlmsg_end(msg, hdr);
16988 : :
16989 : 0 : genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
16990 : : NL80211_MCGRP_MLME, gfp);
16991 : 0 : return;
16992 : :
16993 : 0 : nla_put_failure:
16994 [ # # ]: 0 : genlmsg_cancel(msg, hdr);
16995 : 0 : nlmsg_free(msg);
16996 : : }
16997 : : EXPORT_SYMBOL(cfg80211_update_owe_info_event);
16998 : :
16999 : : /* initialisation/exit functions */
17000 : :
17001 : 3 : int __init nl80211_init(void)
17002 : : {
17003 : 3 : int err;
17004 : :
17005 : 3 : err = genl_register_family(&nl80211_fam);
17006 [ + - ]: 3 : if (err)
17007 : : return err;
17008 : :
17009 : 3 : err = netlink_register_notifier(&nl80211_netlink_notifier);
17010 [ - + ]: 3 : if (err)
17011 : 0 : goto err_out;
17012 : :
17013 : : return 0;
17014 : : err_out:
17015 : 0 : genl_unregister_family(&nl80211_fam);
17016 : 0 : return err;
17017 : : }
17018 : :
17019 : 0 : void nl80211_exit(void)
17020 : : {
17021 : 0 : netlink_unregister_notifier(&nl80211_netlink_notifier);
17022 : 0 : genl_unregister_family(&nl80211_fam);
17023 : 0 : }
|