blob: 6b942a68d1c8e5a54232d722517b150331a81cb3 [file] [log] [blame]
Johannes Berg55682962007-09-20 13:09:35 -04001/*
2 * This is the new netlink-based wireless configuration interface.
3 *
Jouni Malinen026331c2010-02-15 12:53:10 +02004 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
Johannes Berg2740f0c2014-09-03 15:24:58 +03005 * Copyright 2013-2014 Intel Mobile Communications GmbH
Johannes Berg66cd7942017-02-07 22:40:44 +02006 * Copyright 2015-2017 Intel Deutschland GmbH
Haim Dreyfuss50f32712018-04-20 13:49:26 +03007 * Copyright (C) 2018 Intel Corporation
Johannes Berg55682962007-09-20 13:09:35 -04008 */
9
10#include <linux/if.h>
11#include <linux/module.h>
12#include <linux/err.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090013#include <linux/slab.h>
Johannes Berg55682962007-09-20 13:09:35 -040014#include <linux/list.h>
15#include <linux/if_ether.h>
16#include <linux/ieee80211.h>
17#include <linux/nl80211.h>
18#include <linux/rtnetlink.h>
19#include <linux/netlink.h>
Dan Williams259d8c12018-01-29 17:03:15 -080020#include <linux/nospec.h>
Johannes Berg2a519312009-02-10 21:25:55 +010021#include <linux/etherdevice.h>
Johannes Berg463d0182009-07-14 00:33:35 +020022#include <net/net_namespace.h>
Johannes Berg55682962007-09-20 13:09:35 -040023#include <net/genetlink.h>
24#include <net/cfg80211.h>
Johannes Berg463d0182009-07-14 00:33:35 +020025#include <net/sock.h>
Johannes Berg2a0e0472013-01-23 22:57:40 +010026#include <net/inet_connection_sock.h>
Johannes Berg55682962007-09-20 13:09:35 -040027#include "core.h"
28#include "nl80211.h"
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070029#include "reg.h"
Hila Gonene35e4d22012-06-27 17:19:42 +030030#include "rdev-ops.h"
Johannes Berg55682962007-09-20 13:09:35 -040031
Jouni Malinen5fb628e2011-08-10 23:54:35 +030032static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
33 struct genl_info *info,
34 struct cfg80211_crypto_settings *settings,
35 int cipher_limit);
36
Johannes Berg55682962007-09-20 13:09:35 -040037/* the netlink family */
Johannes Berg489111e2016-10-24 14:40:03 +020038static struct genl_family nl80211_fam;
Johannes Berg55682962007-09-20 13:09:35 -040039
Johannes Berg2a94fe42013-11-19 15:19:39 +010040/* multicast groups */
41enum nl80211_multicast_groups {
42 NL80211_MCGRP_CONFIG,
43 NL80211_MCGRP_SCAN,
44 NL80211_MCGRP_REGULATORY,
45 NL80211_MCGRP_MLME,
Johannes Berg567ffc32013-12-18 14:43:31 +010046 NL80211_MCGRP_VENDOR,
Ayala Beker50bcd312016-09-20 17:31:17 +030047 NL80211_MCGRP_NAN,
Johannes Berg2a94fe42013-11-19 15:19:39 +010048 NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
49};
50
51static const struct genl_multicast_group nl80211_mcgrps[] = {
Johannes Berg71b836e2014-12-23 17:17:38 +010052 [NL80211_MCGRP_CONFIG] = { .name = NL80211_MULTICAST_GROUP_CONFIG },
53 [NL80211_MCGRP_SCAN] = { .name = NL80211_MULTICAST_GROUP_SCAN },
54 [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG },
55 [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME },
56 [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR },
Ayala Beker50bcd312016-09-20 17:31:17 +030057 [NL80211_MCGRP_NAN] = { .name = NL80211_MULTICAST_GROUP_NAN },
Johannes Berg2a94fe42013-11-19 15:19:39 +010058#ifdef CONFIG_NL80211_TESTMODE
Johannes Berg71b836e2014-12-23 17:17:38 +010059 [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }
Johannes Berg2a94fe42013-11-19 15:19:39 +010060#endif
61};
62
Johannes Berg89a54e42012-06-15 14:33:17 +020063/* returns ERR_PTR values */
64static struct wireless_dev *
65__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
Johannes Berg55682962007-09-20 13:09:35 -040066{
Johannes Berg89a54e42012-06-15 14:33:17 +020067 struct cfg80211_registered_device *rdev;
68 struct wireless_dev *result = NULL;
69 bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
70 bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
71 u64 wdev_id;
72 int wiphy_idx = -1;
73 int ifidx = -1;
Johannes Berg55682962007-09-20 13:09:35 -040074
Johannes Berg5fe231e2013-05-08 21:45:15 +020075 ASSERT_RTNL();
Johannes Berg55682962007-09-20 13:09:35 -040076
Johannes Berg89a54e42012-06-15 14:33:17 +020077 if (!have_ifidx && !have_wdev_id)
78 return ERR_PTR(-EINVAL);
Johannes Berg55682962007-09-20 13:09:35 -040079
Johannes Berg89a54e42012-06-15 14:33:17 +020080 if (have_ifidx)
81 ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
82 if (have_wdev_id) {
83 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
84 wiphy_idx = wdev_id >> 32;
Johannes Berg55682962007-09-20 13:09:35 -040085 }
86
Johannes Berg89a54e42012-06-15 14:33:17 +020087 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
88 struct wireless_dev *wdev;
89
90 if (wiphy_net(&rdev->wiphy) != netns)
91 continue;
92
93 if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
94 continue;
95
Johannes Berg53873f12016-05-03 16:52:04 +030096 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Berg89a54e42012-06-15 14:33:17 +020097 if (have_ifidx && wdev->netdev &&
98 wdev->netdev->ifindex == ifidx) {
99 result = wdev;
100 break;
101 }
102 if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
103 result = wdev;
104 break;
105 }
106 }
Johannes Berg89a54e42012-06-15 14:33:17 +0200107
108 if (result)
109 break;
110 }
111
112 if (result)
113 return result;
114 return ERR_PTR(-ENODEV);
Johannes Berg55682962007-09-20 13:09:35 -0400115}
116
Johannes Berga9455402012-06-15 13:32:49 +0200117static struct cfg80211_registered_device *
Johannes Berg878d9ec2012-06-15 14:18:32 +0200118__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
Johannes Berga9455402012-06-15 13:32:49 +0200119{
Johannes Berg7fee4772012-06-15 14:09:58 +0200120 struct cfg80211_registered_device *rdev = NULL, *tmp;
121 struct net_device *netdev;
Johannes Berga9455402012-06-15 13:32:49 +0200122
Johannes Berg5fe231e2013-05-08 21:45:15 +0200123 ASSERT_RTNL();
Johannes Berga9455402012-06-15 13:32:49 +0200124
Johannes Berg878d9ec2012-06-15 14:18:32 +0200125 if (!attrs[NL80211_ATTR_WIPHY] &&
Johannes Berg89a54e42012-06-15 14:33:17 +0200126 !attrs[NL80211_ATTR_IFINDEX] &&
127 !attrs[NL80211_ATTR_WDEV])
Johannes Berg7fee4772012-06-15 14:09:58 +0200128 return ERR_PTR(-EINVAL);
129
Johannes Berg878d9ec2012-06-15 14:18:32 +0200130 if (attrs[NL80211_ATTR_WIPHY])
Johannes Berg7fee4772012-06-15 14:09:58 +0200131 rdev = cfg80211_rdev_by_wiphy_idx(
Johannes Berg878d9ec2012-06-15 14:18:32 +0200132 nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
Johannes Berga9455402012-06-15 13:32:49 +0200133
Johannes Berg89a54e42012-06-15 14:33:17 +0200134 if (attrs[NL80211_ATTR_WDEV]) {
135 u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
136 struct wireless_dev *wdev;
137 bool found = false;
138
139 tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
140 if (tmp) {
141 /* make sure wdev exists */
Johannes Berg53873f12016-05-03 16:52:04 +0300142 list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
Johannes Berg89a54e42012-06-15 14:33:17 +0200143 if (wdev->identifier != (u32)wdev_id)
144 continue;
145 found = true;
146 break;
147 }
Johannes Berg89a54e42012-06-15 14:33:17 +0200148
149 if (!found)
150 tmp = NULL;
151
152 if (rdev && tmp != rdev)
153 return ERR_PTR(-EINVAL);
154 rdev = tmp;
155 }
156 }
157
Johannes Berg878d9ec2012-06-15 14:18:32 +0200158 if (attrs[NL80211_ATTR_IFINDEX]) {
159 int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -0700160
Ying Xue7f2b8562014-01-15 10:23:45 +0800161 netdev = __dev_get_by_index(netns, ifindex);
Johannes Berg7fee4772012-06-15 14:09:58 +0200162 if (netdev) {
163 if (netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800164 tmp = wiphy_to_rdev(
165 netdev->ieee80211_ptr->wiphy);
Johannes Berg7fee4772012-06-15 14:09:58 +0200166 else
167 tmp = NULL;
168
Johannes Berg7fee4772012-06-15 14:09:58 +0200169 /* not wireless device -- return error */
170 if (!tmp)
171 return ERR_PTR(-EINVAL);
172
173 /* mismatch -- return error */
174 if (rdev && tmp != rdev)
175 return ERR_PTR(-EINVAL);
176
177 rdev = tmp;
Johannes Berga9455402012-06-15 13:32:49 +0200178 }
Johannes Berga9455402012-06-15 13:32:49 +0200179 }
180
Johannes Berg4f7eff12012-06-15 14:14:22 +0200181 if (!rdev)
182 return ERR_PTR(-ENODEV);
Johannes Berga9455402012-06-15 13:32:49 +0200183
Johannes Berg4f7eff12012-06-15 14:14:22 +0200184 if (netns != wiphy_net(&rdev->wiphy))
185 return ERR_PTR(-ENODEV);
186
187 return rdev;
Johannes Berga9455402012-06-15 13:32:49 +0200188}
189
190/*
191 * This function returns a pointer to the driver
192 * that the genl_info item that is passed refers to.
Johannes Berga9455402012-06-15 13:32:49 +0200193 *
194 * The result of this can be a PTR_ERR and hence must
195 * be checked with IS_ERR() for errors.
196 */
197static struct cfg80211_registered_device *
Johannes Berg4f7eff12012-06-15 14:14:22 +0200198cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
Johannes Berga9455402012-06-15 13:32:49 +0200199{
Johannes Berg5fe231e2013-05-08 21:45:15 +0200200 return __cfg80211_rdev_from_attrs(netns, info->attrs);
Johannes Berga9455402012-06-15 13:32:49 +0200201}
202
Johannes Berg55682962007-09-20 13:09:35 -0400203/* policy for the attributes */
Luciano Coelho8cd4d452014-09-17 11:55:28 +0300204static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
Johannes Berg55682962007-09-20 13:09:35 -0400205 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
206 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
David S. Miller079e24e2009-05-26 21:15:00 -0700207 .len = 20-1 },
Jouni Malinen31888482008-10-30 16:59:24 +0200208 [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100209
Jouni Malinen72bdcf32008-11-26 16:15:24 +0200210 [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
Sujith094d05d2008-12-12 11:57:43 +0530211 [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100212 [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
213 [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
214 [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
215
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +0200216 [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 },
217 [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
218 [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
219 [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
Lukáš Turek81077e82009-12-21 22:50:47 +0100220 [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +0200221 [NL80211_ATTR_WIPHY_DYN_ACK] = { .type = NLA_FLAG },
Johannes Berg55682962007-09-20 13:09:35 -0400222
223 [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
224 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
225 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
Johannes Berg41ade002007-12-19 02:03:29 +0100226
Eliad Pellere007b852011-11-24 18:13:56 +0200227 [NL80211_ATTR_MAC] = { .len = ETH_ALEN },
228 [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN },
Johannes Berg41ade002007-12-19 02:03:29 +0100229
Johannes Bergb9454e82009-07-08 13:29:08 +0200230 [NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
Johannes Berg41ade002007-12-19 02:03:29 +0100231 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
232 .len = WLAN_MAX_KEY_LEN },
233 [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
234 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
235 [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
Jouni Malinen81962262011-11-02 23:36:31 +0200236 [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Berge31b8212010-10-05 19:39:30 +0200237 [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
Johannes Berged1b6cc2007-12-19 02:03:32 +0100238
239 [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
240 [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
241 [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
242 .len = IEEE80211_MAX_DATA_LEN },
243 [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
244 .len = IEEE80211_MAX_DATA_LEN },
Johannes Berg5727ef12007-12-19 02:03:34 +0100245 [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
246 [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
247 [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
248 [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
249 .len = NL80211_MAX_SUPP_RATES },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100250 [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 },
Johannes Berg5727ef12007-12-19 02:03:34 +0100251 [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
Johannes Berg0a9542e2008-10-15 11:54:04 +0200252 [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100253 [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +0800254 .len = IEEE80211_MAX_MESH_ID_LEN },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100255 [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +0300256
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700257 [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
258 [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
259
Jouni Malinen9f1ba902008-08-07 20:07:01 +0300260 [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
261 [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
262 [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
Jouni Malinen90c97a02008-10-30 16:59:22 +0200263 [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY,
264 .len = NL80211_MAX_SUPP_RATES },
Helmut Schaa50b12f52010-11-19 12:40:25 +0100265 [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 },
Jouni Malinen36aedc92008-08-25 11:58:58 +0300266
Javier Cardona24bdd9f2010-12-16 17:37:48 -0800267 [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
Javier Cardona15d5dda2011-04-07 15:08:28 -0700268 [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -0700269
Johannes Berg6c739412011-11-03 09:27:01 +0100270 [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +0200271
272 [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
273 [NL80211_ATTR_IE] = { .type = NLA_BINARY,
274 .len = IEEE80211_MAX_DATA_LEN },
Johannes Berg2a519312009-02-10 21:25:55 +0100275 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
276 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
Jouni Malinen636a5d32009-03-19 13:39:22 +0200277
278 [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
279 .len = IEEE80211_MAX_SSID_LEN },
280 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
281 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
Johannes Berg04a773a2009-04-19 21:24:32 +0200282 [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
Jouni Malinen1965c852009-04-22 21:38:25 +0300283 [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
Jouni Malinendc6382ce2009-05-06 22:09:37 +0300284 [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 },
Johannes Bergeccb8e82009-05-11 21:57:56 +0300285 [NL80211_ATTR_STA_FLAGS2] = {
286 .len = sizeof(struct nl80211_sta_flag_update),
287 },
Jouni Malinen3f77316c2009-05-11 21:57:57 +0300288 [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
Johannes Bergc0692b82010-08-27 14:26:53 +0300289 [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
290 [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
Denis Kenzior64bf3d42018-03-26 12:52:43 -0500291 [NL80211_ATTR_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG },
Samuel Ortizb23aa672009-07-01 21:26:54 +0200292 [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
293 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
294 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
Johannes Berg463d0182009-07-14 00:33:35 +0200295 [NL80211_ATTR_PID] = { .type = NLA_U32 },
Felix Fietkau8b787642009-11-10 18:53:10 +0100296 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
Srinivas Dasari9361df12017-07-07 01:43:39 +0300297 [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN },
Jouni Malinen9588bbd2009-12-23 13:15:41 +0100298 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
299 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +0200300 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
Jouni Malinen026331c2010-02-15 12:53:10 +0200301 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
302 .len = IEEE80211_MAX_DATA_LEN },
303 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
Kalle Valoffb9eb32010-02-17 17:58:10 +0200304 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +0200305 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
Jouni Malinend5cdfac2010-04-04 09:37:19 +0300306 [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +0200307 [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +0300308 [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
309 [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
Johannes Berg2e161f72010-08-12 15:38:38 +0200310 [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
Bruno Randolfafe0cbf2010-11-10 12:50:50 +0900311 [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 },
312 [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
Felix Fietkau885a46d2010-11-11 15:07:22 +0100313 [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
Johannes Bergf7ca38d2010-11-25 10:02:29 +0100314 [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100315 [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200316 [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
Javier Cardona9c3990a2011-05-03 16:57:11 -0700317 [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
Luciano Coelhobbe6ad62011-05-11 17:09:37 +0300318 [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
Johannes Berge5497d72011-07-05 16:35:40 +0200319 [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
Johannes Berg34850ab2011-07-18 18:08:35 +0200320 [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
Jouni Malinen32e9de82011-08-10 23:53:31 +0300321 [NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
Jouni Malinen9946ecf2011-08-10 23:55:56 +0300322 [NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
323 .len = IEEE80211_MAX_DATA_LEN },
324 [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
325 .len = IEEE80211_MAX_DATA_LEN },
Vivek Natarajanf4b34b52011-08-29 14:23:03 +0530326 [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300327 [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +0530328 [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
Arik Nemtsov109086c2011-09-28 14:12:50 +0300329 [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
330 [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
331 [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
332 [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
333 [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
Arik Nemtsov31fa97c2014-06-11 17:18:21 +0300334 [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG },
Johannes Berge247bd902011-11-04 11:18:21 +0100335 [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
Arik Nemtsov00f740e2011-11-10 11:28:56 +0200336 [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
337 .len = IEEE80211_MAX_DATA_LEN },
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -0700338 [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
Ben Greear7e7c8922011-11-18 11:31:59 -0800339 [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
340 [NL80211_ATTR_HT_CAPABILITY_MASK] = {
341 .len = NL80211_HT_CAPABILITY_LEN
342 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +0100343 [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +0530344 [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
Bala Shanmugam4486ea92012-03-07 17:27:12 +0530345 [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
Johannes Berg89a54e42012-06-15 14:33:17 +0200346 [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -0700347 [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
Jouni Malinen11b6b5a2016-10-27 00:41:58 +0300348 [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +0000349 [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
Sam Lefflered4737712012-10-11 21:03:31 -0700350 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
Johannes Berg53cabad2012-11-14 15:17:28 +0100351 [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
352 [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
Srinivas Dasari8feb69c2017-07-07 01:43:41 +0300353 [NL80211_ATTR_LOCAL_MESH_POWER_MODE] = {. type = NLA_U32 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +0530354 [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
355 [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
Jouni Malinen9d62a982013-02-14 21:10:13 +0200356 [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
357 [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
Johannes Berg3713b4e2013-02-14 16:19:38 +0100358 [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
Johannes Bergee2aca32013-02-21 17:36:01 +0100359 [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG },
360 [NL80211_ATTR_VHT_CAPABILITY_MASK] = {
361 .len = NL80211_VHT_CAPABILITY_LEN,
362 },
Jouni Malinen355199e2013-02-27 17:14:27 +0200363 [NL80211_ATTR_MDID] = { .type = NLA_U16 },
364 [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
365 .len = IEEE80211_MAX_DATA_LEN },
Jouni Malinen5e4b6f52013-05-16 20:11:08 +0300366 [NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +0200367 [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
368 [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
369 [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +0300370 [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_BINARY },
371 [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_BINARY },
Sunil Duttc01fc9a2013-10-09 20:45:21 +0530372 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
373 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
Simon Wunderlich5336fa82013-10-07 18:41:05 +0200374 [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +0100375 [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
Johannes Bergad7e7182013-11-13 13:37:47 +0100376 [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
377 [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
378 [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -0800379 [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
380 .len = IEEE80211_QOS_MAP_LEN_MAX },
Jouni Malinen1df4a512014-01-15 00:00:47 +0200381 [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
382 [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +0530383 [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
Jukka Rissanen18e5ca62014-11-13 17:25:14 +0200384 [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +0300385 [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
Assaf Kraussbab5ab72014-09-03 15:25:01 +0300386 [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
Johannes Berg960d01a2014-09-09 22:55:35 +0300387 [NL80211_ATTR_TSID] = { .type = NLA_U8 },
388 [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },
389 [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
Eliad Peller18998c32014-09-10 14:07:34 +0300390 [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
Johannes Bergad2b26a2014-06-12 21:39:05 +0200391 [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN },
Arik Nemtsov1bdd7162014-12-15 19:26:01 +0200392 [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
Vadim Kochan4b681c82015-01-12 16:34:05 +0200393 [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
Luciano Coelho9c748932015-01-16 16:04:09 +0200394 [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
Ilan peer05050752015-03-04 00:32:06 -0500395 [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
Lior David34d50512016-01-28 10:58:25 +0200396 [NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
Arend van Spriel38de03d2016-03-02 20:37:18 +0100397 [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
Ayala Beker17b94242016-03-17 15:41:38 +0200398 [NL80211_ATTR_STA_SUPPORT_P2P_PS] = { .type = NLA_U8 },
Aviya Erenfeldc6e6a0c2016-07-05 15:23:08 +0300399 [NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
400 .len = VHT_MUMIMO_GROUPS_DATA_LEN
401 },
402 [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN },
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300403 [NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
Luca Coelho85859892017-02-08 15:00:34 +0200404 [NL80211_ATTR_BANDS] = { .type = NLA_U32 },
Ayala Bekera442b762016-09-20 17:31:15 +0300405 [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
Jouni Malinen348bd452016-10-27 00:42:03 +0300406 [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
407 .len = FILS_MAX_KEK_LEN },
408 [NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
Michael Braunce0ce132016-10-10 19:12:22 +0200409 [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
Vamsi Krishna2fa436b2016-12-02 23:59:08 +0200410 [NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
vamsi krishnabf95ecd2017-01-13 01:12:20 +0200411 [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
412 [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
413 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
414 },
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +0200415 [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +0300416 [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
417 .len = FILS_ERP_MAX_USERNAME_LEN },
418 [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
419 .len = FILS_ERP_MAX_REALM_LEN },
420 [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
421 [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
422 .len = FILS_ERP_MAX_RRK_LEN },
423 [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
424 [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
Arend Van Sprielca986ad2017-04-21 13:05:00 +0100425 [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
Srinivas Dasari40cbfa92018-01-25 17:13:38 +0200426 [NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
Johannes Berg55682962007-09-20 13:09:35 -0400427};
428
Johannes Berge31b8212010-10-05 19:39:30 +0200429/* policy for the key attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000430static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
Johannes Bergfffd0932009-07-08 14:22:54 +0200431 [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
Johannes Bergb9454e82009-07-08 13:29:08 +0200432 [NL80211_KEY_IDX] = { .type = NLA_U8 },
433 [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
Jouni Malinen81962262011-11-02 23:36:31 +0200434 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Bergb9454e82009-07-08 13:29:08 +0200435 [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
436 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
Johannes Berge31b8212010-10-05 19:39:30 +0200437 [NL80211_KEY_TYPE] = { .type = NLA_U32 },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100438 [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
439};
440
441/* policy for the key default flags */
442static const struct nla_policy
443nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
444 [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
445 [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
Johannes Bergb9454e82009-07-08 13:29:08 +0200446};
447
Johannes Bergf83ace32016-10-17 08:04:07 +0200448#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +0200449/* policy for WoWLAN attributes */
450static const struct nla_policy
451nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
452 [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
453 [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
454 [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
455 [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
Johannes Berg77dbbb12011-07-13 10:48:55 +0200456 [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG },
457 [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG },
458 [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG },
459 [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100460 [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED },
Luciano Coelho8cd4d452014-09-17 11:55:28 +0300461 [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100462};
463
464static const struct nla_policy
465nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
466 [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
467 [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
468 [NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN },
469 [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
470 [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
471 [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 },
472 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
473 .len = sizeof(struct nl80211_wowlan_tcp_data_seq)
474 },
475 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = {
476 .len = sizeof(struct nl80211_wowlan_tcp_data_token)
477 },
478 [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
479 [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 },
480 [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200481};
Johannes Bergf83ace32016-10-17 08:04:07 +0200482#endif /* CONFIG_PM */
Johannes Bergff1b6e62011-05-04 15:37:28 +0200483
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -0700484/* policy for coalesce rule attributes */
485static const struct nla_policy
486nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
487 [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
488 [NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 },
489 [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
490};
491
Johannes Berge5497d72011-07-05 16:35:40 +0200492/* policy for GTK rekey offload attributes */
493static const struct nla_policy
494nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
495 [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN },
496 [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN },
497 [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
498};
499
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300500static const struct nla_policy
501nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
Johannes Berg4a4ab0d2012-06-13 11:17:11 +0200502 [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300503 .len = IEEE80211_MAX_SSID_LEN },
Arend Van Spriel3007e352017-04-21 13:05:01 +0100504 [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = { .len = ETH_ALEN },
Thomas Pedersen88e920b2012-06-21 11:09:54 -0700505 [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300506};
507
Avraham Stern3b06d272015-10-12 09:51:34 +0300508static const struct nla_policy
509nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
510 [NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
511 [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
512};
513
Arend van Spriel38de03d2016-03-02 20:37:18 +0100514static const struct nla_policy
515nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
516 [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
517 [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
518 [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
519 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
520 },
521};
522
Ayala Bekera442b762016-09-20 17:31:15 +0300523/* policy for NAN function attributes */
524static const struct nla_policy
525nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
526 [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
Srinivas Dasari0a278442017-07-07 01:43:40 +0300527 [NL80211_NAN_FUNC_SERVICE_ID] = {
Ayala Bekera442b762016-09-20 17:31:15 +0300528 .len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
529 [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
530 [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
531 [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
532 [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
533 [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
534 [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { .len = ETH_ALEN },
535 [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
536 [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
537 [NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
538 .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN },
539 [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
540 [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
541 [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
542 [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8 },
543 [NL80211_NAN_FUNC_TERM_REASON] = { .type = NLA_U8 },
544};
545
546/* policy for Service Response Filter attributes */
547static const struct nla_policy
548nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
549 [NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG },
550 [NL80211_NAN_SRF_BF] = { .type = NLA_BINARY,
551 .len = NL80211_NAN_FUNC_SRF_MAX_LEN },
552 [NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 },
553 [NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED },
554};
555
Peng Xuad670232017-10-03 23:21:51 +0300556/* policy for packet pattern attributes */
557static const struct nla_policy
558nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
559 [NL80211_PKTPAT_MASK] = { .type = NLA_BINARY, },
560 [NL80211_PKTPAT_PATTERN] = { .type = NLA_BINARY, },
561 [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 },
562};
563
Johannes Berg97990a02013-04-19 01:02:55 +0200564static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
565 struct netlink_callback *cb,
566 struct cfg80211_registered_device **rdev,
567 struct wireless_dev **wdev)
Holger Schuriga0438972009-11-11 11:30:02 +0100568{
Johannes Berg67748892010-10-04 21:14:06 +0200569 int err;
570
Johannes Berg97990a02013-04-19 01:02:55 +0200571 if (!cb->args[0]) {
572 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergc90c39d2016-10-24 14:40:01 +0200573 genl_family_attrbuf(&nl80211_fam),
Johannes Bergfceb6432017-04-12 14:34:07 +0200574 nl80211_fam.maxattr, nl80211_policy, NULL);
Johannes Berg97990a02013-04-19 01:02:55 +0200575 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +0100576 return err;
Johannes Berg97990a02013-04-19 01:02:55 +0200577
Johannes Bergc90c39d2016-10-24 14:40:01 +0200578 *wdev = __cfg80211_wdev_from_attrs(
579 sock_net(skb->sk),
580 genl_family_attrbuf(&nl80211_fam));
Johannes Bergea90e0d2017-03-15 14:26:04 +0100581 if (IS_ERR(*wdev))
582 return PTR_ERR(*wdev);
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800583 *rdev = wiphy_to_rdev((*wdev)->wiphy);
Johannes Bergc319d502013-07-30 22:34:28 +0200584 /* 0 is the first index - add 1 to parse only once */
585 cb->args[0] = (*rdev)->wiphy_idx + 1;
Johannes Berg97990a02013-04-19 01:02:55 +0200586 cb->args[1] = (*wdev)->identifier;
587 } else {
Johannes Bergc319d502013-07-30 22:34:28 +0200588 /* subtract the 1 again here */
589 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
Johannes Berg97990a02013-04-19 01:02:55 +0200590 struct wireless_dev *tmp;
591
Johannes Bergea90e0d2017-03-15 14:26:04 +0100592 if (!wiphy)
593 return -ENODEV;
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800594 *rdev = wiphy_to_rdev(wiphy);
Johannes Berg97990a02013-04-19 01:02:55 +0200595 *wdev = NULL;
596
Johannes Berg53873f12016-05-03 16:52:04 +0300597 list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
Johannes Berg97990a02013-04-19 01:02:55 +0200598 if (tmp->identifier == cb->args[1]) {
599 *wdev = tmp;
600 break;
601 }
602 }
Johannes Berg97990a02013-04-19 01:02:55 +0200603
Johannes Bergea90e0d2017-03-15 14:26:04 +0100604 if (!*wdev)
605 return -ENODEV;
Johannes Berg67748892010-10-04 21:14:06 +0200606 }
607
Johannes Berg67748892010-10-04 21:14:06 +0200608 return 0;
Johannes Berg67748892010-10-04 21:14:06 +0200609}
610
Johannes Bergf4a11bb2009-03-27 12:40:28 +0100611/* IE validation */
612static bool is_valid_ie_attr(const struct nlattr *attr)
613{
614 const u8 *pos;
615 int len;
616
617 if (!attr)
618 return true;
619
620 pos = nla_data(attr);
621 len = nla_len(attr);
622
623 while (len) {
624 u8 elemlen;
625
626 if (len < 2)
627 return false;
628 len -= 2;
629
630 elemlen = pos[1];
631 if (elemlen > len)
632 return false;
633
634 len -= elemlen;
635 pos += 2 + elemlen;
636 }
637
638 return true;
639}
640
Johannes Berg55682962007-09-20 13:09:35 -0400641/* message building helper */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000642static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
Johannes Berg55682962007-09-20 13:09:35 -0400643 int flags, u8 cmd)
644{
645 /* since there is no private header just add the generic one */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000646 return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -0400647}
648
Haim Dreyfuss50f32712018-04-20 13:49:26 +0300649static int nl80211_msg_put_wmm_rules(struct sk_buff *msg,
650 const struct ieee80211_reg_rule *rule)
651{
652 int j;
653 struct nlattr *nl_wmm_rules =
654 nla_nest_start(msg, NL80211_FREQUENCY_ATTR_WMM);
655
656 if (!nl_wmm_rules)
657 goto nla_put_failure;
658
659 for (j = 0; j < IEEE80211_NUM_ACS; j++) {
660 struct nlattr *nl_wmm_rule = nla_nest_start(msg, j);
661
662 if (!nl_wmm_rule)
663 goto nla_put_failure;
664
665 if (nla_put_u16(msg, NL80211_WMMR_CW_MIN,
666 rule->wmm_rule->client[j].cw_min) ||
667 nla_put_u16(msg, NL80211_WMMR_CW_MAX,
668 rule->wmm_rule->client[j].cw_max) ||
669 nla_put_u8(msg, NL80211_WMMR_AIFSN,
670 rule->wmm_rule->client[j].aifsn) ||
671 nla_put_u8(msg, NL80211_WMMR_TXOP,
672 rule->wmm_rule->client[j].cot))
673 goto nla_put_failure;
674
675 nla_nest_end(msg, nl_wmm_rule);
676 }
677 nla_nest_end(msg, nl_wmm_rules);
678
679 return 0;
680
681nla_put_failure:
682 return -ENOBUFS;
683}
684
685static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
Johannes Bergcdc89b92013-02-18 23:54:36 +0100686 struct ieee80211_channel *chan,
687 bool large)
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400688{
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200689 /* Some channels must be completely excluded from the
690 * list to protect old user-space tools from breaking
691 */
692 if (!large && chan->flags &
693 (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
694 return 0;
695
David S. Miller9360ffd2012-03-29 04:41:26 -0400696 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
697 chan->center_freq))
698 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400699
David S. Miller9360ffd2012-03-29 04:41:26 -0400700 if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
701 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
702 goto nla_put_failure;
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200703 if (chan->flags & IEEE80211_CHAN_NO_IR) {
704 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
705 goto nla_put_failure;
706 if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
707 goto nla_put_failure;
708 }
Johannes Bergcdc89b92013-02-18 23:54:36 +0100709 if (chan->flags & IEEE80211_CHAN_RADAR) {
710 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
711 goto nla_put_failure;
712 if (large) {
713 u32 time;
714
715 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
716
717 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
718 chan->dfs_state))
719 goto nla_put_failure;
720 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
721 time))
722 goto nla_put_failure;
Janusz Dziedzic089027e2014-02-21 19:46:12 +0100723 if (nla_put_u32(msg,
724 NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
725 chan->dfs_cac_ms))
726 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +0100727 }
728 }
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400729
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100730 if (large) {
731 if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
732 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
733 goto nla_put_failure;
734 if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
735 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
736 goto nla_put_failure;
737 if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
738 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
739 goto nla_put_failure;
740 if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
741 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
742 goto nla_put_failure;
David Spinadel570dbde2014-02-23 09:12:59 +0200743 if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
744 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
745 goto nla_put_failure;
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300746 if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
747 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
David Spinadel570dbde2014-02-23 09:12:59 +0200748 goto nla_put_failure;
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200749 if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
750 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
751 goto nla_put_failure;
752 if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
753 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
754 goto nla_put_failure;
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100755 }
756
David S. Miller9360ffd2012-03-29 04:41:26 -0400757 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
758 DBM_TO_MBM(chan->max_power)))
759 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400760
Haim Dreyfuss50f32712018-04-20 13:49:26 +0300761 if (large) {
762 const struct ieee80211_reg_rule *rule =
763 freq_reg_info(wiphy, chan->center_freq);
764
765 if (!IS_ERR(rule) && rule->wmm_rule) {
766 if (nl80211_msg_put_wmm_rules(msg, rule))
767 goto nla_put_failure;
768 }
769 }
770
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400771 return 0;
772
773 nla_put_failure:
774 return -ENOBUFS;
775}
776
Johannes Berg55682962007-09-20 13:09:35 -0400777/* netlink command implementations */
778
Johannes Bergb9454e82009-07-08 13:29:08 +0200779struct key_parse {
780 struct key_params p;
781 int idx;
Johannes Berge31b8212010-10-05 19:39:30 +0200782 int type;
Johannes Bergb9454e82009-07-08 13:29:08 +0200783 bool def, defmgmt;
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100784 bool def_uni, def_multi;
Johannes Bergb9454e82009-07-08 13:29:08 +0200785};
786
Johannes Berg768075e2017-11-13 15:35:06 +0100787static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
788 struct key_parse *k)
Johannes Bergb9454e82009-07-08 13:29:08 +0200789{
790 struct nlattr *tb[NL80211_KEY_MAX + 1];
791 int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
Johannes Berg768075e2017-11-13 15:35:06 +0100792 nl80211_key_policy, info->extack);
Johannes Bergb9454e82009-07-08 13:29:08 +0200793 if (err)
794 return err;
795
796 k->def = !!tb[NL80211_KEY_DEFAULT];
797 k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
798
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100799 if (k->def) {
800 k->def_uni = true;
801 k->def_multi = true;
802 }
803 if (k->defmgmt)
804 k->def_multi = true;
805
Johannes Bergb9454e82009-07-08 13:29:08 +0200806 if (tb[NL80211_KEY_IDX])
807 k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
808
809 if (tb[NL80211_KEY_DATA]) {
810 k->p.key = nla_data(tb[NL80211_KEY_DATA]);
811 k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
812 }
813
814 if (tb[NL80211_KEY_SEQ]) {
815 k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
816 k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
817 }
818
819 if (tb[NL80211_KEY_CIPHER])
820 k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
821
Johannes Berge31b8212010-10-05 19:39:30 +0200822 if (tb[NL80211_KEY_TYPE]) {
823 k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
824 if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
Johannes Berg768075e2017-11-13 15:35:06 +0100825 return genl_err_attr(info, -EINVAL,
826 tb[NL80211_KEY_TYPE]);
Johannes Berge31b8212010-10-05 19:39:30 +0200827 }
828
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100829 if (tb[NL80211_KEY_DEFAULT_TYPES]) {
830 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -0700831
Johannes Berg2da8f412012-01-20 13:52:37 +0100832 err = nla_parse_nested(kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
833 tb[NL80211_KEY_DEFAULT_TYPES],
Johannes Berg768075e2017-11-13 15:35:06 +0100834 nl80211_key_default_policy,
835 info->extack);
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100836 if (err)
837 return err;
838
839 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
840 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
841 }
842
Johannes Bergb9454e82009-07-08 13:29:08 +0200843 return 0;
844}
845
846static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
847{
848 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
849 k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
850 k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
851 }
852
853 if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
854 k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
855 k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
856 }
857
858 if (info->attrs[NL80211_ATTR_KEY_IDX])
859 k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
860
861 if (info->attrs[NL80211_ATTR_KEY_CIPHER])
862 k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
863
864 k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
865 k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
866
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100867 if (k->def) {
868 k->def_uni = true;
869 k->def_multi = true;
870 }
871 if (k->defmgmt)
872 k->def_multi = true;
873
Johannes Berge31b8212010-10-05 19:39:30 +0200874 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
875 k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Johannes Berg768075e2017-11-13 15:35:06 +0100876 if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) {
877 GENL_SET_ERR_MSG(info, "key type out of range");
Johannes Berge31b8212010-10-05 19:39:30 +0200878 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +0100879 }
Johannes Berge31b8212010-10-05 19:39:30 +0200880 }
881
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100882 if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
883 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Johannes Bergfceb6432017-04-12 14:34:07 +0200884 int err = nla_parse_nested(kdt,
885 NUM_NL80211_KEY_DEFAULT_TYPES - 1,
886 info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
Johannes Bergfe521452017-04-12 14:34:08 +0200887 nl80211_key_default_policy,
888 info->extack);
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100889 if (err)
890 return err;
891
892 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
893 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
894 }
895
Johannes Bergb9454e82009-07-08 13:29:08 +0200896 return 0;
897}
898
899static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
900{
901 int err;
902
903 memset(k, 0, sizeof(*k));
904 k->idx = -1;
Johannes Berge31b8212010-10-05 19:39:30 +0200905 k->type = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +0200906
907 if (info->attrs[NL80211_ATTR_KEY])
Johannes Berg768075e2017-11-13 15:35:06 +0100908 err = nl80211_parse_key_new(info, info->attrs[NL80211_ATTR_KEY], k);
Johannes Bergb9454e82009-07-08 13:29:08 +0200909 else
910 err = nl80211_parse_key_old(info, k);
911
912 if (err)
913 return err;
914
Johannes Berg768075e2017-11-13 15:35:06 +0100915 if (k->def && k->defmgmt) {
916 GENL_SET_ERR_MSG(info, "key with def && defmgmt is invalid");
Johannes Bergb9454e82009-07-08 13:29:08 +0200917 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +0100918 }
Johannes Bergb9454e82009-07-08 13:29:08 +0200919
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100920 if (k->defmgmt) {
Johannes Berg768075e2017-11-13 15:35:06 +0100921 if (k->def_uni || !k->def_multi) {
922 GENL_SET_ERR_MSG(info, "defmgmt key must be mcast");
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100923 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +0100924 }
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100925 }
926
Johannes Bergb9454e82009-07-08 13:29:08 +0200927 if (k->idx != -1) {
928 if (k->defmgmt) {
Johannes Berg768075e2017-11-13 15:35:06 +0100929 if (k->idx < 4 || k->idx > 5) {
930 GENL_SET_ERR_MSG(info,
931 "defmgmt key idx not 4 or 5");
Johannes Bergb9454e82009-07-08 13:29:08 +0200932 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +0100933 }
Johannes Bergb9454e82009-07-08 13:29:08 +0200934 } else if (k->def) {
Johannes Berg768075e2017-11-13 15:35:06 +0100935 if (k->idx < 0 || k->idx > 3) {
936 GENL_SET_ERR_MSG(info, "def key idx not 0-3");
Johannes Bergb9454e82009-07-08 13:29:08 +0200937 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +0100938 }
Johannes Bergb9454e82009-07-08 13:29:08 +0200939 } else {
Johannes Berg768075e2017-11-13 15:35:06 +0100940 if (k->idx < 0 || k->idx > 5) {
941 GENL_SET_ERR_MSG(info, "key idx not 0-5");
Johannes Bergb9454e82009-07-08 13:29:08 +0200942 return -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +0100943 }
Johannes Bergb9454e82009-07-08 13:29:08 +0200944 }
945 }
946
947 return 0;
948}
949
Johannes Bergfffd0932009-07-08 14:22:54 +0200950static struct cfg80211_cached_keys *
951nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
Johannes Berg768075e2017-11-13 15:35:06 +0100952 struct genl_info *info, bool *no_ht)
Johannes Bergfffd0932009-07-08 14:22:54 +0200953{
Johannes Berg768075e2017-11-13 15:35:06 +0100954 struct nlattr *keys = info->attrs[NL80211_ATTR_KEYS];
Johannes Bergfffd0932009-07-08 14:22:54 +0200955 struct key_parse parse;
956 struct nlattr *key;
957 struct cfg80211_cached_keys *result;
958 int rem, err, def = 0;
Johannes Bergf1c1f172016-09-13 17:08:23 +0200959 bool have_key = false;
960
961 nla_for_each_nested(key, keys, rem) {
962 have_key = true;
963 break;
964 }
965
966 if (!have_key)
967 return NULL;
Johannes Bergfffd0932009-07-08 14:22:54 +0200968
969 result = kzalloc(sizeof(*result), GFP_KERNEL);
970 if (!result)
971 return ERR_PTR(-ENOMEM);
972
973 result->def = -1;
Johannes Bergfffd0932009-07-08 14:22:54 +0200974
975 nla_for_each_nested(key, keys, rem) {
976 memset(&parse, 0, sizeof(parse));
977 parse.idx = -1;
978
Johannes Berg768075e2017-11-13 15:35:06 +0100979 err = nl80211_parse_key_new(info, key, &parse);
Johannes Bergfffd0932009-07-08 14:22:54 +0200980 if (err)
981 goto error;
982 err = -EINVAL;
983 if (!parse.p.key)
984 goto error;
Johannes Berg768075e2017-11-13 15:35:06 +0100985 if (parse.idx < 0 || parse.idx > 3) {
986 GENL_SET_ERR_MSG(info, "key index out of range [0-3]");
Johannes Bergfffd0932009-07-08 14:22:54 +0200987 goto error;
Johannes Berg768075e2017-11-13 15:35:06 +0100988 }
Johannes Bergfffd0932009-07-08 14:22:54 +0200989 if (parse.def) {
Johannes Berg768075e2017-11-13 15:35:06 +0100990 if (def) {
991 GENL_SET_ERR_MSG(info,
992 "only one key can be default");
Johannes Bergfffd0932009-07-08 14:22:54 +0200993 goto error;
Johannes Berg768075e2017-11-13 15:35:06 +0100994 }
Johannes Bergfffd0932009-07-08 14:22:54 +0200995 def = 1;
996 result->def = parse.idx;
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100997 if (!parse.def_uni || !parse.def_multi)
998 goto error;
Johannes Bergfffd0932009-07-08 14:22:54 +0200999 } else if (parse.defmgmt)
1000 goto error;
1001 err = cfg80211_validate_key_settings(rdev, &parse.p,
Johannes Berge31b8212010-10-05 19:39:30 +02001002 parse.idx, false, NULL);
Johannes Bergfffd0932009-07-08 14:22:54 +02001003 if (err)
1004 goto error;
Johannes Berg386b1f22016-09-13 16:10:02 +02001005 if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
1006 parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) {
Johannes Berg768075e2017-11-13 15:35:06 +01001007 GENL_SET_ERR_MSG(info, "connect key must be WEP");
Johannes Berg386b1f22016-09-13 16:10:02 +02001008 err = -EINVAL;
1009 goto error;
1010 }
Johannes Bergfffd0932009-07-08 14:22:54 +02001011 result->params[parse.idx].cipher = parse.p.cipher;
1012 result->params[parse.idx].key_len = parse.p.key_len;
1013 result->params[parse.idx].key = result->data[parse.idx];
1014 memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
Sujith Manoharande7044e2012-10-18 10:19:28 +05301015
Johannes Berg386b1f22016-09-13 16:10:02 +02001016 /* must be WEP key if we got here */
1017 if (no_ht)
1018 *no_ht = true;
Johannes Bergfffd0932009-07-08 14:22:54 +02001019 }
1020
Johannes Bergf1c1f172016-09-13 17:08:23 +02001021 if (result->def < 0) {
1022 err = -EINVAL;
Johannes Berg768075e2017-11-13 15:35:06 +01001023 GENL_SET_ERR_MSG(info, "need a default/TX key");
Johannes Bergf1c1f172016-09-13 17:08:23 +02001024 goto error;
1025 }
1026
Johannes Bergfffd0932009-07-08 14:22:54 +02001027 return result;
1028 error:
1029 kfree(result);
1030 return ERR_PTR(err);
1031}
1032
1033static int nl80211_key_allowed(struct wireless_dev *wdev)
1034{
1035 ASSERT_WDEV_LOCK(wdev);
1036
Johannes Bergfffd0932009-07-08 14:22:54 +02001037 switch (wdev->iftype) {
1038 case NL80211_IFTYPE_AP:
1039 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02001040 case NL80211_IFTYPE_P2P_GO:
Thomas Pedersenff973af2011-05-03 16:57:12 -07001041 case NL80211_IFTYPE_MESH_POINT:
Johannes Bergfffd0932009-07-08 14:22:54 +02001042 break;
1043 case NL80211_IFTYPE_ADHOC:
Johannes Bergfffd0932009-07-08 14:22:54 +02001044 case NL80211_IFTYPE_STATION:
Johannes Berg074ac8d2010-09-16 14:58:22 +02001045 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Bergceca7b72013-05-16 00:55:45 +02001046 if (!wdev->current_bss)
Johannes Bergfffd0932009-07-08 14:22:54 +02001047 return -ENOLINK;
1048 break;
Johannes Bergde4fcba2014-10-31 14:16:12 +01001049 case NL80211_IFTYPE_UNSPECIFIED:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01001050 case NL80211_IFTYPE_OCB:
Johannes Bergde4fcba2014-10-31 14:16:12 +01001051 case NL80211_IFTYPE_MONITOR:
Ayala Bekercb3b7d82016-09-20 17:31:13 +03001052 case NL80211_IFTYPE_NAN:
Johannes Bergde4fcba2014-10-31 14:16:12 +01001053 case NL80211_IFTYPE_P2P_DEVICE:
1054 case NL80211_IFTYPE_WDS:
1055 case NUM_NL80211_IFTYPES:
Johannes Bergfffd0932009-07-08 14:22:54 +02001056 return -EINVAL;
1057 }
1058
1059 return 0;
1060}
1061
Jouni Malinen664834d2014-01-15 00:01:44 +02001062static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
1063 struct nlattr *tb)
1064{
1065 struct ieee80211_channel *chan;
1066
1067 if (tb == NULL)
1068 return NULL;
1069 chan = ieee80211_get_channel(wiphy, nla_get_u32(tb));
1070 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
1071 return NULL;
1072 return chan;
1073}
1074
Johannes Berg7527a782011-05-13 10:58:57 +02001075static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
1076{
1077 struct nlattr *nl_modes = nla_nest_start(msg, attr);
1078 int i;
1079
1080 if (!nl_modes)
1081 goto nla_put_failure;
1082
1083 i = 0;
1084 while (ifmodes) {
David S. Miller9360ffd2012-03-29 04:41:26 -04001085 if ((ifmodes & 1) && nla_put_flag(msg, i))
1086 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001087 ifmodes >>= 1;
1088 i++;
1089 }
1090
1091 nla_nest_end(msg, nl_modes);
1092 return 0;
1093
1094nla_put_failure:
1095 return -ENOBUFS;
1096}
1097
1098static int nl80211_put_iface_combinations(struct wiphy *wiphy,
Johannes Bergcdc89b92013-02-18 23:54:36 +01001099 struct sk_buff *msg,
1100 bool large)
Johannes Berg7527a782011-05-13 10:58:57 +02001101{
1102 struct nlattr *nl_combis;
1103 int i, j;
1104
1105 nl_combis = nla_nest_start(msg,
1106 NL80211_ATTR_INTERFACE_COMBINATIONS);
1107 if (!nl_combis)
1108 goto nla_put_failure;
1109
1110 for (i = 0; i < wiphy->n_iface_combinations; i++) {
1111 const struct ieee80211_iface_combination *c;
1112 struct nlattr *nl_combi, *nl_limits;
1113
1114 c = &wiphy->iface_combinations[i];
1115
1116 nl_combi = nla_nest_start(msg, i + 1);
1117 if (!nl_combi)
1118 goto nla_put_failure;
1119
1120 nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS);
1121 if (!nl_limits)
1122 goto nla_put_failure;
1123
1124 for (j = 0; j < c->n_limits; j++) {
1125 struct nlattr *nl_limit;
1126
1127 nl_limit = nla_nest_start(msg, j + 1);
1128 if (!nl_limit)
1129 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04001130 if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
1131 c->limits[j].max))
1132 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001133 if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
1134 c->limits[j].types))
1135 goto nla_put_failure;
1136 nla_nest_end(msg, nl_limit);
1137 }
1138
1139 nla_nest_end(msg, nl_limits);
1140
David S. Miller9360ffd2012-03-29 04:41:26 -04001141 if (c->beacon_int_infra_match &&
1142 nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
1143 goto nla_put_failure;
1144 if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
1145 c->num_different_channels) ||
1146 nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
1147 c->max_interfaces))
1148 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +01001149 if (large &&
Felix Fietkau8c48b502014-05-05 11:48:40 +02001150 (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
1151 c->radar_detect_widths) ||
1152 nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
1153 c->radar_detect_regions)))
Johannes Bergcdc89b92013-02-18 23:54:36 +01001154 goto nla_put_failure;
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05301155 if (c->beacon_int_min_gcd &&
1156 nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
1157 c->beacon_int_min_gcd))
1158 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001159
1160 nla_nest_end(msg, nl_combi);
1161 }
1162
1163 nla_nest_end(msg, nl_combis);
1164
1165 return 0;
1166nla_put_failure:
1167 return -ENOBUFS;
1168}
1169
Johannes Berg3713b4e2013-02-14 16:19:38 +01001170#ifdef CONFIG_PM
Johannes Bergb56cf722013-02-20 01:02:38 +01001171static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
1172 struct sk_buff *msg)
1173{
Johannes Berg964dc9e2013-06-03 17:25:34 +02001174 const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
Johannes Bergb56cf722013-02-20 01:02:38 +01001175 struct nlattr *nl_tcp;
1176
1177 if (!tcp)
1178 return 0;
1179
1180 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
1181 if (!nl_tcp)
1182 return -ENOBUFS;
1183
1184 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1185 tcp->data_payload_max))
1186 return -ENOBUFS;
1187
1188 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1189 tcp->data_payload_max))
1190 return -ENOBUFS;
1191
1192 if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
1193 return -ENOBUFS;
1194
1195 if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
1196 sizeof(*tcp->tok), tcp->tok))
1197 return -ENOBUFS;
1198
1199 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
1200 tcp->data_interval_max))
1201 return -ENOBUFS;
1202
1203 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
1204 tcp->wake_payload_max))
1205 return -ENOBUFS;
1206
1207 nla_nest_end(msg, nl_tcp);
1208 return 0;
1209}
1210
Johannes Berg3713b4e2013-02-14 16:19:38 +01001211static int nl80211_send_wowlan(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001212 struct cfg80211_registered_device *rdev,
Johannes Bergb56cf722013-02-20 01:02:38 +01001213 bool large)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001214{
1215 struct nlattr *nl_wowlan;
1216
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001217 if (!rdev->wiphy.wowlan)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001218 return 0;
1219
1220 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
1221 if (!nl_wowlan)
1222 return -ENOBUFS;
1223
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001224 if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001225 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001226 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001227 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001228 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001229 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001230 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001231 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001232 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001233 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001234 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001235 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001236 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001237 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001238 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001239 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
1240 return -ENOBUFS;
1241
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001242 if (rdev->wiphy.wowlan->n_patterns) {
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07001243 struct nl80211_pattern_support pat = {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001244 .max_patterns = rdev->wiphy.wowlan->n_patterns,
1245 .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
1246 .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
1247 .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001248 };
1249
1250 if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
1251 sizeof(pat), &pat))
1252 return -ENOBUFS;
1253 }
1254
Luciano Coelho75453cc2015-01-09 14:06:37 +02001255 if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
1256 nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
1257 rdev->wiphy.wowlan->max_nd_match_sets))
1258 return -ENOBUFS;
1259
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001260 if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
Johannes Bergb56cf722013-02-20 01:02:38 +01001261 return -ENOBUFS;
1262
Johannes Berg3713b4e2013-02-14 16:19:38 +01001263 nla_nest_end(msg, nl_wowlan);
1264
1265 return 0;
1266}
1267#endif
1268
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001269static int nl80211_send_coalesce(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001270 struct cfg80211_registered_device *rdev)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001271{
1272 struct nl80211_coalesce_rule_support rule;
1273
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001274 if (!rdev->wiphy.coalesce)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001275 return 0;
1276
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001277 rule.max_rules = rdev->wiphy.coalesce->n_rules;
1278 rule.max_delay = rdev->wiphy.coalesce->max_delay;
1279 rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
1280 rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
1281 rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
1282 rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001283
1284 if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
1285 return -ENOBUFS;
1286
1287 return 0;
1288}
1289
Johannes Berg3713b4e2013-02-14 16:19:38 +01001290static int nl80211_send_band_rateinfo(struct sk_buff *msg,
1291 struct ieee80211_supported_band *sband)
1292{
1293 struct nlattr *nl_rates, *nl_rate;
1294 struct ieee80211_rate *rate;
1295 int i;
1296
1297 /* add HT info */
1298 if (sband->ht_cap.ht_supported &&
1299 (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
1300 sizeof(sband->ht_cap.mcs),
1301 &sband->ht_cap.mcs) ||
1302 nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
1303 sband->ht_cap.cap) ||
1304 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
1305 sband->ht_cap.ampdu_factor) ||
1306 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
1307 sband->ht_cap.ampdu_density)))
1308 return -ENOBUFS;
1309
1310 /* add VHT info */
1311 if (sband->vht_cap.vht_supported &&
1312 (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
1313 sizeof(sband->vht_cap.vht_mcs),
1314 &sband->vht_cap.vht_mcs) ||
1315 nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
1316 sband->vht_cap.cap)))
1317 return -ENOBUFS;
1318
1319 /* add bitrates */
1320 nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
1321 if (!nl_rates)
1322 return -ENOBUFS;
1323
1324 for (i = 0; i < sband->n_bitrates; i++) {
1325 nl_rate = nla_nest_start(msg, i);
1326 if (!nl_rate)
1327 return -ENOBUFS;
1328
1329 rate = &sband->bitrates[i];
1330 if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
1331 rate->bitrate))
1332 return -ENOBUFS;
1333 if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
1334 nla_put_flag(msg,
1335 NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
1336 return -ENOBUFS;
1337
1338 nla_nest_end(msg, nl_rate);
1339 }
1340
1341 nla_nest_end(msg, nl_rates);
1342
1343 return 0;
1344}
1345
1346static int
1347nl80211_send_mgmt_stypes(struct sk_buff *msg,
1348 const struct ieee80211_txrx_stypes *mgmt_stypes)
1349{
1350 u16 stypes;
1351 struct nlattr *nl_ftypes, *nl_ifs;
1352 enum nl80211_iftype ift;
1353 int i;
1354
1355 if (!mgmt_stypes)
1356 return 0;
1357
1358 nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
1359 if (!nl_ifs)
1360 return -ENOBUFS;
1361
1362 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1363 nl_ftypes = nla_nest_start(msg, ift);
1364 if (!nl_ftypes)
1365 return -ENOBUFS;
1366 i = 0;
1367 stypes = mgmt_stypes[ift].tx;
1368 while (stypes) {
1369 if ((stypes & 1) &&
1370 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1371 (i << 4) | IEEE80211_FTYPE_MGMT))
1372 return -ENOBUFS;
1373 stypes >>= 1;
1374 i++;
1375 }
1376 nla_nest_end(msg, nl_ftypes);
1377 }
1378
1379 nla_nest_end(msg, nl_ifs);
1380
1381 nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
1382 if (!nl_ifs)
1383 return -ENOBUFS;
1384
1385 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1386 nl_ftypes = nla_nest_start(msg, ift);
1387 if (!nl_ftypes)
1388 return -ENOBUFS;
1389 i = 0;
1390 stypes = mgmt_stypes[ift].rx;
1391 while (stypes) {
1392 if ((stypes & 1) &&
1393 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1394 (i << 4) | IEEE80211_FTYPE_MGMT))
1395 return -ENOBUFS;
1396 stypes >>= 1;
1397 i++;
1398 }
1399 nla_nest_end(msg, nl_ftypes);
1400 }
1401 nla_nest_end(msg, nl_ifs);
1402
1403 return 0;
1404}
1405
Johannes Berg17948992016-10-26 11:42:04 +02001406#define CMD(op, n) \
1407 do { \
1408 if (rdev->ops->op) { \
1409 i++; \
1410 if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
1411 goto nla_put_failure; \
1412 } \
1413 } while (0)
1414
1415static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
1416 struct sk_buff *msg)
1417{
1418 int i = 0;
1419
1420 /*
1421 * do *NOT* add anything into this function, new things need to be
1422 * advertised only to new versions of userspace that can deal with
1423 * the split (and they can't possibly care about new features...
1424 */
1425 CMD(add_virtual_intf, NEW_INTERFACE);
1426 CMD(change_virtual_intf, SET_INTERFACE);
1427 CMD(add_key, NEW_KEY);
1428 CMD(start_ap, START_AP);
1429 CMD(add_station, NEW_STATION);
1430 CMD(add_mpath, NEW_MPATH);
1431 CMD(update_mesh_config, SET_MESH_CONFIG);
1432 CMD(change_bss, SET_BSS);
1433 CMD(auth, AUTHENTICATE);
1434 CMD(assoc, ASSOCIATE);
1435 CMD(deauth, DEAUTHENTICATE);
1436 CMD(disassoc, DISASSOCIATE);
1437 CMD(join_ibss, JOIN_IBSS);
1438 CMD(join_mesh, JOIN_MESH);
1439 CMD(set_pmksa, SET_PMKSA);
1440 CMD(del_pmksa, DEL_PMKSA);
1441 CMD(flush_pmksa, FLUSH_PMKSA);
1442 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
1443 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
1444 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
1445 CMD(mgmt_tx, FRAME);
1446 CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
1447 if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
1448 i++;
1449 if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
1450 goto nla_put_failure;
1451 }
1452 if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
1453 rdev->ops->join_mesh) {
1454 i++;
1455 if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
1456 goto nla_put_failure;
1457 }
1458 CMD(set_wds_peer, SET_WDS_PEER);
1459 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
1460 CMD(tdls_mgmt, TDLS_MGMT);
1461 CMD(tdls_oper, TDLS_OPER);
1462 }
Arend Van Sprielca986ad2017-04-21 13:05:00 +01001463 if (rdev->wiphy.max_sched_scan_reqs)
Johannes Berg17948992016-10-26 11:42:04 +02001464 CMD(sched_scan_start, START_SCHED_SCAN);
1465 CMD(probe_client, PROBE_CLIENT);
1466 CMD(set_noack_map, SET_NOACK_MAP);
1467 if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
1468 i++;
1469 if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1470 goto nla_put_failure;
1471 }
1472 CMD(start_p2p_device, START_P2P_DEVICE);
1473 CMD(set_mcast_rate, SET_MCAST_RATE);
1474#ifdef CONFIG_NL80211_TESTMODE
1475 CMD(testmode_cmd, TESTMODE);
1476#endif
1477
1478 if (rdev->ops->connect || rdev->ops->auth) {
1479 i++;
1480 if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
1481 goto nla_put_failure;
1482 }
1483
1484 if (rdev->ops->disconnect || rdev->ops->deauth) {
1485 i++;
1486 if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
1487 goto nla_put_failure;
1488 }
1489
1490 return i;
1491 nla_put_failure:
1492 return -ENOBUFS;
1493}
1494
Johannes Berg86e8cf92013-06-19 10:57:22 +02001495struct nl80211_dump_wiphy_state {
1496 s64 filter_wiphy;
1497 long start;
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05301498 long split_start, band_start, chan_start, capa_start;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001499 bool split;
1500};
1501
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001502static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
Johannes Berg3bb20552014-05-26 13:52:25 +02001503 enum nl80211_commands cmd,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001504 struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001505 int flags, struct nl80211_dump_wiphy_state *state)
Johannes Berg55682962007-09-20 13:09:35 -04001506{
1507 void *hdr;
Johannes Bergee688b002008-01-24 19:38:39 +01001508 struct nlattr *nl_bands, *nl_band;
1509 struct nlattr *nl_freqs, *nl_freq;
Johannes Berg8fdc6212009-03-14 09:34:01 +01001510 struct nlattr *nl_cmds;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001511 enum nl80211_band band;
Johannes Bergee688b002008-01-24 19:38:39 +01001512 struct ieee80211_channel *chan;
Johannes Bergee688b002008-01-24 19:38:39 +01001513 int i;
Johannes Berg2e161f72010-08-12 15:38:38 +02001514 const struct ieee80211_txrx_stypes *mgmt_stypes =
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001515 rdev->wiphy.mgmt_stypes;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001516 u32 features;
Johannes Berg55682962007-09-20 13:09:35 -04001517
Johannes Berg3bb20552014-05-26 13:52:25 +02001518 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04001519 if (!hdr)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001520 return -ENOBUFS;
1521
Johannes Berg86e8cf92013-06-19 10:57:22 +02001522 if (WARN_ON(!state))
1523 return -EINVAL;
Johannes Berg55682962007-09-20 13:09:35 -04001524
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001525 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001526 nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001527 wiphy_name(&rdev->wiphy)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04001528 nla_put_u32(msg, NL80211_ATTR_GENERATION,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001529 cfg80211_rdev_list_generation))
David S. Miller9360ffd2012-03-29 04:41:26 -04001530 goto nla_put_failure;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02001531
Johannes Berg3bb20552014-05-26 13:52:25 +02001532 if (cmd != NL80211_CMD_NEW_WIPHY)
1533 goto finish;
1534
Johannes Berg86e8cf92013-06-19 10:57:22 +02001535 switch (state->split_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001536 case 0:
1537 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001538 rdev->wiphy.retry_short) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001539 nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001540 rdev->wiphy.retry_long) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001541 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001542 rdev->wiphy.frag_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001543 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001544 rdev->wiphy.rts_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001545 nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001546 rdev->wiphy.coverage_class) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001547 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001548 rdev->wiphy.max_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001549 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001550 rdev->wiphy.max_sched_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001551 nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001552 rdev->wiphy.max_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001553 nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001554 rdev->wiphy.max_sched_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001555 nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
Avraham Stern3b06d272015-10-12 09:51:34 +03001556 rdev->wiphy.max_match_sets) ||
1557 nla_put_u32(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
1558 rdev->wiphy.max_sched_scan_plans) ||
1559 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
1560 rdev->wiphy.max_sched_scan_plan_interval) ||
1561 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
1562 rdev->wiphy.max_sched_scan_plan_iterations))
Johannes Bergee688b002008-01-24 19:38:39 +01001563 goto nla_put_failure;
1564
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001565 if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001566 nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
1567 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001568 if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001569 nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
1570 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001571 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001572 nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
1573 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001574 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001575 nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
1576 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001577 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001578 nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
1579 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001580 if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001581 nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
David S. Miller9360ffd2012-03-29 04:41:26 -04001582 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001583 state->split_start++;
1584 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001585 break;
1586 case 1:
1587 if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001588 sizeof(u32) * rdev->wiphy.n_cipher_suites,
1589 rdev->wiphy.cipher_suites))
Mahesh Palivelabf0c111e2012-06-22 07:27:46 +00001590 goto nla_put_failure;
1591
Johannes Berg3713b4e2013-02-14 16:19:38 +01001592 if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001593 rdev->wiphy.max_num_pmkids))
Johannes Bergee688b002008-01-24 19:38:39 +01001594 goto nla_put_failure;
1595
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001596 if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001597 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
1598 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001599
Johannes Berg3713b4e2013-02-14 16:19:38 +01001600 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001601 rdev->wiphy.available_antennas_tx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001602 nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001603 rdev->wiphy.available_antennas_rx))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001604 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001605
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001606 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001607 nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001608 rdev->wiphy.probe_resp_offload))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001609 goto nla_put_failure;
Jouni Malinene2f367f262008-11-21 19:01:30 +02001610
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001611 if ((rdev->wiphy.available_antennas_tx ||
1612 rdev->wiphy.available_antennas_rx) &&
1613 rdev->ops->get_antenna) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001614 u32 tx_ant = 0, rx_ant = 0;
1615 int res;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07001616
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001617 res = rdev_get_antenna(rdev, &tx_ant, &rx_ant);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001618 if (!res) {
1619 if (nla_put_u32(msg,
1620 NL80211_ATTR_WIPHY_ANTENNA_TX,
1621 tx_ant) ||
1622 nla_put_u32(msg,
1623 NL80211_ATTR_WIPHY_ANTENNA_RX,
1624 rx_ant))
1625 goto nla_put_failure;
1626 }
Johannes Bergee688b002008-01-24 19:38:39 +01001627 }
1628
Johannes Berg86e8cf92013-06-19 10:57:22 +02001629 state->split_start++;
1630 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001631 break;
1632 case 2:
1633 if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001634 rdev->wiphy.interface_modes))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001635 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001636 state->split_start++;
1637 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001638 break;
1639 case 3:
1640 nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
1641 if (!nl_bands)
Johannes Bergee688b002008-01-24 19:38:39 +01001642 goto nla_put_failure;
1643
Johannes Berg86e8cf92013-06-19 10:57:22 +02001644 for (band = state->band_start;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001645 band < NUM_NL80211_BANDS; band++) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001646 struct ieee80211_supported_band *sband;
1647
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001648 sband = rdev->wiphy.bands[band];
Johannes Berg3713b4e2013-02-14 16:19:38 +01001649
1650 if (!sband)
1651 continue;
1652
1653 nl_band = nla_nest_start(msg, band);
1654 if (!nl_band)
Johannes Bergee688b002008-01-24 19:38:39 +01001655 goto nla_put_failure;
1656
Johannes Berg86e8cf92013-06-19 10:57:22 +02001657 switch (state->chan_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001658 case 0:
1659 if (nl80211_send_band_rateinfo(msg, sband))
1660 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001661 state->chan_start++;
1662 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001663 break;
1664 default:
1665 /* add frequencies */
1666 nl_freqs = nla_nest_start(
1667 msg, NL80211_BAND_ATTR_FREQS);
1668 if (!nl_freqs)
1669 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001670
Johannes Berg86e8cf92013-06-19 10:57:22 +02001671 for (i = state->chan_start - 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001672 i < sband->n_channels;
1673 i++) {
1674 nl_freq = nla_nest_start(msg, i);
1675 if (!nl_freq)
1676 goto nla_put_failure;
1677
1678 chan = &sband->channels[i];
1679
Johannes Berg86e8cf92013-06-19 10:57:22 +02001680 if (nl80211_msg_put_channel(
Haim Dreyfuss50f32712018-04-20 13:49:26 +03001681 msg, &rdev->wiphy, chan,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001682 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001683 goto nla_put_failure;
1684
1685 nla_nest_end(msg, nl_freq);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001686 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001687 break;
1688 }
1689 if (i < sband->n_channels)
Johannes Berg86e8cf92013-06-19 10:57:22 +02001690 state->chan_start = i + 2;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001691 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001692 state->chan_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001693 nla_nest_end(msg, nl_freqs);
1694 }
1695
1696 nla_nest_end(msg, nl_band);
1697
Johannes Berg86e8cf92013-06-19 10:57:22 +02001698 if (state->split) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001699 /* start again here */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001700 if (state->chan_start)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001701 band--;
1702 break;
1703 }
Johannes Bergee688b002008-01-24 19:38:39 +01001704 }
Johannes Berg3713b4e2013-02-14 16:19:38 +01001705 nla_nest_end(msg, nl_bands);
Johannes Bergee688b002008-01-24 19:38:39 +01001706
Johannes Berg57fbcce2016-04-12 15:56:15 +02001707 if (band < NUM_NL80211_BANDS)
Johannes Berg86e8cf92013-06-19 10:57:22 +02001708 state->band_start = band + 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001709 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001710 state->band_start = 0;
Johannes Bergee688b002008-01-24 19:38:39 +01001711
Johannes Berg3713b4e2013-02-14 16:19:38 +01001712 /* if bands & channels are done, continue outside */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001713 if (state->band_start == 0 && state->chan_start == 0)
1714 state->split_start++;
1715 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001716 break;
1717 case 4:
1718 nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
1719 if (!nl_cmds)
David S. Miller9360ffd2012-03-29 04:41:26 -04001720 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001721
Johannes Berg17948992016-10-26 11:42:04 +02001722 i = nl80211_add_commands_unsplit(rdev, msg);
1723 if (i < 0)
1724 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001725 if (state->split) {
Arend van Spriel5de17982013-04-18 15:49:00 +02001726 CMD(crit_proto_start, CRIT_PROTOCOL_START);
1727 CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001728 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02001729 CMD(channel_switch, CHANNEL_SWITCH);
Johannes Berg02df00e2014-06-10 14:06:25 +02001730 CMD(set_qos_map, SET_QOS_MAP);
Johannes Berg723e73a2014-10-22 09:25:06 +02001731 if (rdev->wiphy.features &
1732 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
Johannes Berg960d01a2014-09-09 22:55:35 +03001733 CMD(add_tx_ts, ADD_TX_TS);
Michael Braunce0ce132016-10-10 19:12:22 +02001734 CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
vamsi krishna088e8df2016-10-27 16:51:11 +03001735 CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
Arend van Spriel5de17982013-04-18 15:49:00 +02001736 }
Johannes Berg8fdc6212009-03-14 09:34:01 +01001737#undef CMD
Samuel Ortizb23aa672009-07-01 21:26:54 +02001738
Johannes Berg3713b4e2013-02-14 16:19:38 +01001739 nla_nest_end(msg, nl_cmds);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001740 state->split_start++;
1741 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001742 break;
1743 case 5:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001744 if (rdev->ops->remain_on_channel &&
1745 (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001746 nla_put_u32(msg,
1747 NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001748 rdev->wiphy.max_remain_on_channel_duration))
Johannes Berg2e161f72010-08-12 15:38:38 +02001749 goto nla_put_failure;
1750
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001751 if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001752 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
1753 goto nla_put_failure;
Johannes Berg2e161f72010-08-12 15:38:38 +02001754
Johannes Berg3713b4e2013-02-14 16:19:38 +01001755 if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
1756 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001757 state->split_start++;
1758 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001759 break;
1760 case 6:
Johannes Bergdfb89c52012-06-27 09:23:48 +02001761#ifdef CONFIG_PM
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001762 if (nl80211_send_wowlan(msg, rdev, state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001763 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001764 state->split_start++;
1765 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001766 break;
1767#else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001768 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001769#endif
1770 case 7:
1771 if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001772 rdev->wiphy.software_iftypes))
Johannes Bergff1b6e62011-05-04 15:37:28 +02001773 goto nla_put_failure;
1774
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001775 if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001776 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001777 goto nla_put_failure;
Johannes Bergff1b6e62011-05-04 15:37:28 +02001778
Johannes Berg86e8cf92013-06-19 10:57:22 +02001779 state->split_start++;
1780 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001781 break;
1782 case 8:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001783 if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001784 nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001785 rdev->wiphy.ap_sme_capa))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001786 goto nla_put_failure;
1787
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001788 features = rdev->wiphy.features;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001789 /*
1790 * We can only add the per-channel limit information if the
1791 * dump is split, otherwise it makes it too big. Therefore
1792 * only advertise it in that case.
1793 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001794 if (state->split)
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001795 features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
1796 if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001797 goto nla_put_failure;
1798
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001799 if (rdev->wiphy.ht_capa_mod_mask &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001800 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001801 sizeof(*rdev->wiphy.ht_capa_mod_mask),
1802 rdev->wiphy.ht_capa_mod_mask))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001803 goto nla_put_failure;
1804
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001805 if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
1806 rdev->wiphy.max_acl_mac_addrs &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001807 nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001808 rdev->wiphy.max_acl_mac_addrs))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001809 goto nla_put_failure;
1810
1811 /*
1812 * Any information below this point is only available to
1813 * applications that can deal with it being split. This
1814 * helps ensure that newly added capabilities don't break
1815 * older tools by overrunning their buffers.
1816 *
1817 * We still increment split_start so that in the split
1818 * case we'll continue with more data in the next round,
1819 * but break unconditionally so unsplit data stops here.
1820 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001821 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001822 break;
1823 case 9:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001824 if (rdev->wiphy.extended_capabilities &&
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001825 (nla_put(msg, NL80211_ATTR_EXT_CAPA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001826 rdev->wiphy.extended_capabilities_len,
1827 rdev->wiphy.extended_capabilities) ||
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001828 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001829 rdev->wiphy.extended_capabilities_len,
1830 rdev->wiphy.extended_capabilities_mask)))
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001831 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001832
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001833 if (rdev->wiphy.vht_capa_mod_mask &&
Johannes Bergee2aca32013-02-21 17:36:01 +01001834 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001835 sizeof(*rdev->wiphy.vht_capa_mod_mask),
1836 rdev->wiphy.vht_capa_mod_mask))
Johannes Bergee2aca32013-02-21 17:36:01 +01001837 goto nla_put_failure;
1838
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001839 state->split_start++;
1840 break;
1841 case 10:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001842 if (nl80211_send_coalesce(msg, rdev))
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001843 goto nla_put_failure;
1844
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001845 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
Felix Fietkau01e0daa2013-11-09 14:57:54 +01001846 (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
1847 nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
1848 goto nla_put_failure;
Jouni Malinenb43504c2014-01-15 00:01:08 +02001849
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001850 if (rdev->wiphy.max_ap_assoc_sta &&
Jouni Malinenb43504c2014-01-15 00:01:08 +02001851 nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001852 rdev->wiphy.max_ap_assoc_sta))
Jouni Malinenb43504c2014-01-15 00:01:08 +02001853 goto nla_put_failure;
1854
Johannes Bergad7e7182013-11-13 13:37:47 +01001855 state->split_start++;
1856 break;
1857 case 11:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001858 if (rdev->wiphy.n_vendor_commands) {
Johannes Berg567ffc32013-12-18 14:43:31 +01001859 const struct nl80211_vendor_cmd_info *info;
1860 struct nlattr *nested;
Johannes Bergad7e7182013-11-13 13:37:47 +01001861
Johannes Berg567ffc32013-12-18 14:43:31 +01001862 nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
1863 if (!nested)
Johannes Bergad7e7182013-11-13 13:37:47 +01001864 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01001865
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001866 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
1867 info = &rdev->wiphy.vendor_commands[i].info;
Johannes Berg567ffc32013-12-18 14:43:31 +01001868 if (nla_put(msg, i + 1, sizeof(*info), info))
1869 goto nla_put_failure;
1870 }
1871 nla_nest_end(msg, nested);
1872 }
1873
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001874 if (rdev->wiphy.n_vendor_events) {
Johannes Berg567ffc32013-12-18 14:43:31 +01001875 const struct nl80211_vendor_cmd_info *info;
1876 struct nlattr *nested;
1877
1878 nested = nla_nest_start(msg,
1879 NL80211_ATTR_VENDOR_EVENTS);
1880 if (!nested)
1881 goto nla_put_failure;
1882
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001883 for (i = 0; i < rdev->wiphy.n_vendor_events; i++) {
1884 info = &rdev->wiphy.vendor_events[i];
Johannes Berg567ffc32013-12-18 14:43:31 +01001885 if (nla_put(msg, i + 1, sizeof(*info), info))
1886 goto nla_put_failure;
1887 }
1888 nla_nest_end(msg, nested);
1889 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03001890 state->split_start++;
1891 break;
1892 case 12:
1893 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
1894 nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
1895 rdev->wiphy.max_num_csa_counters))
1896 goto nla_put_failure;
Felix Fietkau01e0daa2013-11-09 14:57:54 +01001897
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02001898 if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
1899 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
1900 goto nla_put_failure;
1901
Arend Van Sprielca986ad2017-04-21 13:05:00 +01001902 if (rdev->wiphy.max_sched_scan_reqs &&
1903 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_MAX_REQS,
1904 rdev->wiphy.max_sched_scan_reqs))
1905 goto nla_put_failure;
1906
Gautam Kumar Shuklad75bb062014-12-23 16:55:19 +01001907 if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
1908 sizeof(rdev->wiphy.ext_features),
1909 rdev->wiphy.ext_features))
1910 goto nla_put_failure;
1911
Arend van Spriel38de03d2016-03-02 20:37:18 +01001912 if (rdev->wiphy.bss_select_support) {
1913 struct nlattr *nested;
1914 u32 bss_select_support = rdev->wiphy.bss_select_support;
1915
1916 nested = nla_nest_start(msg, NL80211_ATTR_BSS_SELECT);
1917 if (!nested)
1918 goto nla_put_failure;
1919
1920 i = 0;
1921 while (bss_select_support) {
1922 if ((bss_select_support & 1) &&
1923 nla_put_flag(msg, i))
1924 goto nla_put_failure;
1925 i++;
1926 bss_select_support >>= 1;
1927 }
1928 nla_nest_end(msg, nested);
1929 }
1930
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05301931 state->split_start++;
1932 break;
1933 case 13:
1934 if (rdev->wiphy.num_iftype_ext_capab &&
1935 rdev->wiphy.iftype_ext_capab) {
1936 struct nlattr *nested_ext_capab, *nested;
1937
1938 nested = nla_nest_start(msg,
1939 NL80211_ATTR_IFTYPE_EXT_CAPA);
1940 if (!nested)
1941 goto nla_put_failure;
1942
1943 for (i = state->capa_start;
1944 i < rdev->wiphy.num_iftype_ext_capab; i++) {
1945 const struct wiphy_iftype_ext_capab *capab;
1946
1947 capab = &rdev->wiphy.iftype_ext_capab[i];
1948
1949 nested_ext_capab = nla_nest_start(msg, i);
1950 if (!nested_ext_capab ||
1951 nla_put_u32(msg, NL80211_ATTR_IFTYPE,
1952 capab->iftype) ||
1953 nla_put(msg, NL80211_ATTR_EXT_CAPA,
1954 capab->extended_capabilities_len,
1955 capab->extended_capabilities) ||
1956 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
1957 capab->extended_capabilities_len,
1958 capab->extended_capabilities_mask))
1959 goto nla_put_failure;
1960
1961 nla_nest_end(msg, nested_ext_capab);
1962 if (state->split)
1963 break;
1964 }
1965 nla_nest_end(msg, nested);
1966 if (i < rdev->wiphy.num_iftype_ext_capab) {
1967 state->capa_start = i + 1;
1968 break;
1969 }
1970 }
1971
Luca Coelho85859892017-02-08 15:00:34 +02001972 if (nla_put_u32(msg, NL80211_ATTR_BANDS,
1973 rdev->wiphy.nan_supported_bands))
1974 goto nla_put_failure;
1975
Johannes Berg3713b4e2013-02-14 16:19:38 +01001976 /* done */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001977 state->split_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001978 break;
Johannes Bergff1b6e62011-05-04 15:37:28 +02001979 }
Johannes Berg3bb20552014-05-26 13:52:25 +02001980 finish:
Johannes Berg053c0952015-01-16 22:09:00 +01001981 genlmsg_end(msg, hdr);
1982 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04001983
1984 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001985 genlmsg_cancel(msg, hdr);
1986 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04001987}
1988
Johannes Berg86e8cf92013-06-19 10:57:22 +02001989static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
1990 struct netlink_callback *cb,
1991 struct nl80211_dump_wiphy_state *state)
1992{
Johannes Bergc90c39d2016-10-24 14:40:01 +02001993 struct nlattr **tb = genl_family_attrbuf(&nl80211_fam);
Johannes Bergfceb6432017-04-12 14:34:07 +02001994 int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, tb,
1995 nl80211_fam.maxattr, nl80211_policy, NULL);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001996 /* ignore parse errors for backward compatibility */
1997 if (ret)
1998 return 0;
1999
2000 state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
2001 if (tb[NL80211_ATTR_WIPHY])
2002 state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
2003 if (tb[NL80211_ATTR_WDEV])
2004 state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
2005 if (tb[NL80211_ATTR_IFINDEX]) {
2006 struct net_device *netdev;
2007 struct cfg80211_registered_device *rdev;
2008 int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2009
Ying Xue7f2b8562014-01-15 10:23:45 +08002010 netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
Johannes Berg86e8cf92013-06-19 10:57:22 +02002011 if (!netdev)
2012 return -ENODEV;
2013 if (netdev->ieee80211_ptr) {
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002014 rdev = wiphy_to_rdev(
Johannes Berg86e8cf92013-06-19 10:57:22 +02002015 netdev->ieee80211_ptr->wiphy);
2016 state->filter_wiphy = rdev->wiphy_idx;
2017 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002018 }
2019
2020 return 0;
2021}
2022
Johannes Berg55682962007-09-20 13:09:35 -04002023static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
2024{
Johannes Berg645e77d2013-03-01 14:03:49 +01002025 int idx = 0, ret;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002026 struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002027 struct cfg80211_registered_device *rdev;
Johannes Berg3a5a4232013-06-19 10:09:57 +02002028
Johannes Berg5fe231e2013-05-08 21:45:15 +02002029 rtnl_lock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02002030 if (!state) {
2031 state = kzalloc(sizeof(*state), GFP_KERNEL);
John W. Linville57ed5cd2013-06-28 13:18:21 -04002032 if (!state) {
2033 rtnl_unlock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02002034 return -ENOMEM;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002035 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002036 state->filter_wiphy = -1;
2037 ret = nl80211_dump_wiphy_parse(skb, cb, state);
2038 if (ret) {
2039 kfree(state);
2040 rtnl_unlock();
2041 return ret;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002042 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002043 cb->args[0] = (long)state;
Johannes Berg3713b4e2013-02-14 16:19:38 +01002044 }
2045
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002046 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2047 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02002048 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002049 if (++idx <= state->start)
Johannes Berg55682962007-09-20 13:09:35 -04002050 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02002051 if (state->filter_wiphy != -1 &&
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002052 state->filter_wiphy != rdev->wiphy_idx)
Johannes Berg3713b4e2013-02-14 16:19:38 +01002053 continue;
2054 /* attempt to fit multiple wiphy data chunks into the skb */
2055 do {
Johannes Berg3bb20552014-05-26 13:52:25 +02002056 ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY,
2057 skb,
Johannes Berg3713b4e2013-02-14 16:19:38 +01002058 NETLINK_CB(cb->skb).portid,
2059 cb->nlh->nlmsg_seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002060 NLM_F_MULTI, state);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002061 if (ret < 0) {
2062 /*
2063 * If sending the wiphy data didn't fit (ENOBUFS
2064 * or EMSGSIZE returned), this SKB is still
2065 * empty (so it's not too big because another
2066 * wiphy dataset is already in the skb) and
2067 * we've not tried to adjust the dump allocation
2068 * yet ... then adjust the alloc size to be
2069 * bigger, and return 1 but with the empty skb.
2070 * This results in an empty message being RX'ed
2071 * in userspace, but that is ignored.
2072 *
2073 * We can then retry with the larger buffer.
2074 */
2075 if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
Pontus Fuchsf12cb282014-01-16 15:00:40 +01002076 !skb->len && !state->split &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002077 cb->min_dump_alloc < 4096) {
2078 cb->min_dump_alloc = 4096;
Pontus Fuchsf12cb282014-01-16 15:00:40 +01002079 state->split_start = 0;
David S. Millerd98cae64e2013-06-19 16:49:39 -07002080 rtnl_unlock();
Johannes Berg3713b4e2013-02-14 16:19:38 +01002081 return 1;
2082 }
2083 idx--;
2084 break;
Johannes Berg645e77d2013-03-01 14:03:49 +01002085 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002086 } while (state->split_start > 0);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002087 break;
Johannes Berg55682962007-09-20 13:09:35 -04002088 }
Johannes Berg5fe231e2013-05-08 21:45:15 +02002089 rtnl_unlock();
Johannes Berg55682962007-09-20 13:09:35 -04002090
Johannes Berg86e8cf92013-06-19 10:57:22 +02002091 state->start = idx;
Johannes Berg55682962007-09-20 13:09:35 -04002092
2093 return skb->len;
2094}
2095
Johannes Berg86e8cf92013-06-19 10:57:22 +02002096static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
2097{
2098 kfree((void *)cb->args[0]);
2099 return 0;
2100}
2101
Johannes Berg55682962007-09-20 13:09:35 -04002102static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
2103{
2104 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002105 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg86e8cf92013-06-19 10:57:22 +02002106 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -04002107
Johannes Berg645e77d2013-03-01 14:03:49 +01002108 msg = nlmsg_new(4096, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002109 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002110 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002111
Johannes Berg3bb20552014-05-26 13:52:25 +02002112 if (nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY, msg,
2113 info->snd_portid, info->snd_seq, 0,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002114 &state) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002115 nlmsg_free(msg);
2116 return -ENOBUFS;
2117 }
Johannes Berg55682962007-09-20 13:09:35 -04002118
Johannes Berg134e6372009-07-10 09:51:34 +00002119 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002120}
2121
Jouni Malinen31888482008-10-30 16:59:24 +02002122static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
2123 [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 },
2124 [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 },
2125 [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 },
2126 [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 },
2127 [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 },
2128};
2129
2130static int parse_txq_params(struct nlattr *tb[],
2131 struct ieee80211_txq_params *txq_params)
2132{
Dan Williams259d8c12018-01-29 17:03:15 -08002133 u8 ac;
2134
Johannes Berga3304b02012-03-28 11:04:24 +02002135 if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
Jouni Malinen31888482008-10-30 16:59:24 +02002136 !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
2137 !tb[NL80211_TXQ_ATTR_AIFS])
2138 return -EINVAL;
2139
Dan Williams259d8c12018-01-29 17:03:15 -08002140 ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
Jouni Malinen31888482008-10-30 16:59:24 +02002141 txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
2142 txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
2143 txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
2144 txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
2145
Dan Williams259d8c12018-01-29 17:03:15 -08002146 if (ac >= NL80211_NUM_ACS)
Johannes Berga3304b02012-03-28 11:04:24 +02002147 return -EINVAL;
Dan Williams259d8c12018-01-29 17:03:15 -08002148 txq_params->ac = array_index_nospec(ac, NL80211_NUM_ACS);
Jouni Malinen31888482008-10-30 16:59:24 +02002149 return 0;
2150}
2151
Johannes Bergf444de02010-05-05 15:25:02 +02002152static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
2153{
2154 /*
Johannes Bergcc1d2802012-05-16 23:50:20 +02002155 * You can only set the channel explicitly for WDS interfaces,
2156 * all others have their channel managed via their respective
2157 * "establish a connection" command (connect, join, ...)
2158 *
2159 * For AP/GO and mesh mode, the channel can be set with the
2160 * channel userspace API, but is only stored and passed to the
2161 * low-level driver when the AP starts or the mesh is joined.
2162 * This is for backward compatibility, userspace can also give
2163 * the channel in the start-ap or join-mesh commands instead.
Johannes Bergf444de02010-05-05 15:25:02 +02002164 *
2165 * Monitors are special as they are normally slaved to
Johannes Berge8c9bd52012-06-06 08:18:22 +02002166 * whatever else is going on, so they have their own special
2167 * operation to set the monitor channel if possible.
Johannes Bergf444de02010-05-05 15:25:02 +02002168 */
2169 return !wdev ||
2170 wdev->iftype == NL80211_IFTYPE_AP ||
Johannes Bergf444de02010-05-05 15:25:02 +02002171 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
Johannes Berg074ac8d2010-09-16 14:58:22 +02002172 wdev->iftype == NL80211_IFTYPE_MONITOR ||
2173 wdev->iftype == NL80211_IFTYPE_P2P_GO;
Johannes Bergf444de02010-05-05 15:25:02 +02002174}
2175
Johannes Berg683b6d32012-11-08 21:25:48 +01002176static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
2177 struct genl_info *info,
2178 struct cfg80211_chan_def *chandef)
2179{
Mahesh Paliveladbeca2e2012-11-29 14:11:07 +05302180 u32 control_freq;
Johannes Berg683b6d32012-11-08 21:25:48 +01002181
2182 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
2183 return -EINVAL;
2184
2185 control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
2186
2187 chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002188 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
2189 chandef->center_freq1 = control_freq;
2190 chandef->center_freq2 = 0;
Johannes Berg683b6d32012-11-08 21:25:48 +01002191
2192 /* Primary channel not allowed */
2193 if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
2194 return -EINVAL;
2195
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002196 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
2197 enum nl80211_channel_type chantype;
Johannes Berg683b6d32012-11-08 21:25:48 +01002198
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002199 chantype = nla_get_u32(
2200 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
2201
2202 switch (chantype) {
2203 case NL80211_CHAN_NO_HT:
2204 case NL80211_CHAN_HT20:
2205 case NL80211_CHAN_HT40PLUS:
2206 case NL80211_CHAN_HT40MINUS:
2207 cfg80211_chandef_create(chandef, chandef->chan,
2208 chantype);
Tova Mussaiffa46292017-08-05 11:44:38 +03002209 /* user input for center_freq is incorrect */
2210 if (info->attrs[NL80211_ATTR_CENTER_FREQ1] &&
2211 chandef->center_freq1 != nla_get_u32(
2212 info->attrs[NL80211_ATTR_CENTER_FREQ1]))
2213 return -EINVAL;
2214 /* center_freq2 must be zero */
2215 if (info->attrs[NL80211_ATTR_CENTER_FREQ2] &&
2216 nla_get_u32(info->attrs[NL80211_ATTR_CENTER_FREQ2]))
2217 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002218 break;
2219 default:
Johannes Berg683b6d32012-11-08 21:25:48 +01002220 return -EINVAL;
Johannes Berg683b6d32012-11-08 21:25:48 +01002221 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002222 } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
2223 chandef->width =
2224 nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
2225 if (info->attrs[NL80211_ATTR_CENTER_FREQ1])
2226 chandef->center_freq1 =
2227 nla_get_u32(
2228 info->attrs[NL80211_ATTR_CENTER_FREQ1]);
2229 if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
2230 chandef->center_freq2 =
2231 nla_get_u32(
2232 info->attrs[NL80211_ATTR_CENTER_FREQ2]);
2233 }
2234
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002235 if (!cfg80211_chandef_valid(chandef))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002236 return -EINVAL;
2237
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002238 if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
2239 IEEE80211_CHAN_DISABLED))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002240 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002241
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02002242 if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
2243 chandef->width == NL80211_CHAN_WIDTH_10) &&
2244 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
2245 return -EINVAL;
2246
Johannes Berg683b6d32012-11-08 21:25:48 +01002247 return 0;
2248}
2249
Johannes Bergf444de02010-05-05 15:25:02 +02002250static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
Jouni Malinene16821b2014-04-28 11:22:08 +03002251 struct net_device *dev,
Johannes Bergf444de02010-05-05 15:25:02 +02002252 struct genl_info *info)
2253{
Johannes Berg683b6d32012-11-08 21:25:48 +01002254 struct cfg80211_chan_def chandef;
Johannes Bergf444de02010-05-05 15:25:02 +02002255 int result;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002256 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
Jouni Malinene16821b2014-04-28 11:22:08 +03002257 struct wireless_dev *wdev = NULL;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002258
Jouni Malinene16821b2014-04-28 11:22:08 +03002259 if (dev)
2260 wdev = dev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002261 if (!nl80211_can_set_dev_channel(wdev))
2262 return -EOPNOTSUPP;
Jouni Malinene16821b2014-04-28 11:22:08 +03002263 if (wdev)
2264 iftype = wdev->iftype;
Johannes Bergf444de02010-05-05 15:25:02 +02002265
Johannes Berg683b6d32012-11-08 21:25:48 +01002266 result = nl80211_parse_chandef(rdev, info, &chandef);
2267 if (result)
2268 return result;
Johannes Bergf444de02010-05-05 15:25:02 +02002269
Johannes Berge8c9bd52012-06-06 08:18:22 +02002270 switch (iftype) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002271 case NL80211_IFTYPE_AP:
2272 case NL80211_IFTYPE_P2P_GO:
Arik Nemtsov923b3522015-07-08 15:41:44 +03002273 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
2274 iftype)) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002275 result = -EINVAL;
2276 break;
2277 }
Jouni Malinene16821b2014-04-28 11:22:08 +03002278 if (wdev->beacon_interval) {
2279 if (!dev || !rdev->ops->set_ap_chanwidth ||
2280 !(rdev->wiphy.features &
2281 NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
2282 result = -EBUSY;
2283 break;
2284 }
2285
2286 /* Only allow dynamic channel width changes */
2287 if (chandef.chan != wdev->preset_chandef.chan) {
2288 result = -EBUSY;
2289 break;
2290 }
2291 result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
2292 if (result)
2293 break;
2294 }
Johannes Berg683b6d32012-11-08 21:25:48 +01002295 wdev->preset_chandef = chandef;
Johannes Bergaa430da2012-05-16 23:50:18 +02002296 result = 0;
2297 break;
Johannes Bergcc1d2802012-05-16 23:50:20 +02002298 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg683b6d32012-11-08 21:25:48 +01002299 result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
Johannes Bergcc1d2802012-05-16 23:50:20 +02002300 break;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002301 case NL80211_IFTYPE_MONITOR:
Johannes Berg683b6d32012-11-08 21:25:48 +01002302 result = cfg80211_set_monitor_channel(rdev, &chandef);
Johannes Berge8c9bd52012-06-06 08:18:22 +02002303 break;
Johannes Bergaa430da2012-05-16 23:50:18 +02002304 default:
Johannes Berge8c9bd52012-06-06 08:18:22 +02002305 result = -EINVAL;
Johannes Bergf444de02010-05-05 15:25:02 +02002306 }
Johannes Bergf444de02010-05-05 15:25:02 +02002307
2308 return result;
2309}
2310
2311static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
2312{
Johannes Berg4c476992010-10-04 21:36:35 +02002313 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2314 struct net_device *netdev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02002315
Jouni Malinene16821b2014-04-28 11:22:08 +03002316 return __nl80211_set_channel(rdev, netdev, info);
Johannes Bergf444de02010-05-05 15:25:02 +02002317}
2318
Bill Jordane8347eb2010-10-01 13:54:28 -04002319static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
2320{
Johannes Berg43b19952010-10-07 13:10:30 +02002321 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2322 struct net_device *dev = info->user_ptr[1];
2323 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg388ac772010-10-07 13:11:09 +02002324 const u8 *bssid;
Bill Jordane8347eb2010-10-01 13:54:28 -04002325
2326 if (!info->attrs[NL80211_ATTR_MAC])
2327 return -EINVAL;
2328
Johannes Berg43b19952010-10-07 13:10:30 +02002329 if (netif_running(dev))
2330 return -EBUSY;
Bill Jordane8347eb2010-10-01 13:54:28 -04002331
Johannes Berg43b19952010-10-07 13:10:30 +02002332 if (!rdev->ops->set_wds_peer)
2333 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002334
Johannes Berg43b19952010-10-07 13:10:30 +02002335 if (wdev->iftype != NL80211_IFTYPE_WDS)
2336 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002337
2338 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Hila Gonene35e4d22012-06-27 17:19:42 +03002339 return rdev_set_wds_peer(rdev, dev, bssid);
Bill Jordane8347eb2010-10-01 13:54:28 -04002340}
2341
Johannes Berg55682962007-09-20 13:09:35 -04002342static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
2343{
2344 struct cfg80211_registered_device *rdev;
Johannes Bergf444de02010-05-05 15:25:02 +02002345 struct net_device *netdev = NULL;
2346 struct wireless_dev *wdev;
Bill Jordana1e567c2010-09-10 11:22:32 -04002347 int result = 0, rem_txq_params = 0;
Jouni Malinen31888482008-10-30 16:59:24 +02002348 struct nlattr *nl_txq_params;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002349 u32 changed;
2350 u8 retry_short = 0, retry_long = 0;
2351 u32 frag_threshold = 0, rts_threshold = 0;
Lukáš Turek81077e82009-12-21 22:50:47 +01002352 u8 coverage_class = 0;
Johannes Berg55682962007-09-20 13:09:35 -04002353
Johannes Berg5fe231e2013-05-08 21:45:15 +02002354 ASSERT_RTNL();
2355
Johannes Bergf444de02010-05-05 15:25:02 +02002356 /*
2357 * Try to find the wiphy and netdev. Normally this
2358 * function shouldn't need the netdev, but this is
2359 * done for backward compatibility -- previously
2360 * setting the channel was done per wiphy, but now
2361 * it is per netdev. Previous userland like hostapd
2362 * also passed a netdev to set_wiphy, so that it is
2363 * possible to let that go to the right netdev!
2364 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002365
Johannes Bergf444de02010-05-05 15:25:02 +02002366 if (info->attrs[NL80211_ATTR_IFINDEX]) {
2367 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
2368
Ying Xue7f2b8562014-01-15 10:23:45 +08002369 netdev = __dev_get_by_index(genl_info_net(info), ifindex);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002370 if (netdev && netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002371 rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002372 else
Johannes Bergf444de02010-05-05 15:25:02 +02002373 netdev = NULL;
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002374 }
2375
Johannes Bergf444de02010-05-05 15:25:02 +02002376 if (!netdev) {
Johannes Berg878d9ec2012-06-15 14:18:32 +02002377 rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
2378 info->attrs);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002379 if (IS_ERR(rdev))
Johannes Berg4c476992010-10-04 21:36:35 +02002380 return PTR_ERR(rdev);
Johannes Bergf444de02010-05-05 15:25:02 +02002381 wdev = NULL;
2382 netdev = NULL;
2383 result = 0;
Johannes Berg71fe96b2012-10-24 10:04:58 +02002384 } else
Johannes Bergf444de02010-05-05 15:25:02 +02002385 wdev = netdev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002386
2387 /*
2388 * end workaround code, by now the rdev is available
2389 * and locked, and wdev may or may not be NULL.
2390 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002391
2392 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
Jouni Malinen31888482008-10-30 16:59:24 +02002393 result = cfg80211_dev_rename(
2394 rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002395
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002396 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002397 return result;
Johannes Berg55682962007-09-20 13:09:35 -04002398
Jouni Malinen31888482008-10-30 16:59:24 +02002399 if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
2400 struct ieee80211_txq_params txq_params;
2401 struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
2402
Ying Xue7f2b8562014-01-15 10:23:45 +08002403 if (!rdev->ops->set_txq_params)
2404 return -EOPNOTSUPP;
Jouni Malinen31888482008-10-30 16:59:24 +02002405
Ying Xue7f2b8562014-01-15 10:23:45 +08002406 if (!netdev)
2407 return -EINVAL;
Eliad Pellerf70f01c2011-09-25 20:06:53 +03002408
Johannes Berg133a3ff2011-11-03 14:50:13 +01002409 if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002410 netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2411 return -EINVAL;
Johannes Berg133a3ff2011-11-03 14:50:13 +01002412
Ying Xue7f2b8562014-01-15 10:23:45 +08002413 if (!netif_running(netdev))
2414 return -ENETDOWN;
Johannes Berg2b5f8b02012-04-02 10:51:55 +02002415
Jouni Malinen31888482008-10-30 16:59:24 +02002416 nla_for_each_nested(nl_txq_params,
2417 info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
2418 rem_txq_params) {
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02002419 result = nla_parse_nested(tb, NL80211_TXQ_ATTR_MAX,
2420 nl_txq_params,
Johannes Bergfe521452017-04-12 14:34:08 +02002421 txq_params_policy,
2422 info->extack);
Johannes Bergae811e22014-01-24 10:17:47 +01002423 if (result)
2424 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002425 result = parse_txq_params(tb, &txq_params);
2426 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002427 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002428
Hila Gonene35e4d22012-06-27 17:19:42 +03002429 result = rdev_set_txq_params(rdev, netdev,
2430 &txq_params);
Jouni Malinen31888482008-10-30 16:59:24 +02002431 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002432 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002433 }
2434 }
2435
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002436 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinene16821b2014-04-28 11:22:08 +03002437 result = __nl80211_set_channel(
2438 rdev,
2439 nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
2440 info);
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002441 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002442 return result;
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002443 }
2444
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002445 if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
Johannes Bergc8442112012-10-24 10:17:18 +02002446 struct wireless_dev *txp_wdev = wdev;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002447 enum nl80211_tx_power_setting type;
2448 int idx, mbm = 0;
2449
Johannes Bergc8442112012-10-24 10:17:18 +02002450 if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
2451 txp_wdev = NULL;
2452
Ying Xue7f2b8562014-01-15 10:23:45 +08002453 if (!rdev->ops->set_tx_power)
2454 return -EOPNOTSUPP;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002455
2456 idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
2457 type = nla_get_u32(info->attrs[idx]);
2458
2459 if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002460 (type != NL80211_TX_POWER_AUTOMATIC))
2461 return -EINVAL;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002462
2463 if (type != NL80211_TX_POWER_AUTOMATIC) {
2464 idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
2465 mbm = nla_get_u32(info->attrs[idx]);
2466 }
2467
Johannes Bergc8442112012-10-24 10:17:18 +02002468 result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002469 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002470 return result;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002471 }
2472
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002473 if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
2474 info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
2475 u32 tx_ant, rx_ant;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07002476
Bruno Randolf7f531e02010-12-16 11:30:22 +09002477 if ((!rdev->wiphy.available_antennas_tx &&
2478 !rdev->wiphy.available_antennas_rx) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002479 !rdev->ops->set_antenna)
2480 return -EOPNOTSUPP;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002481
2482 tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
2483 rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
2484
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002485 /* reject antenna configurations which don't match the
Bruno Randolf7f531e02010-12-16 11:30:22 +09002486 * available antenna masks, except for the "all" mask */
2487 if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002488 (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
2489 return -EINVAL;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002490
Bruno Randolf7f531e02010-12-16 11:30:22 +09002491 tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
2492 rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002493
Hila Gonene35e4d22012-06-27 17:19:42 +03002494 result = rdev_set_antenna(rdev, tx_ant, rx_ant);
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002495 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002496 return result;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002497 }
2498
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002499 changed = 0;
2500
2501 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
2502 retry_short = nla_get_u8(
2503 info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002504 if (retry_short == 0)
2505 return -EINVAL;
2506
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002507 changed |= WIPHY_PARAM_RETRY_SHORT;
2508 }
2509
2510 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
2511 retry_long = nla_get_u8(
2512 info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002513 if (retry_long == 0)
2514 return -EINVAL;
2515
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002516 changed |= WIPHY_PARAM_RETRY_LONG;
2517 }
2518
2519 if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
2520 frag_threshold = nla_get_u32(
2521 info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002522 if (frag_threshold < 256)
2523 return -EINVAL;
2524
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002525 if (frag_threshold != (u32) -1) {
2526 /*
2527 * Fragments (apart from the last one) are required to
2528 * have even length. Make the fragmentation code
2529 * simpler by stripping LSB should someone try to use
2530 * odd threshold value.
2531 */
2532 frag_threshold &= ~0x1;
2533 }
2534 changed |= WIPHY_PARAM_FRAG_THRESHOLD;
2535 }
2536
2537 if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
2538 rts_threshold = nla_get_u32(
2539 info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
2540 changed |= WIPHY_PARAM_RTS_THRESHOLD;
2541 }
2542
Lukáš Turek81077e82009-12-21 22:50:47 +01002543 if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002544 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK])
2545 return -EINVAL;
2546
Lukáš Turek81077e82009-12-21 22:50:47 +01002547 coverage_class = nla_get_u8(
2548 info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
2549 changed |= WIPHY_PARAM_COVERAGE_CLASS;
2550 }
2551
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002552 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
2553 if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION))
2554 return -EOPNOTSUPP;
2555
2556 changed |= WIPHY_PARAM_DYN_ACK;
2557 }
2558
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002559 if (changed) {
2560 u8 old_retry_short, old_retry_long;
2561 u32 old_frag_threshold, old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002562 u8 old_coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002563
Ying Xue7f2b8562014-01-15 10:23:45 +08002564 if (!rdev->ops->set_wiphy_params)
2565 return -EOPNOTSUPP;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002566
2567 old_retry_short = rdev->wiphy.retry_short;
2568 old_retry_long = rdev->wiphy.retry_long;
2569 old_frag_threshold = rdev->wiphy.frag_threshold;
2570 old_rts_threshold = rdev->wiphy.rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002571 old_coverage_class = rdev->wiphy.coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002572
2573 if (changed & WIPHY_PARAM_RETRY_SHORT)
2574 rdev->wiphy.retry_short = retry_short;
2575 if (changed & WIPHY_PARAM_RETRY_LONG)
2576 rdev->wiphy.retry_long = retry_long;
2577 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
2578 rdev->wiphy.frag_threshold = frag_threshold;
2579 if (changed & WIPHY_PARAM_RTS_THRESHOLD)
2580 rdev->wiphy.rts_threshold = rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002581 if (changed & WIPHY_PARAM_COVERAGE_CLASS)
2582 rdev->wiphy.coverage_class = coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002583
Hila Gonene35e4d22012-06-27 17:19:42 +03002584 result = rdev_set_wiphy_params(rdev, changed);
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002585 if (result) {
2586 rdev->wiphy.retry_short = old_retry_short;
2587 rdev->wiphy.retry_long = old_retry_long;
2588 rdev->wiphy.frag_threshold = old_frag_threshold;
2589 rdev->wiphy.rts_threshold = old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002590 rdev->wiphy.coverage_class = old_coverage_class;
Michal Kazior9189ee32015-08-03 10:55:24 +02002591 return result;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002592 }
2593 }
Ying Xue7f2b8562014-01-15 10:23:45 +08002594 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002595}
2596
Johannes Berg71bbc992012-06-15 15:30:18 +02002597static inline u64 wdev_id(struct wireless_dev *wdev)
2598{
2599 return (u64)wdev->identifier |
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002600 ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
Johannes Berg71bbc992012-06-15 15:30:18 +02002601}
Johannes Berg55682962007-09-20 13:09:35 -04002602
Johannes Berg683b6d32012-11-08 21:25:48 +01002603static int nl80211_send_chandef(struct sk_buff *msg,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01002604 const struct cfg80211_chan_def *chandef)
Johannes Berg683b6d32012-11-08 21:25:48 +01002605{
Johannes Berg601555c2014-11-27 17:26:56 +01002606 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
2607 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002608
Johannes Berg683b6d32012-11-08 21:25:48 +01002609 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
2610 chandef->chan->center_freq))
2611 return -ENOBUFS;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002612 switch (chandef->width) {
2613 case NL80211_CHAN_WIDTH_20_NOHT:
2614 case NL80211_CHAN_WIDTH_20:
2615 case NL80211_CHAN_WIDTH_40:
2616 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
2617 cfg80211_get_chandef_type(chandef)))
2618 return -ENOBUFS;
2619 break;
2620 default:
2621 break;
2622 }
2623 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
2624 return -ENOBUFS;
2625 if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
2626 return -ENOBUFS;
2627 if (chandef->center_freq2 &&
2628 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
Johannes Berg683b6d32012-11-08 21:25:48 +01002629 return -ENOBUFS;
2630 return 0;
2631}
2632
Eric W. Biederman15e47302012-09-07 20:12:54 +00002633static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
Johannes Bergd7264052009-04-19 16:23:20 +02002634 struct cfg80211_registered_device *rdev,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002635 struct wireless_dev *wdev, bool removal)
Johannes Berg55682962007-09-20 13:09:35 -04002636{
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002637 struct net_device *dev = wdev->netdev;
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002638 u8 cmd = NL80211_CMD_NEW_INTERFACE;
Johannes Berg55682962007-09-20 13:09:35 -04002639 void *hdr;
2640
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002641 if (removal)
2642 cmd = NL80211_CMD_DEL_INTERFACE;
2643
2644 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04002645 if (!hdr)
2646 return -1;
2647
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002648 if (dev &&
2649 (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002650 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002651 goto nla_put_failure;
2652
2653 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
2654 nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02002655 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
2656 NL80211_ATTR_PAD) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002657 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04002658 nla_put_u32(msg, NL80211_ATTR_GENERATION,
2659 rdev->devlist_generation ^
2660 (cfg80211_rdev_list_generation << 2)))
2661 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002662
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002663 if (rdev->ops->get_channel) {
Johannes Berg683b6d32012-11-08 21:25:48 +01002664 int ret;
2665 struct cfg80211_chan_def chandef;
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002666
Johannes Berg683b6d32012-11-08 21:25:48 +01002667 ret = rdev_get_channel(rdev, wdev, &chandef);
2668 if (ret == 0) {
2669 if (nl80211_send_chandef(msg, &chandef))
2670 goto nla_put_failure;
2671 }
Pontus Fuchsd91df0e2012-04-03 16:39:58 +02002672 }
2673
Rafał Miłeckid55d0d52015-08-31 22:59:38 +02002674 if (rdev->ops->get_tx_power) {
2675 int dbm, ret;
2676
2677 ret = rdev_get_tx_power(rdev, wdev, &dbm);
2678 if (ret == 0 &&
2679 nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
2680 DBM_TO_MBM(dbm)))
2681 goto nla_put_failure;
2682 }
2683
Johannes Berg44905262017-10-17 21:56:01 +02002684 wdev_lock(wdev);
2685 switch (wdev->iftype) {
2686 case NL80211_IFTYPE_AP:
2687 if (wdev->ssid_len &&
2688 nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
Johannes Berg4564b182017-12-11 12:33:47 +01002689 goto nla_put_failure_locked;
Johannes Berg44905262017-10-17 21:56:01 +02002690 break;
2691 case NL80211_IFTYPE_STATION:
2692 case NL80211_IFTYPE_P2P_CLIENT:
2693 case NL80211_IFTYPE_ADHOC: {
2694 const u8 *ssid_ie;
2695 if (!wdev->current_bss)
2696 break;
Dominik Brodowski7a94b8c2018-01-15 08:12:15 +01002697 rcu_read_lock();
Johannes Berg44905262017-10-17 21:56:01 +02002698 ssid_ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
2699 WLAN_EID_SSID);
Dominik Brodowski7a94b8c2018-01-15 08:12:15 +01002700 if (ssid_ie &&
2701 nla_put(msg, NL80211_ATTR_SSID, ssid_ie[1], ssid_ie + 2))
2702 goto nla_put_failure_rcu_locked;
2703 rcu_read_unlock();
Johannes Berg44905262017-10-17 21:56:01 +02002704 break;
2705 }
2706 default:
2707 /* nothing */
2708 break;
Antonio Quartullib84e7a02012-11-07 12:52:20 +01002709 }
Johannes Berg44905262017-10-17 21:56:01 +02002710 wdev_unlock(wdev);
Antonio Quartullib84e7a02012-11-07 12:52:20 +01002711
Johannes Berg053c0952015-01-16 22:09:00 +01002712 genlmsg_end(msg, hdr);
2713 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002714
Dominik Brodowski7a94b8c2018-01-15 08:12:15 +01002715 nla_put_failure_rcu_locked:
2716 rcu_read_unlock();
Johannes Berg4564b182017-12-11 12:33:47 +01002717 nla_put_failure_locked:
2718 wdev_unlock(wdev);
Johannes Berg55682962007-09-20 13:09:35 -04002719 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002720 genlmsg_cancel(msg, hdr);
2721 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04002722}
2723
2724static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
2725{
2726 int wp_idx = 0;
2727 int if_idx = 0;
2728 int wp_start = cb->args[0];
2729 int if_start = cb->args[1];
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002730 int filter_wiphy = -1;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002731 struct cfg80211_registered_device *rdev;
Johannes Berg55682962007-09-20 13:09:35 -04002732 struct wireless_dev *wdev;
Johannes Bergea90e0d2017-03-15 14:26:04 +01002733 int ret;
Johannes Berg55682962007-09-20 13:09:35 -04002734
Johannes Berg5fe231e2013-05-08 21:45:15 +02002735 rtnl_lock();
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002736 if (!cb->args[2]) {
2737 struct nl80211_dump_wiphy_state state = {
2738 .filter_wiphy = -1,
2739 };
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002740
2741 ret = nl80211_dump_wiphy_parse(skb, cb, &state);
2742 if (ret)
Johannes Bergea90e0d2017-03-15 14:26:04 +01002743 goto out_unlock;
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002744
2745 filter_wiphy = state.filter_wiphy;
2746
2747 /*
2748 * if filtering, set cb->args[2] to +1 since 0 is the default
2749 * value needed to determine that parsing is necessary.
2750 */
2751 if (filter_wiphy >= 0)
2752 cb->args[2] = filter_wiphy + 1;
2753 else
2754 cb->args[2] = -1;
2755 } else if (cb->args[2] > 0) {
2756 filter_wiphy = cb->args[2] - 1;
2757 }
2758
Johannes Bergf5ea9122009-08-07 16:17:38 +02002759 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2760 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02002761 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002762 if (wp_idx < wp_start) {
2763 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002764 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002765 }
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002766
2767 if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx)
2768 continue;
2769
Johannes Berg55682962007-09-20 13:09:35 -04002770 if_idx = 0;
2771
Johannes Berg53873f12016-05-03 16:52:04 +03002772 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002773 if (if_idx < if_start) {
2774 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002775 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002776 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002777 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
Johannes Berg55682962007-09-20 13:09:35 -04002778 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002779 rdev, wdev, false) < 0) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002780 goto out;
2781 }
2782 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002783 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002784
2785 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002786 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002787 out:
Johannes Berg55682962007-09-20 13:09:35 -04002788 cb->args[0] = wp_idx;
2789 cb->args[1] = if_idx;
2790
Johannes Bergea90e0d2017-03-15 14:26:04 +01002791 ret = skb->len;
2792 out_unlock:
2793 rtnl_unlock();
2794
2795 return ret;
Johannes Berg55682962007-09-20 13:09:35 -04002796}
2797
2798static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
2799{
2800 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002801 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002802 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04002803
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07002804 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002805 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002806 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002807
Eric W. Biederman15e47302012-09-07 20:12:54 +00002808 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002809 rdev, wdev, false) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002810 nlmsg_free(msg);
2811 return -ENOBUFS;
2812 }
Johannes Berg55682962007-09-20 13:09:35 -04002813
Johannes Berg134e6372009-07-10 09:51:34 +00002814 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002815}
2816
Michael Wu66f7ac52008-01-31 19:48:22 +01002817static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
2818 [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
2819 [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
2820 [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
2821 [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
2822 [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002823 [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
Michael Wu66f7ac52008-01-31 19:48:22 +01002824};
2825
2826static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
2827{
2828 struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
2829 int flag;
2830
2831 *mntrflags = 0;
2832
2833 if (!nla)
2834 return -EINVAL;
2835
Johannes Bergfceb6432017-04-12 14:34:07 +02002836 if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, nla,
2837 mntr_flags_policy, NULL))
Michael Wu66f7ac52008-01-31 19:48:22 +01002838 return -EINVAL;
2839
2840 for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
2841 if (flags[flag])
2842 *mntrflags |= (1<<flag);
2843
Johannes Berg818a9862017-04-12 11:23:28 +02002844 *mntrflags |= MONITOR_FLAG_CHANGED;
2845
Michael Wu66f7ac52008-01-31 19:48:22 +01002846 return 0;
2847}
2848
Johannes Berg1db77592017-04-12 11:36:31 +02002849static int nl80211_parse_mon_options(struct cfg80211_registered_device *rdev,
2850 enum nl80211_iftype type,
2851 struct genl_info *info,
2852 struct vif_params *params)
2853{
2854 bool change = false;
2855 int err;
2856
2857 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
2858 if (type != NL80211_IFTYPE_MONITOR)
2859 return -EINVAL;
2860
2861 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
2862 &params->flags);
2863 if (err)
2864 return err;
2865
2866 change = true;
2867 }
2868
2869 if (params->flags & MONITOR_FLAG_ACTIVE &&
2870 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2871 return -EOPNOTSUPP;
2872
2873 if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
2874 const u8 *mumimo_groups;
2875 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2876
2877 if (type != NL80211_IFTYPE_MONITOR)
2878 return -EINVAL;
2879
2880 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2881 return -EOPNOTSUPP;
2882
2883 mumimo_groups =
2884 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
2885
2886 /* bits 0 and 63 are reserved and must be zero */
Johannes Berg49546012017-04-27 09:13:38 +02002887 if ((mumimo_groups[0] & BIT(0)) ||
2888 (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(7)))
Johannes Berg1db77592017-04-12 11:36:31 +02002889 return -EINVAL;
2890
2891 params->vht_mumimo_groups = mumimo_groups;
2892 change = true;
2893 }
2894
2895 if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
2896 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2897
2898 if (type != NL80211_IFTYPE_MONITOR)
2899 return -EINVAL;
2900
2901 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2902 return -EOPNOTSUPP;
2903
2904 params->vht_mumimo_follow_addr =
2905 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]);
2906 change = true;
2907 }
2908
2909 return change ? 1 : 0;
2910}
2911
Johannes Berg9bc383d2009-11-19 11:55:19 +01002912static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002913 struct net_device *netdev, u8 use_4addr,
2914 enum nl80211_iftype iftype)
Johannes Berg9bc383d2009-11-19 11:55:19 +01002915{
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002916 if (!use_4addr) {
Jiri Pirkof350a0a82010-06-15 06:50:45 +00002917 if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002918 return -EBUSY;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002919 return 0;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002920 }
Johannes Berg9bc383d2009-11-19 11:55:19 +01002921
2922 switch (iftype) {
2923 case NL80211_IFTYPE_AP_VLAN:
2924 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
2925 return 0;
2926 break;
2927 case NL80211_IFTYPE_STATION:
2928 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
2929 return 0;
2930 break;
2931 default:
2932 break;
2933 }
2934
2935 return -EOPNOTSUPP;
2936}
2937
Johannes Berg55682962007-09-20 13:09:35 -04002938static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
2939{
Johannes Berg4c476992010-10-04 21:36:35 +02002940 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002941 struct vif_params params;
Johannes Berge36d56b2009-06-09 21:04:43 +02002942 int err;
Johannes Berg04a773a2009-04-19 21:24:32 +02002943 enum nl80211_iftype otype, ntype;
Johannes Berg4c476992010-10-04 21:36:35 +02002944 struct net_device *dev = info->user_ptr[1];
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002945 bool change = false;
Johannes Berg55682962007-09-20 13:09:35 -04002946
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002947 memset(&params, 0, sizeof(params));
2948
Johannes Berg04a773a2009-04-19 21:24:32 +02002949 otype = ntype = dev->ieee80211_ptr->iftype;
Johannes Berg55682962007-09-20 13:09:35 -04002950
Johannes Berg723b0382008-09-16 20:22:09 +02002951 if (info->attrs[NL80211_ATTR_IFTYPE]) {
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002952 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
Johannes Berg04a773a2009-04-19 21:24:32 +02002953 if (otype != ntype)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002954 change = true;
Johannes Berg4c476992010-10-04 21:36:35 +02002955 if (ntype > NL80211_IFTYPE_MAX)
2956 return -EINVAL;
Johannes Berg723b0382008-09-16 20:22:09 +02002957 }
2958
Johannes Berg92ffe052008-09-16 20:39:36 +02002959 if (info->attrs[NL80211_ATTR_MESH_ID]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01002960 struct wireless_dev *wdev = dev->ieee80211_ptr;
2961
Johannes Berg4c476992010-10-04 21:36:35 +02002962 if (ntype != NL80211_IFTYPE_MESH_POINT)
2963 return -EINVAL;
Johannes Berg29cbe682010-12-03 09:20:44 +01002964 if (netif_running(dev))
2965 return -EBUSY;
2966
2967 wdev_lock(wdev);
2968 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2969 IEEE80211_MAX_MESH_ID_LEN);
2970 wdev->mesh_id_up_len =
2971 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2972 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2973 wdev->mesh_id_up_len);
2974 wdev_unlock(wdev);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002975 }
2976
Felix Fietkau8b787642009-11-10 18:53:10 +01002977 if (info->attrs[NL80211_ATTR_4ADDR]) {
2978 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
2979 change = true;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002980 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002981 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002982 return err;
Felix Fietkau8b787642009-11-10 18:53:10 +01002983 } else {
2984 params.use_4addr = -1;
2985 }
2986
Johannes Berg1db77592017-04-12 11:36:31 +02002987 err = nl80211_parse_mon_options(rdev, ntype, info, &params);
2988 if (err < 0)
2989 return err;
2990 if (err > 0)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002991 change = true;
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002992
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002993 if (change)
Johannes Berg818a9862017-04-12 11:23:28 +02002994 err = cfg80211_change_iface(rdev, dev, ntype, &params);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002995 else
2996 err = 0;
Johannes Berg60719ff2008-09-16 14:55:09 +02002997
Johannes Berg9bc383d2009-11-19 11:55:19 +01002998 if (!err && params.use_4addr != -1)
2999 dev->ieee80211_ptr->use_4addr = params.use_4addr;
3000
Johannes Berg55682962007-09-20 13:09:35 -04003001 return err;
3002}
3003
3004static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
3005{
Johannes Berg4c476992010-10-04 21:36:35 +02003006 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003007 struct vif_params params;
Johannes Berg84efbb82012-06-16 00:00:26 +02003008 struct wireless_dev *wdev;
Denis Kenzior896ff062016-08-03 16:58:33 -05003009 struct sk_buff *msg;
Johannes Berg55682962007-09-20 13:09:35 -04003010 int err;
3011 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
3012
Johannes Berg78f22b62014-03-24 17:57:27 +01003013 /* to avoid failing a new interface creation due to pending removal */
3014 cfg80211_destroy_ifaces(rdev);
3015
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003016 memset(&params, 0, sizeof(params));
3017
Johannes Berg55682962007-09-20 13:09:35 -04003018 if (!info->attrs[NL80211_ATTR_IFNAME])
3019 return -EINVAL;
3020
3021 if (info->attrs[NL80211_ATTR_IFTYPE]) {
3022 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
3023 if (type > NL80211_IFTYPE_MAX)
3024 return -EINVAL;
3025 }
3026
Johannes Berg79c97e92009-07-07 03:56:12 +02003027 if (!rdev->ops->add_virtual_intf ||
Johannes Berg4c476992010-10-04 21:36:35 +02003028 !(rdev->wiphy.interface_modes & (1 << type)))
3029 return -EOPNOTSUPP;
Johannes Berg55682962007-09-20 13:09:35 -04003030
Ayala Bekercb3b7d82016-09-20 17:31:13 +03003031 if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
Ben Greeare8f479b2014-10-22 12:23:05 -07003032 rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
3033 info->attrs[NL80211_ATTR_MAC]) {
Arend van Spriel1c18f142013-01-08 10:17:27 +01003034 nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
3035 ETH_ALEN);
3036 if (!is_valid_ether_addr(params.macaddr))
3037 return -EADDRNOTAVAIL;
3038 }
3039
Johannes Berg9bc383d2009-11-19 11:55:19 +01003040 if (info->attrs[NL80211_ATTR_4ADDR]) {
Felix Fietkau8b787642009-11-10 18:53:10 +01003041 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
Johannes Bergad4bb6f2009-11-19 00:56:30 +01003042 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
Johannes Berg9bc383d2009-11-19 11:55:19 +01003043 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02003044 return err;
Johannes Berg9bc383d2009-11-19 11:55:19 +01003045 }
Felix Fietkau8b787642009-11-10 18:53:10 +01003046
Johannes Berg1db77592017-04-12 11:36:31 +02003047 err = nl80211_parse_mon_options(rdev, type, info, &params);
3048 if (err < 0)
3049 return err;
Felix Fietkaue057d3c2013-05-28 13:01:52 +02003050
Johannes Berga18c7192015-02-24 10:56:42 +01003051 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3052 if (!msg)
3053 return -ENOMEM;
3054
Hila Gonene35e4d22012-06-27 17:19:42 +03003055 wdev = rdev_add_virtual_intf(rdev,
3056 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
Johannes Berg818a9862017-04-12 11:23:28 +02003057 NET_NAME_USER, type, &params);
Rafał Miłeckid687cbb2014-11-14 18:43:28 +01003058 if (WARN_ON(!wdev)) {
3059 nlmsg_free(msg);
3060 return -EPROTO;
3061 } else if (IS_ERR(wdev)) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02003062 nlmsg_free(msg);
Johannes Berg84efbb82012-06-16 00:00:26 +02003063 return PTR_ERR(wdev);
Johannes Berg1c90f9d2012-06-16 00:05:37 +02003064 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01003065
Jukka Rissanen18e5ca62014-11-13 17:25:14 +02003066 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
Johannes Berg78f22b62014-03-24 17:57:27 +01003067 wdev->owner_nlportid = info->snd_portid;
3068
Johannes Berg98104fde2012-06-16 00:19:54 +02003069 switch (type) {
3070 case NL80211_IFTYPE_MESH_POINT:
3071 if (!info->attrs[NL80211_ATTR_MESH_ID])
3072 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01003073 wdev_lock(wdev);
3074 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
3075 IEEE80211_MAX_MESH_ID_LEN);
3076 wdev->mesh_id_up_len =
3077 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
3078 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
3079 wdev->mesh_id_up_len);
3080 wdev_unlock(wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +02003081 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03003082 case NL80211_IFTYPE_NAN:
Johannes Berg98104fde2012-06-16 00:19:54 +02003083 case NL80211_IFTYPE_P2P_DEVICE:
3084 /*
Ayala Bekercb3b7d82016-09-20 17:31:13 +03003085 * P2P Device and NAN do not have a netdev, so don't go
Johannes Berg98104fde2012-06-16 00:19:54 +02003086 * through the netdev notifier and must be added here
3087 */
3088 mutex_init(&wdev->mtx);
3089 INIT_LIST_HEAD(&wdev->event_list);
3090 spin_lock_init(&wdev->event_lock);
3091 INIT_LIST_HEAD(&wdev->mgmt_registrations);
3092 spin_lock_init(&wdev->mgmt_registrations_lock);
3093
Johannes Berg98104fde2012-06-16 00:19:54 +02003094 wdev->identifier = ++rdev->wdev_id;
Johannes Berg53873f12016-05-03 16:52:04 +03003095 list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
Johannes Berg98104fde2012-06-16 00:19:54 +02003096 rdev->devlist_generation++;
Johannes Berg98104fde2012-06-16 00:19:54 +02003097 break;
3098 default:
3099 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01003100 }
3101
Eric W. Biederman15e47302012-09-07 20:12:54 +00003102 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02003103 rdev, wdev, false) < 0) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02003104 nlmsg_free(msg);
3105 return -ENOBUFS;
3106 }
3107
Denis Kenzior896ff062016-08-03 16:58:33 -05003108 /*
3109 * For wdevs which have no associated netdev object (e.g. of type
3110 * NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here.
3111 * For all other types, the event will be generated from the
3112 * netdev notifier
3113 */
3114 if (!wdev->netdev)
3115 nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02003116
Johannes Berg1c90f9d2012-06-16 00:05:37 +02003117 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04003118}
3119
3120static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
3121{
Johannes Berg4c476992010-10-04 21:36:35 +02003122 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg84efbb82012-06-16 00:00:26 +02003123 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04003124
Johannes Berg4c476992010-10-04 21:36:35 +02003125 if (!rdev->ops->del_virtual_intf)
3126 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01003127
Johannes Berg84efbb82012-06-16 00:00:26 +02003128 /*
3129 * If we remove a wireless device without a netdev then clear
3130 * user_ptr[1] so that nl80211_post_doit won't dereference it
3131 * to check if it needs to do dev_put(). Otherwise it crashes
3132 * since the wdev has been freed, unlike with a netdev where
3133 * we need the dev_put() for the netdev to really be freed.
3134 */
3135 if (!wdev->netdev)
3136 info->user_ptr[1] = NULL;
3137
Denis Kenzior7f8ed012016-08-03 16:58:35 -05003138 return rdev_del_virtual_intf(rdev, wdev);
Johannes Berg55682962007-09-20 13:09:35 -04003139}
3140
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003141static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
3142{
3143 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3144 struct net_device *dev = info->user_ptr[1];
3145 u16 noack_map;
3146
3147 if (!info->attrs[NL80211_ATTR_NOACK_MAP])
3148 return -EINVAL;
3149
3150 if (!rdev->ops->set_noack_map)
3151 return -EOPNOTSUPP;
3152
3153 noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
3154
Hila Gonene35e4d22012-06-27 17:19:42 +03003155 return rdev_set_noack_map(rdev, dev, noack_map);
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003156}
3157
Johannes Berg41ade002007-12-19 02:03:29 +01003158struct get_key_cookie {
3159 struct sk_buff *msg;
3160 int error;
Johannes Bergb9454e82009-07-08 13:29:08 +02003161 int idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003162};
3163
3164static void get_key_callback(void *c, struct key_params *params)
3165{
Johannes Bergb9454e82009-07-08 13:29:08 +02003166 struct nlattr *key;
Johannes Berg41ade002007-12-19 02:03:29 +01003167 struct get_key_cookie *cookie = c;
3168
David S. Miller9360ffd2012-03-29 04:41:26 -04003169 if ((params->key &&
3170 nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
3171 params->key_len, params->key)) ||
3172 (params->seq &&
3173 nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
3174 params->seq_len, params->seq)) ||
3175 (params->cipher &&
3176 nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
3177 params->cipher)))
3178 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003179
Johannes Bergb9454e82009-07-08 13:29:08 +02003180 key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
3181 if (!key)
3182 goto nla_put_failure;
3183
David S. Miller9360ffd2012-03-29 04:41:26 -04003184 if ((params->key &&
3185 nla_put(cookie->msg, NL80211_KEY_DATA,
3186 params->key_len, params->key)) ||
3187 (params->seq &&
3188 nla_put(cookie->msg, NL80211_KEY_SEQ,
3189 params->seq_len, params->seq)) ||
3190 (params->cipher &&
3191 nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
3192 params->cipher)))
3193 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003194
David S. Miller9360ffd2012-03-29 04:41:26 -04003195 if (nla_put_u8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx))
3196 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003197
3198 nla_nest_end(cookie->msg, key);
3199
Johannes Berg41ade002007-12-19 02:03:29 +01003200 return;
3201 nla_put_failure:
3202 cookie->error = 1;
3203}
3204
3205static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
3206{
Johannes Berg4c476992010-10-04 21:36:35 +02003207 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003208 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003209 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003210 u8 key_idx = 0;
Johannes Berge31b8212010-10-05 19:39:30 +02003211 const u8 *mac_addr = NULL;
3212 bool pairwise;
Johannes Berg41ade002007-12-19 02:03:29 +01003213 struct get_key_cookie cookie = {
3214 .error = 0,
3215 };
3216 void *hdr;
3217 struct sk_buff *msg;
3218
3219 if (info->attrs[NL80211_ATTR_KEY_IDX])
3220 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
3221
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +02003222 if (key_idx > 5)
Johannes Berg41ade002007-12-19 02:03:29 +01003223 return -EINVAL;
3224
3225 if (info->attrs[NL80211_ATTR_MAC])
3226 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3227
Johannes Berge31b8212010-10-05 19:39:30 +02003228 pairwise = !!mac_addr;
3229 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
3230 u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07003231
Johannes Berge31b8212010-10-05 19:39:30 +02003232 if (kt >= NUM_NL80211_KEYTYPES)
3233 return -EINVAL;
3234 if (kt != NL80211_KEYTYPE_GROUP &&
3235 kt != NL80211_KEYTYPE_PAIRWISE)
3236 return -EINVAL;
3237 pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
3238 }
3239
Johannes Berg4c476992010-10-04 21:36:35 +02003240 if (!rdev->ops->get_key)
3241 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003242
Johannes Berg0fa7b392015-01-23 11:10:12 +01003243 if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3244 return -ENOENT;
3245
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07003246 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02003247 if (!msg)
3248 return -ENOMEM;
Johannes Berg41ade002007-12-19 02:03:29 +01003249
Eric W. Biederman15e47302012-09-07 20:12:54 +00003250 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg41ade002007-12-19 02:03:29 +01003251 NL80211_CMD_NEW_KEY);
Dan Carpentercb35fba2013-08-14 14:50:01 +03003252 if (!hdr)
Johannes Berg9fe271a2013-10-25 11:15:12 +02003253 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003254
3255 cookie.msg = msg;
Johannes Bergb9454e82009-07-08 13:29:08 +02003256 cookie.idx = key_idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003257
David S. Miller9360ffd2012-03-29 04:41:26 -04003258 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
3259 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
3260 goto nla_put_failure;
3261 if (mac_addr &&
3262 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
3263 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003264
Hila Gonene35e4d22012-06-27 17:19:42 +03003265 err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
3266 get_key_callback);
Johannes Berg41ade002007-12-19 02:03:29 +01003267
3268 if (err)
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003269 goto free_msg;
Johannes Berg41ade002007-12-19 02:03:29 +01003270
3271 if (cookie.error)
3272 goto nla_put_failure;
3273
3274 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02003275 return genlmsg_reply(msg, info);
Johannes Berg41ade002007-12-19 02:03:29 +01003276
3277 nla_put_failure:
3278 err = -ENOBUFS;
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003279 free_msg:
Johannes Berg41ade002007-12-19 02:03:29 +01003280 nlmsg_free(msg);
Johannes Berg41ade002007-12-19 02:03:29 +01003281 return err;
3282}
3283
3284static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
3285{
Johannes Berg4c476992010-10-04 21:36:35 +02003286 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergb9454e82009-07-08 13:29:08 +02003287 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003288 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003289 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003290
Johannes Bergb9454e82009-07-08 13:29:08 +02003291 err = nl80211_parse_key(info, &key);
3292 if (err)
3293 return err;
3294
3295 if (key.idx < 0)
Johannes Berg41ade002007-12-19 02:03:29 +01003296 return -EINVAL;
3297
Johannes Bergb9454e82009-07-08 13:29:08 +02003298 /* only support setting default key */
3299 if (!key.def && !key.defmgmt)
Johannes Berg41ade002007-12-19 02:03:29 +01003300 return -EINVAL;
3301
Johannes Bergfffd0932009-07-08 14:22:54 +02003302 wdev_lock(dev->ieee80211_ptr);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003303
3304 if (key.def) {
3305 if (!rdev->ops->set_default_key) {
3306 err = -EOPNOTSUPP;
3307 goto out;
3308 }
3309
3310 err = nl80211_key_allowed(dev->ieee80211_ptr);
3311 if (err)
3312 goto out;
3313
Hila Gonene35e4d22012-06-27 17:19:42 +03003314 err = rdev_set_default_key(rdev, dev, key.idx,
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003315 key.def_uni, key.def_multi);
3316
3317 if (err)
3318 goto out;
Johannes Bergfffd0932009-07-08 14:22:54 +02003319
Johannes Berg3d23e342009-09-29 23:27:28 +02003320#ifdef CONFIG_CFG80211_WEXT
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003321 dev->ieee80211_ptr->wext.default_key = key.idx;
Johannes Berg08645122009-05-11 13:54:58 +02003322#endif
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003323 } else {
3324 if (key.def_uni || !key.def_multi) {
3325 err = -EINVAL;
3326 goto out;
3327 }
3328
3329 if (!rdev->ops->set_default_mgmt_key) {
3330 err = -EOPNOTSUPP;
3331 goto out;
3332 }
3333
3334 err = nl80211_key_allowed(dev->ieee80211_ptr);
3335 if (err)
3336 goto out;
3337
Hila Gonene35e4d22012-06-27 17:19:42 +03003338 err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003339 if (err)
3340 goto out;
3341
3342#ifdef CONFIG_CFG80211_WEXT
3343 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
3344#endif
3345 }
3346
3347 out:
Johannes Bergfffd0932009-07-08 14:22:54 +02003348 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003349
Johannes Berg41ade002007-12-19 02:03:29 +01003350 return err;
3351}
3352
3353static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
3354{
Johannes Berg4c476992010-10-04 21:36:35 +02003355 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfffd0932009-07-08 14:22:54 +02003356 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003357 struct net_device *dev = info->user_ptr[1];
Johannes Bergb9454e82009-07-08 13:29:08 +02003358 struct key_parse key;
Johannes Berge31b8212010-10-05 19:39:30 +02003359 const u8 *mac_addr = NULL;
Johannes Berg41ade002007-12-19 02:03:29 +01003360
Johannes Bergb9454e82009-07-08 13:29:08 +02003361 err = nl80211_parse_key(info, &key);
3362 if (err)
3363 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003364
Johannes Bergb9454e82009-07-08 13:29:08 +02003365 if (!key.p.key)
Johannes Berg41ade002007-12-19 02:03:29 +01003366 return -EINVAL;
3367
Johannes Berg41ade002007-12-19 02:03:29 +01003368 if (info->attrs[NL80211_ATTR_MAC])
3369 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3370
Johannes Berge31b8212010-10-05 19:39:30 +02003371 if (key.type == -1) {
3372 if (mac_addr)
3373 key.type = NL80211_KEYTYPE_PAIRWISE;
3374 else
3375 key.type = NL80211_KEYTYPE_GROUP;
3376 }
3377
3378 /* for now */
3379 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3380 key.type != NL80211_KEYTYPE_GROUP)
3381 return -EINVAL;
3382
Johannes Berg4c476992010-10-04 21:36:35 +02003383 if (!rdev->ops->add_key)
3384 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01003385
Johannes Berge31b8212010-10-05 19:39:30 +02003386 if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
3387 key.type == NL80211_KEYTYPE_PAIRWISE,
3388 mac_addr))
Johannes Berg4c476992010-10-04 21:36:35 +02003389 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02003390
3391 wdev_lock(dev->ieee80211_ptr);
3392 err = nl80211_key_allowed(dev->ieee80211_ptr);
3393 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003394 err = rdev_add_key(rdev, dev, key.idx,
3395 key.type == NL80211_KEYTYPE_PAIRWISE,
3396 mac_addr, &key.p);
Johannes Bergfffd0932009-07-08 14:22:54 +02003397 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003398
Johannes Berg41ade002007-12-19 02:03:29 +01003399 return err;
3400}
3401
3402static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
3403{
Johannes Berg4c476992010-10-04 21:36:35 +02003404 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003405 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003406 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003407 u8 *mac_addr = NULL;
Johannes Bergb9454e82009-07-08 13:29:08 +02003408 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003409
Johannes Bergb9454e82009-07-08 13:29:08 +02003410 err = nl80211_parse_key(info, &key);
3411 if (err)
3412 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003413
3414 if (info->attrs[NL80211_ATTR_MAC])
3415 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3416
Johannes Berge31b8212010-10-05 19:39:30 +02003417 if (key.type == -1) {
3418 if (mac_addr)
3419 key.type = NL80211_KEYTYPE_PAIRWISE;
3420 else
3421 key.type = NL80211_KEYTYPE_GROUP;
3422 }
3423
3424 /* for now */
3425 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3426 key.type != NL80211_KEYTYPE_GROUP)
3427 return -EINVAL;
3428
Johannes Berg4c476992010-10-04 21:36:35 +02003429 if (!rdev->ops->del_key)
3430 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003431
Johannes Bergfffd0932009-07-08 14:22:54 +02003432 wdev_lock(dev->ieee80211_ptr);
3433 err = nl80211_key_allowed(dev->ieee80211_ptr);
Johannes Berge31b8212010-10-05 19:39:30 +02003434
Johannes Berg0fa7b392015-01-23 11:10:12 +01003435 if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
Johannes Berge31b8212010-10-05 19:39:30 +02003436 !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3437 err = -ENOENT;
3438
Johannes Bergfffd0932009-07-08 14:22:54 +02003439 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003440 err = rdev_del_key(rdev, dev, key.idx,
3441 key.type == NL80211_KEYTYPE_PAIRWISE,
3442 mac_addr);
Johannes Berg41ade002007-12-19 02:03:29 +01003443
Johannes Berg3d23e342009-09-29 23:27:28 +02003444#ifdef CONFIG_CFG80211_WEXT
Johannes Berg08645122009-05-11 13:54:58 +02003445 if (!err) {
Johannes Bergb9454e82009-07-08 13:29:08 +02003446 if (key.idx == dev->ieee80211_ptr->wext.default_key)
Johannes Berg08645122009-05-11 13:54:58 +02003447 dev->ieee80211_ptr->wext.default_key = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +02003448 else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
Johannes Berg08645122009-05-11 13:54:58 +02003449 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
3450 }
3451#endif
Johannes Bergfffd0932009-07-08 14:22:54 +02003452 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg08645122009-05-11 13:54:58 +02003453
Johannes Berg41ade002007-12-19 02:03:29 +01003454 return err;
3455}
3456
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05303457/* This function returns an error or the number of nested attributes */
3458static int validate_acl_mac_addrs(struct nlattr *nl_attr)
3459{
3460 struct nlattr *attr;
3461 int n_entries = 0, tmp;
3462
3463 nla_for_each_nested(attr, nl_attr, tmp) {
3464 if (nla_len(attr) != ETH_ALEN)
3465 return -EINVAL;
3466
3467 n_entries++;
3468 }
3469
3470 return n_entries;
3471}
3472
3473/*
3474 * This function parses ACL information and allocates memory for ACL data.
3475 * On successful return, the calling function is responsible to free the
3476 * ACL buffer returned by this function.
3477 */
3478static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
3479 struct genl_info *info)
3480{
3481 enum nl80211_acl_policy acl_policy;
3482 struct nlattr *attr;
3483 struct cfg80211_acl_data *acl;
3484 int i = 0, n_entries, tmp;
3485
3486 if (!wiphy->max_acl_mac_addrs)
3487 return ERR_PTR(-EOPNOTSUPP);
3488
3489 if (!info->attrs[NL80211_ATTR_ACL_POLICY])
3490 return ERR_PTR(-EINVAL);
3491
3492 acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
3493 if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
3494 acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
3495 return ERR_PTR(-EINVAL);
3496
3497 if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
3498 return ERR_PTR(-EINVAL);
3499
3500 n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
3501 if (n_entries < 0)
3502 return ERR_PTR(n_entries);
3503
3504 if (n_entries > wiphy->max_acl_mac_addrs)
3505 return ERR_PTR(-ENOTSUPP);
3506
3507 acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
3508 GFP_KERNEL);
3509 if (!acl)
3510 return ERR_PTR(-ENOMEM);
3511
3512 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
3513 memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
3514 i++;
3515 }
3516
3517 acl->n_acl_entries = n_entries;
3518 acl->acl_policy = acl_policy;
3519
3520 return acl;
3521}
3522
3523static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
3524{
3525 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3526 struct net_device *dev = info->user_ptr[1];
3527 struct cfg80211_acl_data *acl;
3528 int err;
3529
3530 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3531 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3532 return -EOPNOTSUPP;
3533
3534 if (!dev->ieee80211_ptr->beacon_interval)
3535 return -EINVAL;
3536
3537 acl = parse_acl_data(&rdev->wiphy, info);
3538 if (IS_ERR(acl))
3539 return PTR_ERR(acl);
3540
3541 err = rdev_set_mac_acl(rdev, dev, acl);
3542
3543 kfree(acl);
3544
3545 return err;
3546}
3547
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303548static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
3549 u8 *rates, u8 rates_len)
3550{
3551 u8 i;
3552 u32 mask = 0;
3553
3554 for (i = 0; i < rates_len; i++) {
3555 int rate = (rates[i] & 0x7f) * 5;
3556 int ridx;
3557
3558 for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
3559 struct ieee80211_rate *srate =
3560 &sband->bitrates[ridx];
3561 if (rate == srate->bitrate) {
3562 mask |= 1 << ridx;
3563 break;
3564 }
3565 }
3566 if (ridx == sband->n_bitrates)
3567 return 0; /* rate not found */
3568 }
3569
3570 return mask;
3571}
3572
3573static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
3574 u8 *rates, u8 rates_len,
3575 u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
3576{
3577 u8 i;
3578
3579 memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
3580
3581 for (i = 0; i < rates_len; i++) {
3582 int ridx, rbit;
3583
3584 ridx = rates[i] / 8;
3585 rbit = BIT(rates[i] % 8);
3586
3587 /* check validity */
3588 if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
3589 return false;
3590
3591 /* check availability */
3592 if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
3593 mcs[ridx] |= rbit;
3594 else
3595 return false;
3596 }
3597
3598 return true;
3599}
3600
3601static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
3602{
3603 u16 mcs_mask = 0;
3604
3605 switch (vht_mcs_map) {
3606 case IEEE80211_VHT_MCS_NOT_SUPPORTED:
3607 break;
3608 case IEEE80211_VHT_MCS_SUPPORT_0_7:
3609 mcs_mask = 0x00FF;
3610 break;
3611 case IEEE80211_VHT_MCS_SUPPORT_0_8:
3612 mcs_mask = 0x01FF;
3613 break;
3614 case IEEE80211_VHT_MCS_SUPPORT_0_9:
3615 mcs_mask = 0x03FF;
3616 break;
3617 default:
3618 break;
3619 }
3620
3621 return mcs_mask;
3622}
3623
3624static void vht_build_mcs_mask(u16 vht_mcs_map,
3625 u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
3626{
3627 u8 nss;
3628
3629 for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
3630 vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
3631 vht_mcs_map >>= 2;
3632 }
3633}
3634
3635static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
3636 struct nl80211_txrate_vht *txrate,
3637 u16 mcs[NL80211_VHT_NSS_MAX])
3638{
3639 u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3640 u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
3641 u8 i;
3642
3643 if (!sband->vht_cap.vht_supported)
3644 return false;
3645
3646 memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
3647
3648 /* Build vht_mcs_mask from VHT capabilities */
3649 vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
3650
3651 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
3652 if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
3653 mcs[i] = txrate->mcs[i];
3654 else
3655 return false;
3656 }
3657
3658 return true;
3659}
3660
3661static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
3662 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
3663 .len = NL80211_MAX_SUPP_RATES },
3664 [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
3665 .len = NL80211_MAX_SUPP_HT_RATES },
3666 [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
3667 [NL80211_TXRATE_GI] = { .type = NLA_U8 },
3668};
3669
3670static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
3671 struct cfg80211_bitrate_mask *mask)
3672{
3673 struct nlattr *tb[NL80211_TXRATE_MAX + 1];
3674 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3675 int rem, i;
3676 struct nlattr *tx_rates;
3677 struct ieee80211_supported_band *sband;
3678 u16 vht_tx_mcs_map;
3679
3680 memset(mask, 0, sizeof(*mask));
3681 /* Default to all rates enabled */
3682 for (i = 0; i < NUM_NL80211_BANDS; i++) {
3683 sband = rdev->wiphy.bands[i];
3684
3685 if (!sband)
3686 continue;
3687
3688 mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
3689 memcpy(mask->control[i].ht_mcs,
3690 sband->ht_cap.mcs.rx_mask,
3691 sizeof(mask->control[i].ht_mcs));
3692
3693 if (!sband->vht_cap.vht_supported)
3694 continue;
3695
3696 vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3697 vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
3698 }
3699
3700 /* if no rates are given set it back to the defaults */
3701 if (!info->attrs[NL80211_ATTR_TX_RATES])
3702 goto out;
3703
3704 /* The nested attribute uses enum nl80211_band as the index. This maps
3705 * directly to the enum nl80211_band values used in cfg80211.
3706 */
3707 BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
3708 nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
3709 enum nl80211_band band = nla_type(tx_rates);
3710 int err;
3711
3712 if (band < 0 || band >= NUM_NL80211_BANDS)
3713 return -EINVAL;
3714 sband = rdev->wiphy.bands[band];
3715 if (sband == NULL)
3716 return -EINVAL;
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02003717 err = nla_parse_nested(tb, NL80211_TXRATE_MAX, tx_rates,
Johannes Bergfe521452017-04-12 14:34:08 +02003718 nl80211_txattr_policy, info->extack);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303719 if (err)
3720 return err;
3721 if (tb[NL80211_TXRATE_LEGACY]) {
3722 mask->control[band].legacy = rateset_to_mask(
3723 sband,
3724 nla_data(tb[NL80211_TXRATE_LEGACY]),
3725 nla_len(tb[NL80211_TXRATE_LEGACY]));
3726 if ((mask->control[band].legacy == 0) &&
3727 nla_len(tb[NL80211_TXRATE_LEGACY]))
3728 return -EINVAL;
3729 }
3730 if (tb[NL80211_TXRATE_HT]) {
3731 if (!ht_rateset_to_mask(
3732 sband,
3733 nla_data(tb[NL80211_TXRATE_HT]),
3734 nla_len(tb[NL80211_TXRATE_HT]),
3735 mask->control[band].ht_mcs))
3736 return -EINVAL;
3737 }
3738 if (tb[NL80211_TXRATE_VHT]) {
3739 if (!vht_set_mcs_mask(
3740 sband,
3741 nla_data(tb[NL80211_TXRATE_VHT]),
3742 mask->control[band].vht_mcs))
3743 return -EINVAL;
3744 }
3745 if (tb[NL80211_TXRATE_GI]) {
3746 mask->control[band].gi =
3747 nla_get_u8(tb[NL80211_TXRATE_GI]);
3748 if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
3749 return -EINVAL;
3750 }
3751
3752 if (mask->control[band].legacy == 0) {
3753 /* don't allow empty legacy rates if HT or VHT
3754 * are not even supported.
3755 */
3756 if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
3757 rdev->wiphy.bands[band]->vht_cap.vht_supported))
3758 return -EINVAL;
3759
3760 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
3761 if (mask->control[band].ht_mcs[i])
3762 goto out;
3763
3764 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
3765 if (mask->control[band].vht_mcs[i])
3766 goto out;
3767
3768 /* legacy and mcs rates may not be both empty */
3769 return -EINVAL;
3770 }
3771 }
3772
3773out:
3774 return 0;
3775}
3776
Johannes Berg8564e382016-09-19 09:44:44 +02003777static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
3778 enum nl80211_band band,
3779 struct cfg80211_bitrate_mask *beacon_rate)
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303780{
Johannes Berg8564e382016-09-19 09:44:44 +02003781 u32 count_ht, count_vht, i;
3782 u32 rate = beacon_rate->control[band].legacy;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303783
3784 /* Allow only one rate */
3785 if (hweight32(rate) > 1)
3786 return -EINVAL;
3787
3788 count_ht = 0;
3789 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003790 if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303791 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003792 } else if (beacon_rate->control[band].ht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303793 count_ht++;
3794 if (count_ht > 1)
3795 return -EINVAL;
3796 }
3797 if (count_ht && rate)
3798 return -EINVAL;
3799 }
3800
3801 count_vht = 0;
3802 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003803 if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303804 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003805 } else if (beacon_rate->control[band].vht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303806 count_vht++;
3807 if (count_vht > 1)
3808 return -EINVAL;
3809 }
3810 if (count_vht && rate)
3811 return -EINVAL;
3812 }
3813
3814 if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
3815 return -EINVAL;
3816
Johannes Berg8564e382016-09-19 09:44:44 +02003817 if (rate &&
3818 !wiphy_ext_feature_isset(&rdev->wiphy,
3819 NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
3820 return -EINVAL;
3821 if (count_ht &&
3822 !wiphy_ext_feature_isset(&rdev->wiphy,
3823 NL80211_EXT_FEATURE_BEACON_RATE_HT))
3824 return -EINVAL;
3825 if (count_vht &&
3826 !wiphy_ext_feature_isset(&rdev->wiphy,
3827 NL80211_EXT_FEATURE_BEACON_RATE_VHT))
3828 return -EINVAL;
3829
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303830 return 0;
3831}
3832
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003833static int nl80211_parse_beacon(struct nlattr *attrs[],
Johannes Berg88600202012-02-13 15:17:18 +01003834 struct cfg80211_beacon_data *bcn)
Johannes Berged1b6cc2007-12-19 02:03:32 +01003835{
Johannes Berg88600202012-02-13 15:17:18 +01003836 bool haveinfo = false;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003837
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003838 if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
3839 !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
3840 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
3841 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
Johannes Bergf4a11bb2009-03-27 12:40:28 +01003842 return -EINVAL;
3843
Johannes Berg88600202012-02-13 15:17:18 +01003844 memset(bcn, 0, sizeof(*bcn));
Johannes Berged1b6cc2007-12-19 02:03:32 +01003845
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003846 if (attrs[NL80211_ATTR_BEACON_HEAD]) {
3847 bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
3848 bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
Johannes Berg88600202012-02-13 15:17:18 +01003849 if (!bcn->head_len)
3850 return -EINVAL;
3851 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003852 }
3853
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003854 if (attrs[NL80211_ATTR_BEACON_TAIL]) {
3855 bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
3856 bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
Johannes Berg88600202012-02-13 15:17:18 +01003857 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003858 }
3859
Johannes Berg4c476992010-10-04 21:36:35 +02003860 if (!haveinfo)
3861 return -EINVAL;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003862
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003863 if (attrs[NL80211_ATTR_IE]) {
3864 bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
3865 bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003866 }
3867
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003868 if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003869 bcn->proberesp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003870 nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003871 bcn->proberesp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003872 nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003873 }
3874
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003875 if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003876 bcn->assocresp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003877 nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003878 bcn->assocresp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003879 nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003880 }
3881
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003882 if (attrs[NL80211_ATTR_PROBE_RESP]) {
3883 bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
3884 bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
Arik Nemtsov00f740e2011-11-10 11:28:56 +02003885 }
3886
Johannes Berg88600202012-02-13 15:17:18 +01003887 return 0;
3888}
3889
Johannes Berg66cd7942017-02-07 22:40:44 +02003890static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
3891 const u8 *rates)
3892{
3893 int i;
3894
3895 if (!rates)
3896 return;
3897
3898 for (i = 0; i < rates[1]; i++) {
3899 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
3900 params->ht_required = true;
3901 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
3902 params->vht_required = true;
3903 }
3904}
3905
3906/*
3907 * Since the nl80211 API didn't include, from the beginning, attributes about
3908 * HT/VHT requirements/capabilities, we parse them out of the IEs for the
3909 * benefit of drivers that rebuild IEs in the firmware.
3910 */
3911static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
3912{
3913 const struct cfg80211_beacon_data *bcn = &params->beacon;
Igor Mitsyankoba83bfb2017-08-30 13:52:25 -07003914 size_t ies_len = bcn->tail_len;
3915 const u8 *ies = bcn->tail;
Johannes Berg66cd7942017-02-07 22:40:44 +02003916 const u8 *rates;
3917 const u8 *cap;
3918
3919 rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
3920 nl80211_check_ap_rate_selectors(params, rates);
3921
3922 rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
3923 nl80211_check_ap_rate_selectors(params, rates);
3924
3925 cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
3926 if (cap && cap[1] >= sizeof(*params->ht_cap))
3927 params->ht_cap = (void *)(cap + 2);
3928 cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
3929 if (cap && cap[1] >= sizeof(*params->vht_cap))
3930 params->vht_cap = (void *)(cap + 2);
3931}
3932
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003933static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
3934 struct cfg80211_ap_settings *params)
3935{
3936 struct wireless_dev *wdev;
3937 bool ret = false;
3938
Johannes Berg53873f12016-05-03 16:52:04 +03003939 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003940 if (wdev->iftype != NL80211_IFTYPE_AP &&
3941 wdev->iftype != NL80211_IFTYPE_P2P_GO)
3942 continue;
3943
Johannes Berg683b6d32012-11-08 21:25:48 +01003944 if (!wdev->preset_chandef.chan)
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003945 continue;
3946
Johannes Berg683b6d32012-11-08 21:25:48 +01003947 params->chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003948 ret = true;
3949 break;
3950 }
3951
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003952 return ret;
3953}
3954
Jouni Malinene39e5b52012-09-30 19:29:39 +03003955static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
3956 enum nl80211_auth_type auth_type,
3957 enum nl80211_commands cmd)
3958{
3959 if (auth_type > NL80211_AUTHTYPE_MAX)
3960 return false;
3961
3962 switch (cmd) {
3963 case NL80211_CMD_AUTHENTICATE:
3964 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
3965 auth_type == NL80211_AUTHTYPE_SAE)
3966 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03003967 if (!wiphy_ext_feature_isset(&rdev->wiphy,
3968 NL80211_EXT_FEATURE_FILS_STA) &&
3969 (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3970 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3971 auth_type == NL80211_AUTHTYPE_FILS_PK))
3972 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003973 return true;
3974 case NL80211_CMD_CONNECT:
Srinivas Dasari10773a72018-01-25 17:13:39 +02003975 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
3976 auth_type == NL80211_AUTHTYPE_SAE)
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03003977 return false;
Srinivas Dasari10773a72018-01-25 17:13:39 +02003978
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03003979 /* FILS with SK PFS or PK not supported yet */
3980 if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3981 auth_type == NL80211_AUTHTYPE_FILS_PK)
3982 return false;
3983 if (!wiphy_ext_feature_isset(
3984 &rdev->wiphy,
3985 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
3986 auth_type == NL80211_AUTHTYPE_FILS_SK)
3987 return false;
3988 return true;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003989 case NL80211_CMD_START_AP:
3990 /* SAE not supported yet */
3991 if (auth_type == NL80211_AUTHTYPE_SAE)
3992 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03003993 /* FILS not supported yet */
3994 if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3995 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3996 auth_type == NL80211_AUTHTYPE_FILS_PK)
3997 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003998 return true;
3999 default:
4000 return false;
4001 }
4002}
4003
Johannes Berg88600202012-02-13 15:17:18 +01004004static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
4005{
4006 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4007 struct net_device *dev = info->user_ptr[1];
4008 struct wireless_dev *wdev = dev->ieee80211_ptr;
4009 struct cfg80211_ap_settings params;
4010 int err;
4011
4012 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4013 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4014 return -EOPNOTSUPP;
4015
4016 if (!rdev->ops->start_ap)
4017 return -EOPNOTSUPP;
4018
4019 if (wdev->beacon_interval)
4020 return -EALREADY;
4021
4022 memset(&params, 0, sizeof(params));
4023
4024 /* these are required for START_AP */
4025 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
4026 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
4027 !info->attrs[NL80211_ATTR_BEACON_HEAD])
4028 return -EINVAL;
4029
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004030 err = nl80211_parse_beacon(info->attrs, &params.beacon);
Johannes Berg88600202012-02-13 15:17:18 +01004031 if (err)
4032 return err;
4033
4034 params.beacon_interval =
4035 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
4036 params.dtim_period =
4037 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
4038
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05304039 err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
4040 params.beacon_interval);
Johannes Berg88600202012-02-13 15:17:18 +01004041 if (err)
4042 return err;
4043
4044 /*
4045 * In theory, some of these attributes should be required here
4046 * but since they were not used when the command was originally
4047 * added, keep them optional for old user space programs to let
4048 * them continue to work with drivers that do not need the
4049 * additional information -- drivers must check!
4050 */
4051 if (info->attrs[NL80211_ATTR_SSID]) {
4052 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
4053 params.ssid_len =
4054 nla_len(info->attrs[NL80211_ATTR_SSID]);
4055 if (params.ssid_len == 0 ||
4056 params.ssid_len > IEEE80211_MAX_SSID_LEN)
4057 return -EINVAL;
4058 }
4059
4060 if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
4061 params.hidden_ssid = nla_get_u32(
4062 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
4063 if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
4064 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
4065 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
4066 return -EINVAL;
4067 }
4068
4069 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
4070
4071 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
4072 params.auth_type = nla_get_u32(
4073 info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03004074 if (!nl80211_valid_auth_type(rdev, params.auth_type,
4075 NL80211_CMD_START_AP))
Johannes Berg88600202012-02-13 15:17:18 +01004076 return -EINVAL;
4077 } else
4078 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
4079
4080 err = nl80211_crypto_settings(rdev, info, &params.crypto,
4081 NL80211_MAX_NR_CIPHER_SUITES);
4082 if (err)
4083 return err;
4084
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +05304085 if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
4086 if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
4087 return -EOPNOTSUPP;
4088 params.inactivity_timeout = nla_get_u16(
4089 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
4090 }
4091
Johannes Berg53cabad2012-11-14 15:17:28 +01004092 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
4093 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4094 return -EINVAL;
4095 params.p2p_ctwindow =
4096 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
4097 if (params.p2p_ctwindow > 127)
4098 return -EINVAL;
4099 if (params.p2p_ctwindow != 0 &&
4100 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
4101 return -EINVAL;
4102 }
4103
4104 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
4105 u8 tmp;
4106
4107 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4108 return -EINVAL;
4109 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
4110 if (tmp > 1)
4111 return -EINVAL;
4112 params.p2p_opp_ps = tmp;
4113 if (params.p2p_opp_ps != 0 &&
4114 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
4115 return -EINVAL;
4116 }
4117
Johannes Bergaa430da2012-05-16 23:50:18 +02004118 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01004119 err = nl80211_parse_chandef(rdev, info, &params.chandef);
4120 if (err)
4121 return err;
4122 } else if (wdev->preset_chandef.chan) {
4123 params.chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004124 } else if (!nl80211_get_ap_channel(rdev, &params))
Johannes Bergaa430da2012-05-16 23:50:18 +02004125 return -EINVAL;
4126
Arik Nemtsov923b3522015-07-08 15:41:44 +03004127 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
4128 wdev->iftype))
Johannes Bergaa430da2012-05-16 23:50:18 +02004129 return -EINVAL;
4130
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304131 if (info->attrs[NL80211_ATTR_TX_RATES]) {
4132 err = nl80211_parse_tx_bitrate_mask(info, &params.beacon_rate);
4133 if (err)
4134 return err;
4135
Johannes Berg8564e382016-09-19 09:44:44 +02004136 err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
4137 &params.beacon_rate);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304138 if (err)
4139 return err;
4140 }
4141
Eliad Peller18998c32014-09-10 14:07:34 +03004142 if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
4143 params.smps_mode =
4144 nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
4145 switch (params.smps_mode) {
4146 case NL80211_SMPS_OFF:
4147 break;
4148 case NL80211_SMPS_STATIC:
4149 if (!(rdev->wiphy.features &
4150 NL80211_FEATURE_STATIC_SMPS))
4151 return -EINVAL;
4152 break;
4153 case NL80211_SMPS_DYNAMIC:
4154 if (!(rdev->wiphy.features &
4155 NL80211_FEATURE_DYNAMIC_SMPS))
4156 return -EINVAL;
4157 break;
4158 default:
4159 return -EINVAL;
4160 }
4161 } else {
4162 params.smps_mode = NL80211_SMPS_OFF;
4163 }
4164
Purushottam Kushwaha6e8ef842016-07-05 13:44:51 +05304165 params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
4166 if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
4167 return -EOPNOTSUPP;
4168
Ola Olsson4baf6be2015-10-29 07:04:58 +01004169 if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
4170 params.acl = parse_acl_data(&rdev->wiphy, info);
4171 if (IS_ERR(params.acl))
4172 return PTR_ERR(params.acl);
4173 }
4174
Johannes Berg66cd7942017-02-07 22:40:44 +02004175 nl80211_calculate_ap_params(&params);
4176
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004177 wdev_lock(wdev);
Hila Gonene35e4d22012-06-27 17:19:42 +03004178 err = rdev_start_ap(rdev, dev, &params);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004179 if (!err) {
Johannes Berg683b6d32012-11-08 21:25:48 +01004180 wdev->preset_chandef = params.chandef;
Johannes Berg88600202012-02-13 15:17:18 +01004181 wdev->beacon_interval = params.beacon_interval;
Michal Kazior9e0e2962014-01-29 14:22:27 +01004182 wdev->chandef = params.chandef;
Antonio Quartulli06e191e2012-11-07 12:52:19 +01004183 wdev->ssid_len = params.ssid_len;
4184 memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
Denis Kenzior466a3062018-03-26 12:52:47 -05004185
4186 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
4187 wdev->conn_owner_nlportid = info->snd_portid;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004188 }
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004189 wdev_unlock(wdev);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05304190
4191 kfree(params.acl);
4192
Johannes Berg56d18932011-05-09 18:41:15 +02004193 return err;
Johannes Berged1b6cc2007-12-19 02:03:32 +01004194}
4195
Johannes Berg88600202012-02-13 15:17:18 +01004196static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
4197{
4198 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4199 struct net_device *dev = info->user_ptr[1];
4200 struct wireless_dev *wdev = dev->ieee80211_ptr;
4201 struct cfg80211_beacon_data params;
4202 int err;
4203
4204 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4205 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4206 return -EOPNOTSUPP;
4207
4208 if (!rdev->ops->change_beacon)
4209 return -EOPNOTSUPP;
4210
4211 if (!wdev->beacon_interval)
4212 return -EINVAL;
4213
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004214 err = nl80211_parse_beacon(info->attrs, &params);
Johannes Berg88600202012-02-13 15:17:18 +01004215 if (err)
4216 return err;
4217
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004218 wdev_lock(wdev);
4219 err = rdev_change_beacon(rdev, dev, &params);
4220 wdev_unlock(wdev);
4221
4222 return err;
Johannes Berg88600202012-02-13 15:17:18 +01004223}
4224
4225static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
Johannes Berged1b6cc2007-12-19 02:03:32 +01004226{
Johannes Berg4c476992010-10-04 21:36:35 +02004227 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4228 struct net_device *dev = info->user_ptr[1];
Johannes Berged1b6cc2007-12-19 02:03:32 +01004229
Ilan Peer7c8d5e02014-02-25 15:33:38 +02004230 return cfg80211_stop_ap(rdev, dev, false);
Johannes Berged1b6cc2007-12-19 02:03:32 +01004231}
4232
Johannes Berg5727ef12007-12-19 02:03:34 +01004233static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
4234 [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
4235 [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
4236 [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
Jouni Malinen0e467242009-05-11 21:57:55 +03004237 [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
Javier Cardonab39c48f2011-04-07 15:08:30 -07004238 [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
Johannes Bergd83023d2011-12-14 09:29:15 +01004239 [NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },
Johannes Berg5727ef12007-12-19 02:03:34 +01004240};
4241
Johannes Bergeccb8e82009-05-11 21:57:56 +03004242static int parse_station_flags(struct genl_info *info,
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004243 enum nl80211_iftype iftype,
Johannes Bergeccb8e82009-05-11 21:57:56 +03004244 struct station_parameters *params)
Johannes Berg5727ef12007-12-19 02:03:34 +01004245{
4246 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
Johannes Bergeccb8e82009-05-11 21:57:56 +03004247 struct nlattr *nla;
Johannes Berg5727ef12007-12-19 02:03:34 +01004248 int flag;
4249
Johannes Bergeccb8e82009-05-11 21:57:56 +03004250 /*
4251 * Try parsing the new attribute first so userspace
4252 * can specify both for older kernels.
4253 */
4254 nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
4255 if (nla) {
4256 struct nl80211_sta_flag_update *sta_flags;
Johannes Berg5727ef12007-12-19 02:03:34 +01004257
Johannes Bergeccb8e82009-05-11 21:57:56 +03004258 sta_flags = nla_data(nla);
4259 params->sta_flags_mask = sta_flags->mask;
4260 params->sta_flags_set = sta_flags->set;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004261 params->sta_flags_set &= params->sta_flags_mask;
Johannes Bergeccb8e82009-05-11 21:57:56 +03004262 if ((params->sta_flags_mask |
4263 params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
4264 return -EINVAL;
4265 return 0;
4266 }
4267
4268 /* if present, parse the old attribute */
4269
4270 nla = info->attrs[NL80211_ATTR_STA_FLAGS];
Johannes Berg5727ef12007-12-19 02:03:34 +01004271 if (!nla)
4272 return 0;
4273
Johannes Bergfceb6432017-04-12 14:34:07 +02004274 if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX, nla,
Johannes Bergfe521452017-04-12 14:34:08 +02004275 sta_flags_policy, info->extack))
Johannes Berg5727ef12007-12-19 02:03:34 +01004276 return -EINVAL;
4277
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004278 /*
4279 * Only allow certain flags for interface types so that
4280 * other attributes are silently ignored. Remember that
4281 * this is backward compatibility code with old userspace
4282 * and shouldn't be hit in other cases anyway.
4283 */
4284 switch (iftype) {
4285 case NL80211_IFTYPE_AP:
4286 case NL80211_IFTYPE_AP_VLAN:
4287 case NL80211_IFTYPE_P2P_GO:
4288 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4289 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4290 BIT(NL80211_STA_FLAG_WME) |
4291 BIT(NL80211_STA_FLAG_MFP);
4292 break;
4293 case NL80211_IFTYPE_P2P_CLIENT:
4294 case NL80211_IFTYPE_STATION:
4295 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4296 BIT(NL80211_STA_FLAG_TDLS_PEER);
4297 break;
4298 case NL80211_IFTYPE_MESH_POINT:
4299 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4300 BIT(NL80211_STA_FLAG_MFP) |
4301 BIT(NL80211_STA_FLAG_AUTHORIZED);
4302 default:
4303 return -EINVAL;
4304 }
Johannes Berg5727ef12007-12-19 02:03:34 +01004305
Johannes Berg3383b5a2012-05-10 20:14:43 +02004306 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
4307 if (flags[flag]) {
Johannes Bergeccb8e82009-05-11 21:57:56 +03004308 params->sta_flags_set |= (1<<flag);
Johannes Berg5727ef12007-12-19 02:03:34 +01004309
Johannes Berg3383b5a2012-05-10 20:14:43 +02004310 /* no longer support new API additions in old API */
4311 if (flag > NL80211_STA_FLAG_MAX_OLD_API)
4312 return -EINVAL;
4313 }
4314 }
4315
Johannes Berg5727ef12007-12-19 02:03:34 +01004316 return 0;
4317}
4318
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004319static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
4320 int attr)
4321{
4322 struct nlattr *rate;
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004323 u32 bitrate;
4324 u16 bitrate_compat;
Matthias Kaehlckebbf67e42017-04-17 15:59:52 -07004325 enum nl80211_rate_info rate_flg;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004326
4327 rate = nla_nest_start(msg, attr);
4328 if (!rate)
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004329 return false;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004330
4331 /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
4332 bitrate = cfg80211_calculate_bitrate(info);
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004333 /* report 16-bit bitrate only if we can */
4334 bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004335 if (bitrate > 0 &&
4336 nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
4337 return false;
4338 if (bitrate_compat > 0 &&
4339 nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
4340 return false;
4341
Johannes Bergb51f3be2015-01-15 16:14:02 +01004342 switch (info->bw) {
4343 case RATE_INFO_BW_5:
4344 rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
4345 break;
4346 case RATE_INFO_BW_10:
4347 rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
4348 break;
4349 default:
4350 WARN_ON(1);
4351 /* fall through */
4352 case RATE_INFO_BW_20:
4353 rate_flg = 0;
4354 break;
4355 case RATE_INFO_BW_40:
4356 rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
4357 break;
4358 case RATE_INFO_BW_80:
4359 rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
4360 break;
4361 case RATE_INFO_BW_160:
4362 rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
4363 break;
4364 }
4365
4366 if (rate_flg && nla_put_flag(msg, rate_flg))
4367 return false;
4368
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004369 if (info->flags & RATE_INFO_FLAGS_MCS) {
4370 if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
4371 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004372 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4373 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4374 return false;
4375 } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
4376 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
4377 return false;
4378 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
4379 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004380 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4381 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4382 return false;
4383 }
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004384
4385 nla_nest_end(msg, rate);
4386 return true;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004387}
4388
Felix Fietkau119363c2013-04-22 16:29:30 +02004389static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
4390 int id)
4391{
4392 void *attr;
4393 int i = 0;
4394
4395 if (!mask)
4396 return true;
4397
4398 attr = nla_nest_start(msg, id);
4399 if (!attr)
4400 return false;
4401
4402 for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
4403 if (!(mask & BIT(i)))
4404 continue;
4405
4406 if (nla_put_u8(msg, i, signal[i]))
4407 return false;
4408 }
4409
4410 nla_nest_end(msg, attr);
4411
4412 return true;
4413}
4414
Johannes Bergcf5ead82014-11-14 17:14:00 +01004415static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
4416 u32 seq, int flags,
John W. Linville66266b32012-03-15 13:25:41 -04004417 struct cfg80211_registered_device *rdev,
4418 struct net_device *dev,
Johannes Berg98b62182009-12-23 13:15:44 +01004419 const u8 *mac_addr, struct station_info *sinfo)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004420{
4421 void *hdr;
Paul Stewartf4263c92011-03-31 09:25:41 -07004422 struct nlattr *sinfoattr, *bss_param;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004423
Johannes Bergcf5ead82014-11-14 17:14:00 +01004424 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004425 if (!hdr)
4426 return -1;
4427
David S. Miller9360ffd2012-03-29 04:41:26 -04004428 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
4429 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
4430 nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
4431 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02004432
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004433 sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
4434 if (!sinfoattr)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004435 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004436
4437#define PUT_SINFO(attr, memb, type) do { \
Johannes Bergd686b922016-04-26 09:54:11 +02004438 BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
Mohammed Shafi Shajakhan739960f2016-04-07 19:59:34 +05304439 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
Johannes Berg319090b2014-11-17 14:08:11 +01004440 nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
4441 sinfo->memb)) \
4442 goto nla_put_failure; \
4443 } while (0)
Johannes Bergd686b922016-04-26 09:54:11 +02004444#define PUT_SINFO_U64(attr, memb) do { \
4445 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
4446 nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
4447 sinfo->memb, NL80211_STA_INFO_PAD)) \
4448 goto nla_put_failure; \
4449 } while (0)
Johannes Berg319090b2014-11-17 14:08:11 +01004450
4451 PUT_SINFO(CONNECTED_TIME, connected_time, u32);
4452 PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
4453
4454 if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) |
4455 BIT(NL80211_STA_INFO_RX_BYTES64)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004456 nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004457 (u32)sinfo->rx_bytes))
4458 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004459
4460 if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) |
4461 BIT(NL80211_STA_INFO_TX_BYTES64)) &&
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004462 nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
4463 (u32)sinfo->tx_bytes))
4464 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004465
Johannes Bergd686b922016-04-26 09:54:11 +02004466 PUT_SINFO_U64(RX_BYTES64, rx_bytes);
4467 PUT_SINFO_U64(TX_BYTES64, tx_bytes);
Johannes Berg319090b2014-11-17 14:08:11 +01004468 PUT_SINFO(LLID, llid, u16);
4469 PUT_SINFO(PLID, plid, u16);
4470 PUT_SINFO(PLINK_STATE, plink_state, u8);
Johannes Bergd686b922016-04-26 09:54:11 +02004471 PUT_SINFO_U64(RX_DURATION, rx_duration);
Johannes Berg319090b2014-11-17 14:08:11 +01004472
John W. Linville66266b32012-03-15 13:25:41 -04004473 switch (rdev->wiphy.signal_type) {
4474 case CFG80211_SIGNAL_TYPE_MBM:
Johannes Berg319090b2014-11-17 14:08:11 +01004475 PUT_SINFO(SIGNAL, signal, u8);
4476 PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
John W. Linville66266b32012-03-15 13:25:41 -04004477 break;
4478 default:
4479 break;
4480 }
Johannes Berg319090b2014-11-17 14:08:11 +01004481 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004482 if (!nl80211_put_signal(msg, sinfo->chains,
4483 sinfo->chain_signal,
4484 NL80211_STA_INFO_CHAIN_SIGNAL))
4485 goto nla_put_failure;
4486 }
Johannes Berg319090b2014-11-17 14:08:11 +01004487 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004488 if (!nl80211_put_signal(msg, sinfo->chains,
4489 sinfo->chain_signal_avg,
4490 NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
4491 goto nla_put_failure;
4492 }
Johannes Berg319090b2014-11-17 14:08:11 +01004493 if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004494 if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
4495 NL80211_STA_INFO_TX_BITRATE))
Henning Rogge420e7fa2008-12-11 22:04:19 +01004496 goto nla_put_failure;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004497 }
Johannes Berg319090b2014-11-17 14:08:11 +01004498 if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004499 if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
4500 NL80211_STA_INFO_RX_BITRATE))
4501 goto nla_put_failure;
Henning Rogge420e7fa2008-12-11 22:04:19 +01004502 }
Johannes Berg319090b2014-11-17 14:08:11 +01004503
4504 PUT_SINFO(RX_PACKETS, rx_packets, u32);
4505 PUT_SINFO(TX_PACKETS, tx_packets, u32);
4506 PUT_SINFO(TX_RETRIES, tx_retries, u32);
4507 PUT_SINFO(TX_FAILED, tx_failed, u32);
4508 PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
4509 PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
4510 PUT_SINFO(LOCAL_PM, local_pm, u32);
4511 PUT_SINFO(PEER_PM, peer_pm, u32);
4512 PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
4513
4514 if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) {
Paul Stewartf4263c92011-03-31 09:25:41 -07004515 bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
4516 if (!bss_param)
4517 goto nla_put_failure;
4518
David S. Miller9360ffd2012-03-29 04:41:26 -04004519 if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
4520 nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
4521 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
4522 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
4523 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
4524 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
4525 nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
4526 sinfo->bss_param.dtim_period) ||
4527 nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
4528 sinfo->bss_param.beacon_interval))
4529 goto nla_put_failure;
Paul Stewartf4263c92011-03-31 09:25:41 -07004530
4531 nla_nest_end(msg, bss_param);
4532 }
Johannes Berg319090b2014-11-17 14:08:11 +01004533 if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004534 nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
4535 sizeof(struct nl80211_sta_flag_update),
4536 &sinfo->sta_flags))
4537 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004538
Johannes Bergd686b922016-04-26 09:54:11 +02004539 PUT_SINFO_U64(T_OFFSET, t_offset);
4540 PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
4541 PUT_SINFO_U64(BEACON_RX, rx_beacon);
Johannes Berga76b1942014-11-17 14:12:22 +01004542 PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
Venkateswara Naralasettyc4b50cd2018-02-13 11:03:06 +05304543 PUT_SINFO(ACK_SIGNAL, ack_signal, u8);
Balaji Pothunoori81d54392018-04-16 20:18:40 +05304544 if (wiphy_ext_feature_isset(&rdev->wiphy,
4545 NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT))
4546 PUT_SINFO(DATA_ACK_SIGNAL_AVG, avg_ack_signal, s8);
Johannes Berg319090b2014-11-17 14:08:11 +01004547
4548#undef PUT_SINFO
Johannes Bergd686b922016-04-26 09:54:11 +02004549#undef PUT_SINFO_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004550
4551 if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) {
4552 struct nlattr *tidsattr;
4553 int tid;
4554
4555 tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS);
4556 if (!tidsattr)
4557 goto nla_put_failure;
4558
4559 for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
4560 struct cfg80211_tid_stats *tidstats;
4561 struct nlattr *tidattr;
4562
4563 tidstats = &sinfo->pertid[tid];
4564
4565 if (!tidstats->filled)
4566 continue;
4567
4568 tidattr = nla_nest_start(msg, tid + 1);
4569 if (!tidattr)
4570 goto nla_put_failure;
4571
Johannes Bergd686b922016-04-26 09:54:11 +02004572#define PUT_TIDVAL_U64(attr, memb) do { \
Johannes Berg6de39802014-12-19 12:34:00 +01004573 if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
Johannes Bergd686b922016-04-26 09:54:11 +02004574 nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
4575 tidstats->memb, NL80211_TID_STATS_PAD)) \
Johannes Berg6de39802014-12-19 12:34:00 +01004576 goto nla_put_failure; \
4577 } while (0)
4578
Johannes Bergd686b922016-04-26 09:54:11 +02004579 PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
4580 PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
4581 PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
4582 PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
Johannes Berg6de39802014-12-19 12:34:00 +01004583
Johannes Bergd686b922016-04-26 09:54:11 +02004584#undef PUT_TIDVAL_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004585 nla_nest_end(msg, tidattr);
4586 }
4587
4588 nla_nest_end(msg, tidsattr);
4589 }
4590
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004591 nla_nest_end(msg, sinfoattr);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004592
Johannes Berg319090b2014-11-17 14:08:11 +01004593 if (sinfo->assoc_req_ies_len &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004594 nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
4595 sinfo->assoc_req_ies))
4596 goto nla_put_failure;
Jouni Malinen50d3dfb2011-08-08 12:11:52 +03004597
Johannes Berg053c0952015-01-16 22:09:00 +01004598 genlmsg_end(msg, hdr);
4599 return 0;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004600
4601 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07004602 genlmsg_cancel(msg, hdr);
4603 return -EMSGSIZE;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004604}
4605
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004606static int nl80211_dump_station(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004607 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004608{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004609 struct station_info sinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004610 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02004611 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004612 u8 mac_addr[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02004613 int sta_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004614 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004615
Johannes Bergea90e0d2017-03-15 14:26:04 +01004616 rtnl_lock();
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004617 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02004618 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +01004619 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004620
Johannes Berg97990a02013-04-19 01:02:55 +02004621 if (!wdev->netdev) {
4622 err = -EINVAL;
4623 goto out_err;
4624 }
4625
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004626 if (!rdev->ops->dump_station) {
Jouni Malineneec60b02009-03-20 21:21:19 +02004627 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004628 goto out_err;
4629 }
4630
Johannes Bergbba95fe2008-07-29 13:22:51 +02004631 while (1) {
Jouni Malinenf612ced2011-08-11 11:46:22 +03004632 memset(&sinfo, 0, sizeof(sinfo));
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004633 err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
Hila Gonene35e4d22012-06-27 17:19:42 +03004634 mac_addr, &sinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02004635 if (err == -ENOENT)
4636 break;
4637 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01004638 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004639
Johannes Bergcf5ead82014-11-14 17:14:00 +01004640 if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004641 NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004642 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004643 rdev, wdev->netdev, mac_addr,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004644 &sinfo) < 0)
4645 goto out;
4646
4647 sta_idx++;
4648 }
4649
Johannes Bergbba95fe2008-07-29 13:22:51 +02004650 out:
Johannes Berg97990a02013-04-19 01:02:55 +02004651 cb->args[2] = sta_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004652 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004653 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01004654 rtnl_unlock();
Johannes Bergbba95fe2008-07-29 13:22:51 +02004655
4656 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004657}
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004658
Johannes Berg5727ef12007-12-19 02:03:34 +01004659static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
4660{
Johannes Berg4c476992010-10-04 21:36:35 +02004661 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4662 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004663 struct station_info sinfo;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004664 struct sk_buff *msg;
4665 u8 *mac_addr = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02004666 int err;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004667
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004668 memset(&sinfo, 0, sizeof(sinfo));
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004669
4670 if (!info->attrs[NL80211_ATTR_MAC])
4671 return -EINVAL;
4672
4673 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4674
Johannes Berg4c476992010-10-04 21:36:35 +02004675 if (!rdev->ops->get_station)
4676 return -EOPNOTSUPP;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004677
Hila Gonene35e4d22012-06-27 17:19:42 +03004678 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004679 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02004680 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004681
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07004682 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004683 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02004684 return -ENOMEM;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004685
Johannes Bergcf5ead82014-11-14 17:14:00 +01004686 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
4687 info->snd_portid, info->snd_seq, 0,
John W. Linville66266b32012-03-15 13:25:41 -04004688 rdev, dev, mac_addr, &sinfo) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02004689 nlmsg_free(msg);
4690 return -ENOBUFS;
4691 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004692
Johannes Berg4c476992010-10-04 21:36:35 +02004693 return genlmsg_reply(msg, info);
Johannes Berg5727ef12007-12-19 02:03:34 +01004694}
4695
Johannes Berg77ee7c82013-02-15 00:48:33 +01004696int cfg80211_check_station_change(struct wiphy *wiphy,
4697 struct station_parameters *params,
4698 enum cfg80211_station_type statype)
4699{
Ayala Bekere4208422015-10-23 11:20:06 +03004700 if (params->listen_interval != -1 &&
4701 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004702 return -EINVAL;
Ayala Bekere4208422015-10-23 11:20:06 +03004703
Ayala Beker17b94242016-03-17 15:41:38 +02004704 if (params->support_p2p_ps != -1 &&
4705 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
4706 return -EINVAL;
4707
Arik Nemtsovc72e1142014-07-17 17:14:29 +03004708 if (params->aid &&
Ayala Bekere4208422015-10-23 11:20:06 +03004709 !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
4710 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004711 return -EINVAL;
4712
4713 /* When you run into this, adjust the code below for the new flag */
4714 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
4715
4716 switch (statype) {
Thomas Pederseneef941e2013-03-04 13:06:11 -08004717 case CFG80211_STA_MESH_PEER_KERNEL:
4718 case CFG80211_STA_MESH_PEER_USER:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004719 /*
4720 * No ignoring the TDLS flag here -- the userspace mesh
4721 * code doesn't have the bug of including TDLS in the
4722 * mask everywhere.
4723 */
4724 if (params->sta_flags_mask &
4725 ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4726 BIT(NL80211_STA_FLAG_MFP) |
4727 BIT(NL80211_STA_FLAG_AUTHORIZED)))
4728 return -EINVAL;
4729 break;
4730 case CFG80211_STA_TDLS_PEER_SETUP:
4731 case CFG80211_STA_TDLS_PEER_ACTIVE:
4732 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
4733 return -EINVAL;
4734 /* ignore since it can't change */
4735 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4736 break;
4737 default:
4738 /* disallow mesh-specific things */
4739 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
4740 return -EINVAL;
4741 if (params->local_pm)
4742 return -EINVAL;
4743 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4744 return -EINVAL;
4745 }
4746
4747 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4748 statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
4749 /* TDLS can't be set, ... */
4750 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
4751 return -EINVAL;
4752 /*
4753 * ... but don't bother the driver with it. This works around
4754 * a hostapd/wpa_supplicant issue -- it always includes the
4755 * TLDS_PEER flag in the mask even for AP mode.
4756 */
4757 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4758 }
4759
Ayala Beker47edb112015-09-21 15:49:53 +03004760 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4761 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004762 /* reject other things that can't change */
4763 if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
4764 return -EINVAL;
4765 if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
4766 return -EINVAL;
4767 if (params->supported_rates)
4768 return -EINVAL;
4769 if (params->ext_capab || params->ht_capa || params->vht_capa)
4770 return -EINVAL;
4771 }
4772
Ayala Beker47edb112015-09-21 15:49:53 +03004773 if (statype != CFG80211_STA_AP_CLIENT &&
4774 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004775 if (params->vlan)
4776 return -EINVAL;
4777 }
4778
4779 switch (statype) {
4780 case CFG80211_STA_AP_MLME_CLIENT:
4781 /* Use this only for authorizing/unauthorizing a station */
4782 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4783 return -EOPNOTSUPP;
4784 break;
4785 case CFG80211_STA_AP_CLIENT:
Ayala Beker47edb112015-09-21 15:49:53 +03004786 case CFG80211_STA_AP_CLIENT_UNASSOC:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004787 /* accept only the listed bits */
4788 if (params->sta_flags_mask &
4789 ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4790 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4791 BIT(NL80211_STA_FLAG_ASSOCIATED) |
4792 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4793 BIT(NL80211_STA_FLAG_WME) |
4794 BIT(NL80211_STA_FLAG_MFP)))
4795 return -EINVAL;
4796
4797 /* but authenticated/associated only if driver handles it */
4798 if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
4799 params->sta_flags_mask &
4800 (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4801 BIT(NL80211_STA_FLAG_ASSOCIATED)))
4802 return -EINVAL;
4803 break;
4804 case CFG80211_STA_IBSS:
4805 case CFG80211_STA_AP_STA:
4806 /* reject any changes other than AUTHORIZED */
4807 if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
4808 return -EINVAL;
4809 break;
4810 case CFG80211_STA_TDLS_PEER_SETUP:
4811 /* reject any changes other than AUTHORIZED or WME */
4812 if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4813 BIT(NL80211_STA_FLAG_WME)))
4814 return -EINVAL;
4815 /* force (at least) rates when authorizing */
4816 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
4817 !params->supported_rates)
4818 return -EINVAL;
4819 break;
4820 case CFG80211_STA_TDLS_PEER_ACTIVE:
4821 /* reject any changes */
4822 return -EINVAL;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004823 case CFG80211_STA_MESH_PEER_KERNEL:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004824 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4825 return -EINVAL;
4826 break;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004827 case CFG80211_STA_MESH_PEER_USER:
Chun-Yeow Yeoh42925042015-04-18 01:30:02 +08004828 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
4829 params->plink_action != NL80211_PLINK_ACTION_BLOCK)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004830 return -EINVAL;
4831 break;
4832 }
4833
Beni Lev06f7c882016-07-19 19:28:56 +03004834 /*
4835 * Older kernel versions ignored this attribute entirely, so don't
4836 * reject attempts to update it but mark it as unused instead so the
4837 * driver won't look at the data.
4838 */
4839 if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
4840 statype != CFG80211_STA_TDLS_PEER_SETUP)
4841 params->opmode_notif_used = false;
4842
Johannes Berg77ee7c82013-02-15 00:48:33 +01004843 return 0;
4844}
4845EXPORT_SYMBOL(cfg80211_check_station_change);
4846
Johannes Berg5727ef12007-12-19 02:03:34 +01004847/*
Felix Fietkauc258d2d2009-11-11 17:23:31 +01004848 * Get vlan interface making sure it is running and on the right wiphy.
Johannes Berg5727ef12007-12-19 02:03:34 +01004849 */
Johannes Berg80b99892011-11-18 16:23:01 +01004850static struct net_device *get_vlan(struct genl_info *info,
4851 struct cfg80211_registered_device *rdev)
Johannes Berg5727ef12007-12-19 02:03:34 +01004852{
Johannes Berg463d0182009-07-14 00:33:35 +02004853 struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
Johannes Berg80b99892011-11-18 16:23:01 +01004854 struct net_device *v;
4855 int ret;
Johannes Berg5727ef12007-12-19 02:03:34 +01004856
Johannes Berg80b99892011-11-18 16:23:01 +01004857 if (!vlanattr)
4858 return NULL;
4859
4860 v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
4861 if (!v)
4862 return ERR_PTR(-ENODEV);
4863
4864 if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
4865 ret = -EINVAL;
4866 goto error;
Johannes Berg5727ef12007-12-19 02:03:34 +01004867 }
Johannes Berg80b99892011-11-18 16:23:01 +01004868
Johannes Berg77ee7c82013-02-15 00:48:33 +01004869 if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
4870 v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4871 v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
4872 ret = -EINVAL;
4873 goto error;
4874 }
4875
Johannes Berg80b99892011-11-18 16:23:01 +01004876 if (!netif_running(v)) {
4877 ret = -ENETDOWN;
4878 goto error;
4879 }
4880
4881 return v;
4882 error:
4883 dev_put(v);
4884 return ERR_PTR(ret);
Johannes Berg5727ef12007-12-19 02:03:34 +01004885}
4886
Johannes Berg94e860f2014-01-20 23:58:15 +01004887static const struct nla_policy
4888nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
Jouni Malinendf881292013-02-14 21:10:54 +02004889 [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
4890 [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
4891};
4892
Johannes Bergff276692013-02-15 00:09:01 +01004893static int nl80211_parse_sta_wme(struct genl_info *info,
4894 struct station_parameters *params)
Jouni Malinendf881292013-02-14 21:10:54 +02004895{
Jouni Malinendf881292013-02-14 21:10:54 +02004896 struct nlattr *tb[NL80211_STA_WME_MAX + 1];
4897 struct nlattr *nla;
4898 int err;
4899
Jouni Malinendf881292013-02-14 21:10:54 +02004900 /* parse WME attributes if present */
4901 if (!info->attrs[NL80211_ATTR_STA_WME])
4902 return 0;
4903
4904 nla = info->attrs[NL80211_ATTR_STA_WME];
4905 err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
Johannes Bergfe521452017-04-12 14:34:08 +02004906 nl80211_sta_wme_policy, info->extack);
Jouni Malinendf881292013-02-14 21:10:54 +02004907 if (err)
4908 return err;
4909
4910 if (tb[NL80211_STA_WME_UAPSD_QUEUES])
4911 params->uapsd_queues = nla_get_u8(
4912 tb[NL80211_STA_WME_UAPSD_QUEUES]);
4913 if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
4914 return -EINVAL;
4915
4916 if (tb[NL80211_STA_WME_MAX_SP])
4917 params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
4918
4919 if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
4920 return -EINVAL;
4921
4922 params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
4923
4924 return 0;
4925}
4926
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304927static int nl80211_parse_sta_channel_info(struct genl_info *info,
4928 struct station_parameters *params)
4929{
4930 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
4931 params->supported_channels =
4932 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4933 params->supported_channels_len =
4934 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4935 /*
4936 * Need to include at least one (first channel, number of
4937 * channels) tuple for each subband, and must have proper
4938 * tuples for the rest of the data as well.
4939 */
4940 if (params->supported_channels_len < 2)
4941 return -EINVAL;
4942 if (params->supported_channels_len % 2)
4943 return -EINVAL;
4944 }
4945
4946 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
4947 params->supported_oper_classes =
4948 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4949 params->supported_oper_classes_len =
4950 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4951 /*
4952 * The value of the Length field of the Supported Operating
4953 * Classes element is between 2 and 253.
4954 */
4955 if (params->supported_oper_classes_len < 2 ||
4956 params->supported_oper_classes_len > 253)
4957 return -EINVAL;
4958 }
4959 return 0;
4960}
4961
Johannes Bergff276692013-02-15 00:09:01 +01004962static int nl80211_set_station_tdls(struct genl_info *info,
4963 struct station_parameters *params)
4964{
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304965 int err;
Johannes Bergff276692013-02-15 00:09:01 +01004966 /* Dummy STA entry gets updated once the peer capabilities are known */
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03004967 if (info->attrs[NL80211_ATTR_PEER_AID])
4968 params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Johannes Bergff276692013-02-15 00:09:01 +01004969 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
4970 params->ht_capa =
4971 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
4972 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
4973 params->vht_capa =
4974 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
4975
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304976 err = nl80211_parse_sta_channel_info(info, params);
4977 if (err)
4978 return err;
4979
Johannes Bergff276692013-02-15 00:09:01 +01004980 return nl80211_parse_sta_wme(info, params);
4981}
4982
Johannes Berg5727ef12007-12-19 02:03:34 +01004983static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
4984{
Johannes Berg4c476992010-10-04 21:36:35 +02004985 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02004986 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01004987 struct station_parameters params;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004988 u8 *mac_addr;
4989 int err;
Johannes Berg5727ef12007-12-19 02:03:34 +01004990
4991 memset(&params, 0, sizeof(params));
4992
Johannes Berg77ee7c82013-02-15 00:48:33 +01004993 if (!rdev->ops->change_station)
4994 return -EOPNOTSUPP;
4995
Ayala Bekere4208422015-10-23 11:20:06 +03004996 /*
4997 * AID and listen_interval properties can be set only for unassociated
4998 * station. Include these parameters here and will check them in
4999 * cfg80211_check_station_change().
5000 */
Ayala Bekera9bc31e2015-11-26 16:26:12 +01005001 if (info->attrs[NL80211_ATTR_STA_AID])
5002 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Ayala Bekere4208422015-10-23 11:20:06 +03005003
5004 if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
5005 params.listen_interval =
5006 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
5007 else
5008 params.listen_interval = -1;
Johannes Berg5727ef12007-12-19 02:03:34 +01005009
Ayala Beker17b94242016-03-17 15:41:38 +02005010 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
5011 u8 tmp;
5012
5013 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
5014 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
5015 return -EINVAL;
5016
5017 params.support_p2p_ps = tmp;
5018 } else {
5019 params.support_p2p_ps = -1;
5020 }
5021
Johannes Berg5727ef12007-12-19 02:03:34 +01005022 if (!info->attrs[NL80211_ATTR_MAC])
5023 return -EINVAL;
5024
5025 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
5026
5027 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
5028 params.supported_rates =
5029 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5030 params.supported_rates_len =
5031 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5032 }
5033
Jouni Malinen9d62a982013-02-14 21:10:13 +02005034 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
5035 params.capability =
5036 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
5037 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
5038 }
5039
5040 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
5041 params.ext_capab =
5042 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5043 params.ext_capab_len =
5044 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5045 }
5046
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005047 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01005048 return -EINVAL;
5049
Johannes Bergf8bacc22013-02-14 23:27:01 +01005050 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005051 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01005052 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
5053 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
5054 return -EINVAL;
5055 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005056
Johannes Bergf8bacc22013-02-14 23:27:01 +01005057 if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
Javier Cardona9c3990a2011-05-03 16:57:11 -07005058 params.plink_state =
Johannes Bergf8bacc22013-02-14 23:27:01 +01005059 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
5060 if (params.plink_state >= NUM_NL80211_PLINK_STATES)
5061 return -EINVAL;
Masashi Honma7d27a0b2016-07-01 10:19:34 +09005062 if (info->attrs[NL80211_ATTR_MESH_PEER_AID]) {
5063 params.peer_aid = nla_get_u16(
5064 info->attrs[NL80211_ATTR_MESH_PEER_AID]);
5065 if (params.peer_aid > IEEE80211_MAX_AID)
5066 return -EINVAL;
5067 }
Johannes Bergf8bacc22013-02-14 23:27:01 +01005068 params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
5069 }
Javier Cardona9c3990a2011-05-03 16:57:11 -07005070
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005071 if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
5072 enum nl80211_mesh_power_mode pm = nla_get_u32(
5073 info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
5074
5075 if (pm <= NL80211_MESH_POWER_UNKNOWN ||
5076 pm > NL80211_MESH_POWER_MAX)
5077 return -EINVAL;
5078
5079 params.local_pm = pm;
5080 }
5081
Beni Lev06f7c882016-07-19 19:28:56 +03005082 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
5083 params.opmode_notif_used = true;
5084 params.opmode_notif =
5085 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
5086 }
5087
Johannes Berg77ee7c82013-02-15 00:48:33 +01005088 /* Include parameters for TDLS peer (will check later) */
5089 err = nl80211_set_station_tdls(info, &params);
5090 if (err)
5091 return err;
5092
5093 params.vlan = get_vlan(info, rdev);
5094 if (IS_ERR(params.vlan))
5095 return PTR_ERR(params.vlan);
5096
Johannes Berga97f4422009-06-18 17:23:43 +02005097 switch (dev->ieee80211_ptr->iftype) {
5098 case NL80211_IFTYPE_AP:
5099 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02005100 case NL80211_IFTYPE_P2P_GO:
Johannes Berg074ac8d2010-09-16 14:58:22 +02005101 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berga97f4422009-06-18 17:23:43 +02005102 case NL80211_IFTYPE_STATION:
Antonio Quartulli267335d2012-01-31 20:25:47 +01005103 case NL80211_IFTYPE_ADHOC:
Johannes Berga97f4422009-06-18 17:23:43 +02005104 case NL80211_IFTYPE_MESH_POINT:
Johannes Berga97f4422009-06-18 17:23:43 +02005105 break;
5106 default:
Johannes Berg77ee7c82013-02-15 00:48:33 +01005107 err = -EOPNOTSUPP;
5108 goto out_put_vlan;
Johannes Berg034d6552009-05-27 10:35:29 +02005109 }
5110
Johannes Berg77ee7c82013-02-15 00:48:33 +01005111 /* driver will call cfg80211_check_station_change() */
Hila Gonene35e4d22012-06-27 17:19:42 +03005112 err = rdev_change_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005113
Johannes Berg77ee7c82013-02-15 00:48:33 +01005114 out_put_vlan:
Johannes Berg5727ef12007-12-19 02:03:34 +01005115 if (params.vlan)
5116 dev_put(params.vlan);
Johannes Berg3b858752009-03-12 09:55:09 +01005117
Johannes Berg5727ef12007-12-19 02:03:34 +01005118 return err;
5119}
5120
5121static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
5122{
Johannes Berg4c476992010-10-04 21:36:35 +02005123 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg5727ef12007-12-19 02:03:34 +01005124 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02005125 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01005126 struct station_parameters params;
5127 u8 *mac_addr = NULL;
Johannes Bergbda95eb2015-11-26 16:26:13 +01005128 u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5129 BIT(NL80211_STA_FLAG_ASSOCIATED);
Johannes Berg5727ef12007-12-19 02:03:34 +01005130
5131 memset(&params, 0, sizeof(params));
5132
Johannes Berg984c3112013-02-14 23:43:25 +01005133 if (!rdev->ops->add_station)
5134 return -EOPNOTSUPP;
5135
Johannes Berg5727ef12007-12-19 02:03:34 +01005136 if (!info->attrs[NL80211_ATTR_MAC])
5137 return -EINVAL;
5138
Johannes Berg5727ef12007-12-19 02:03:34 +01005139 if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
5140 return -EINVAL;
5141
5142 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
5143 return -EINVAL;
5144
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03005145 if (!info->attrs[NL80211_ATTR_STA_AID] &&
5146 !info->attrs[NL80211_ATTR_PEER_AID])
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02005147 return -EINVAL;
5148
Johannes Berg5727ef12007-12-19 02:03:34 +01005149 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
5150 params.supported_rates =
5151 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5152 params.supported_rates_len =
5153 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5154 params.listen_interval =
5155 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
Johannes Berg51b50fb2009-05-24 16:42:30 +02005156
Ayala Beker17b94242016-03-17 15:41:38 +02005157 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
5158 u8 tmp;
5159
5160 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
5161 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
5162 return -EINVAL;
5163
5164 params.support_p2p_ps = tmp;
5165 } else {
5166 /*
5167 * if not specified, assume it's supported for P2P GO interface,
5168 * and is NOT supported for AP interface
5169 */
5170 params.support_p2p_ps =
5171 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO;
5172 }
5173
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005174 if (info->attrs[NL80211_ATTR_PEER_AID])
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03005175 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005176 else
5177 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02005178 if (!params.aid || params.aid > IEEE80211_MAX_AID)
5179 return -EINVAL;
Johannes Berg51b50fb2009-05-24 16:42:30 +02005180
Jouni Malinen9d62a982013-02-14 21:10:13 +02005181 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
5182 params.capability =
5183 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
5184 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
5185 }
5186
5187 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
5188 params.ext_capab =
5189 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5190 params.ext_capab_len =
5191 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5192 }
5193
Jouni Malinen36aedc92008-08-25 11:58:58 +03005194 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
5195 params.ht_capa =
5196 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005197
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +00005198 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
5199 params.vht_capa =
5200 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
5201
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +01005202 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
5203 params.opmode_notif_used = true;
5204 params.opmode_notif =
5205 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
5206 }
5207
Johannes Bergf8bacc22013-02-14 23:27:01 +01005208 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Javier Cardona96b78df2011-04-07 15:08:33 -07005209 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01005210 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
5211 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
5212 return -EINVAL;
5213 }
Javier Cardona96b78df2011-04-07 15:08:33 -07005214
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305215 err = nl80211_parse_sta_channel_info(info, &params);
5216 if (err)
5217 return err;
5218
Johannes Bergff276692013-02-15 00:09:01 +01005219 err = nl80211_parse_sta_wme(info, &params);
5220 if (err)
5221 return err;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005222
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005223 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01005224 return -EINVAL;
5225
Johannes Berg496fcc22015-03-12 08:53:27 +02005226 /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
5227 * as userspace might just pass through the capabilities from the IEs
5228 * directly, rather than enforcing this restriction and returning an
5229 * error in this case.
5230 */
5231 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
5232 params.ht_capa = NULL;
5233 params.vht_capa = NULL;
5234 }
5235
Johannes Berg77ee7c82013-02-15 00:48:33 +01005236 /* When you run into this, adjust the code below for the new flag */
5237 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
5238
Johannes Bergbdd90d52011-12-14 12:20:27 +01005239 switch (dev->ieee80211_ptr->iftype) {
5240 case NL80211_IFTYPE_AP:
5241 case NL80211_IFTYPE_AP_VLAN:
5242 case NL80211_IFTYPE_P2P_GO:
Johannes Berg984c3112013-02-14 23:43:25 +01005243 /* ignore WME attributes if iface/sta is not capable */
5244 if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
5245 !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
5246 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005247
Johannes Bergbdd90d52011-12-14 12:20:27 +01005248 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005249 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5250 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005251 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005252 /* but don't bother the driver with it */
5253 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
Eliad Pellerc75786c2011-08-23 14:37:46 +03005254
Johannes Bergd582cff2012-10-26 17:53:44 +02005255 /* allow authenticated/associated only if driver handles it */
5256 if (!(rdev->wiphy.features &
5257 NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
Johannes Bergbda95eb2015-11-26 16:26:13 +01005258 params.sta_flags_mask & auth_assoc)
Johannes Bergd582cff2012-10-26 17:53:44 +02005259 return -EINVAL;
5260
Johannes Bergbda95eb2015-11-26 16:26:13 +01005261 /* Older userspace, or userspace wanting to be compatible with
5262 * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
5263 * and assoc flags in the mask, but assumes the station will be
5264 * added as associated anyway since this was the required driver
5265 * behaviour before NL80211_FEATURE_FULL_AP_CLIENT_STATE was
5266 * introduced.
5267 * In order to not bother drivers with this quirk in the API
5268 * set the flags in both the mask and set for new stations in
5269 * this case.
5270 */
5271 if (!(params.sta_flags_mask & auth_assoc)) {
5272 params.sta_flags_mask |= auth_assoc;
5273 params.sta_flags_set |= auth_assoc;
5274 }
5275
Johannes Bergbdd90d52011-12-14 12:20:27 +01005276 /* must be last in here for error handling */
5277 params.vlan = get_vlan(info, rdev);
5278 if (IS_ERR(params.vlan))
5279 return PTR_ERR(params.vlan);
5280 break;
5281 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg984c3112013-02-14 23:43:25 +01005282 /* ignore uAPSD data */
5283 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5284
Johannes Bergd582cff2012-10-26 17:53:44 +02005285 /* associated is disallowed */
5286 if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
5287 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005288 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005289 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5290 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005291 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005292 break;
5293 case NL80211_IFTYPE_STATION:
Johannes Berg93d08f02013-03-04 09:29:46 +01005294 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg984c3112013-02-14 23:43:25 +01005295 /* ignore uAPSD data */
5296 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5297
Johannes Berg77ee7c82013-02-15 00:48:33 +01005298 /* these are disallowed */
5299 if (params.sta_flags_mask &
5300 (BIT(NL80211_STA_FLAG_ASSOCIATED) |
5301 BIT(NL80211_STA_FLAG_AUTHENTICATED)))
Johannes Bergd582cff2012-10-26 17:53:44 +02005302 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005303 /* Only TDLS peers can be added */
5304 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
5305 return -EINVAL;
5306 /* Can only add if TDLS ... */
5307 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
5308 return -EOPNOTSUPP;
5309 /* ... with external setup is supported */
5310 if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
5311 return -EOPNOTSUPP;
Johannes Berg77ee7c82013-02-15 00:48:33 +01005312 /*
5313 * Older wpa_supplicant versions always mark the TDLS peer
5314 * as authorized, but it shouldn't yet be.
5315 */
5316 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
Johannes Bergbdd90d52011-12-14 12:20:27 +01005317 break;
5318 default:
5319 return -EOPNOTSUPP;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005320 }
5321
Johannes Bergbdd90d52011-12-14 12:20:27 +01005322 /* be aware of params.vlan when changing code here */
Johannes Berg5727ef12007-12-19 02:03:34 +01005323
Hila Gonene35e4d22012-06-27 17:19:42 +03005324 err = rdev_add_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005325
Johannes Berg5727ef12007-12-19 02:03:34 +01005326 if (params.vlan)
5327 dev_put(params.vlan);
Johannes Berg5727ef12007-12-19 02:03:34 +01005328 return err;
5329}
5330
5331static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
5332{
Johannes Berg4c476992010-10-04 21:36:35 +02005333 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5334 struct net_device *dev = info->user_ptr[1];
Jouni Malinen89c771e2014-10-10 20:52:40 +03005335 struct station_del_parameters params;
5336
5337 memset(&params, 0, sizeof(params));
Johannes Berg5727ef12007-12-19 02:03:34 +01005338
5339 if (info->attrs[NL80211_ATTR_MAC])
Jouni Malinen89c771e2014-10-10 20:52:40 +03005340 params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005341
Johannes Berge80cf852009-05-11 14:43:13 +02005342 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Marco Porschd5d9de02010-03-30 10:00:16 +02005343 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
Johannes Berg074ac8d2010-09-16 14:58:22 +02005344 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
Johannes Berg4c476992010-10-04 21:36:35 +02005345 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5346 return -EINVAL;
Johannes Berge80cf852009-05-11 14:43:13 +02005347
Johannes Berg4c476992010-10-04 21:36:35 +02005348 if (!rdev->ops->del_station)
5349 return -EOPNOTSUPP;
Johannes Berg5727ef12007-12-19 02:03:34 +01005350
Jouni Malinen98856862014-10-20 13:20:45 +03005351 if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
5352 params.subtype =
5353 nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
5354 if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
5355 params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
5356 return -EINVAL;
5357 } else {
5358 /* Default to Deauthentication frame */
5359 params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
5360 }
5361
5362 if (info->attrs[NL80211_ATTR_REASON_CODE]) {
5363 params.reason_code =
5364 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
5365 if (params.reason_code == 0)
5366 return -EINVAL; /* 0 is reserved */
5367 } else {
5368 /* Default to reason code 2 */
5369 params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
5370 }
5371
Jouni Malinen89c771e2014-10-10 20:52:40 +03005372 return rdev_del_station(rdev, dev, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005373}
5374
Eric W. Biederman15e47302012-09-07 20:12:54 +00005375static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005376 int flags, struct net_device *dev,
5377 u8 *dst, u8 *next_hop,
5378 struct mpath_info *pinfo)
5379{
5380 void *hdr;
5381 struct nlattr *pinfoattr;
5382
Henning Rogge1ef4c852014-11-04 16:14:58 +01005383 hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005384 if (!hdr)
5385 return -1;
5386
David S. Miller9360ffd2012-03-29 04:41:26 -04005387 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5388 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
5389 nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
5390 nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
5391 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02005392
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005393 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
5394 if (!pinfoattr)
5395 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005396 if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
5397 nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
5398 pinfo->frame_qlen))
5399 goto nla_put_failure;
5400 if (((pinfo->filled & MPATH_INFO_SN) &&
5401 nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
5402 ((pinfo->filled & MPATH_INFO_METRIC) &&
5403 nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
5404 pinfo->metric)) ||
5405 ((pinfo->filled & MPATH_INFO_EXPTIME) &&
5406 nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
5407 pinfo->exptime)) ||
5408 ((pinfo->filled & MPATH_INFO_FLAGS) &&
5409 nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
5410 pinfo->flags)) ||
5411 ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
5412 nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
5413 pinfo->discovery_timeout)) ||
5414 ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
5415 nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
5416 pinfo->discovery_retries)))
5417 goto nla_put_failure;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005418
5419 nla_nest_end(msg, pinfoattr);
5420
Johannes Berg053c0952015-01-16 22:09:00 +01005421 genlmsg_end(msg, hdr);
5422 return 0;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005423
5424 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07005425 genlmsg_cancel(msg, hdr);
5426 return -EMSGSIZE;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005427}
5428
5429static int nl80211_dump_mpath(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005430 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005431{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005432 struct mpath_info pinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005433 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02005434 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005435 u8 dst[ETH_ALEN];
5436 u8 next_hop[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02005437 int path_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005438 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005439
Johannes Bergea90e0d2017-03-15 14:26:04 +01005440 rtnl_lock();
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005441 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02005442 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +01005443 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005444
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005445 if (!rdev->ops->dump_mpath) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005446 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005447 goto out_err;
5448 }
5449
Johannes Berg97990a02013-04-19 01:02:55 +02005450 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005451 err = -EOPNOTSUPP;
Roel Kluin0448b5f2009-08-22 21:15:49 +02005452 goto out_err;
Jouni Malineneec60b02009-03-20 21:21:19 +02005453 }
5454
Johannes Bergbba95fe2008-07-29 13:22:51 +02005455 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005456 err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
Johannes Berg97990a02013-04-19 01:02:55 +02005457 next_hop, &pinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02005458 if (err == -ENOENT)
5459 break;
5460 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01005461 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005462
Eric W. Biederman15e47302012-09-07 20:12:54 +00005463 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005464 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg97990a02013-04-19 01:02:55 +02005465 wdev->netdev, dst, next_hop,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005466 &pinfo) < 0)
5467 goto out;
5468
5469 path_idx++;
5470 }
5471
Johannes Bergbba95fe2008-07-29 13:22:51 +02005472 out:
Johannes Berg97990a02013-04-19 01:02:55 +02005473 cb->args[2] = path_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005474 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005475 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01005476 rtnl_unlock();
Johannes Bergbba95fe2008-07-29 13:22:51 +02005477 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005478}
5479
5480static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
5481{
Johannes Berg4c476992010-10-04 21:36:35 +02005482 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005483 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02005484 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005485 struct mpath_info pinfo;
5486 struct sk_buff *msg;
5487 u8 *dst = NULL;
5488 u8 next_hop[ETH_ALEN];
5489
5490 memset(&pinfo, 0, sizeof(pinfo));
5491
5492 if (!info->attrs[NL80211_ATTR_MAC])
5493 return -EINVAL;
5494
5495 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5496
Johannes Berg4c476992010-10-04 21:36:35 +02005497 if (!rdev->ops->get_mpath)
5498 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005499
Johannes Berg4c476992010-10-04 21:36:35 +02005500 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5501 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005502
Hila Gonene35e4d22012-06-27 17:19:42 +03005503 err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005504 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005505 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005506
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005507 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005508 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02005509 return -ENOMEM;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005510
Eric W. Biederman15e47302012-09-07 20:12:54 +00005511 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg4c476992010-10-04 21:36:35 +02005512 dev, dst, next_hop, &pinfo) < 0) {
5513 nlmsg_free(msg);
5514 return -ENOBUFS;
5515 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005516
Johannes Berg4c476992010-10-04 21:36:35 +02005517 return genlmsg_reply(msg, info);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005518}
5519
5520static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
5521{
Johannes Berg4c476992010-10-04 21:36:35 +02005522 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5523 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005524 u8 *dst = NULL;
5525 u8 *next_hop = NULL;
5526
5527 if (!info->attrs[NL80211_ATTR_MAC])
5528 return -EINVAL;
5529
5530 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5531 return -EINVAL;
5532
5533 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5534 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5535
Johannes Berg4c476992010-10-04 21:36:35 +02005536 if (!rdev->ops->change_mpath)
5537 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005538
Johannes Berg4c476992010-10-04 21:36:35 +02005539 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5540 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005541
Hila Gonene35e4d22012-06-27 17:19:42 +03005542 return rdev_change_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005543}
Johannes Berg4c476992010-10-04 21:36:35 +02005544
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005545static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
5546{
Johannes Berg4c476992010-10-04 21:36:35 +02005547 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5548 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005549 u8 *dst = NULL;
5550 u8 *next_hop = NULL;
5551
5552 if (!info->attrs[NL80211_ATTR_MAC])
5553 return -EINVAL;
5554
5555 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5556 return -EINVAL;
5557
5558 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5559 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5560
Johannes Berg4c476992010-10-04 21:36:35 +02005561 if (!rdev->ops->add_mpath)
5562 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005563
Johannes Berg4c476992010-10-04 21:36:35 +02005564 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5565 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005566
Hila Gonene35e4d22012-06-27 17:19:42 +03005567 return rdev_add_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005568}
5569
5570static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
5571{
Johannes Berg4c476992010-10-04 21:36:35 +02005572 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5573 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005574 u8 *dst = NULL;
5575
5576 if (info->attrs[NL80211_ATTR_MAC])
5577 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5578
Johannes Berg4c476992010-10-04 21:36:35 +02005579 if (!rdev->ops->del_mpath)
5580 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005581
Hila Gonene35e4d22012-06-27 17:19:42 +03005582 return rdev_del_mpath(rdev, dev, dst);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005583}
5584
Henning Rogge66be7d22014-09-12 08:58:49 +02005585static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
5586{
5587 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5588 int err;
5589 struct net_device *dev = info->user_ptr[1];
5590 struct mpath_info pinfo;
5591 struct sk_buff *msg;
5592 u8 *dst = NULL;
5593 u8 mpp[ETH_ALEN];
5594
5595 memset(&pinfo, 0, sizeof(pinfo));
5596
5597 if (!info->attrs[NL80211_ATTR_MAC])
5598 return -EINVAL;
5599
5600 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5601
5602 if (!rdev->ops->get_mpp)
5603 return -EOPNOTSUPP;
5604
5605 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5606 return -EOPNOTSUPP;
5607
5608 err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
5609 if (err)
5610 return err;
5611
5612 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5613 if (!msg)
5614 return -ENOMEM;
5615
5616 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
5617 dev, dst, mpp, &pinfo) < 0) {
5618 nlmsg_free(msg);
5619 return -ENOBUFS;
5620 }
5621
5622 return genlmsg_reply(msg, info);
5623}
5624
5625static int nl80211_dump_mpp(struct sk_buff *skb,
5626 struct netlink_callback *cb)
5627{
5628 struct mpath_info pinfo;
5629 struct cfg80211_registered_device *rdev;
5630 struct wireless_dev *wdev;
5631 u8 dst[ETH_ALEN];
5632 u8 mpp[ETH_ALEN];
5633 int path_idx = cb->args[2];
5634 int err;
5635
Johannes Bergea90e0d2017-03-15 14:26:04 +01005636 rtnl_lock();
Henning Rogge66be7d22014-09-12 08:58:49 +02005637 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
5638 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +01005639 goto out_err;
Henning Rogge66be7d22014-09-12 08:58:49 +02005640
5641 if (!rdev->ops->dump_mpp) {
5642 err = -EOPNOTSUPP;
5643 goto out_err;
5644 }
5645
5646 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
5647 err = -EOPNOTSUPP;
5648 goto out_err;
5649 }
5650
5651 while (1) {
5652 err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
5653 mpp, &pinfo);
5654 if (err == -ENOENT)
5655 break;
5656 if (err)
5657 goto out_err;
5658
5659 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
5660 cb->nlh->nlmsg_seq, NLM_F_MULTI,
5661 wdev->netdev, dst, mpp,
5662 &pinfo) < 0)
5663 goto out;
5664
5665 path_idx++;
5666 }
5667
5668 out:
5669 cb->args[2] = path_idx;
5670 err = skb->len;
5671 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01005672 rtnl_unlock();
Henning Rogge66be7d22014-09-12 08:58:49 +02005673 return err;
5674}
5675
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005676static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
5677{
Johannes Berg4c476992010-10-04 21:36:35 +02005678 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5679 struct net_device *dev = info->user_ptr[1];
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005680 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005681 struct bss_parameters params;
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005682 int err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005683
5684 memset(&params, 0, sizeof(params));
5685 /* default to not changing parameters */
5686 params.use_cts_prot = -1;
5687 params.use_short_preamble = -1;
5688 params.use_short_slot_time = -1;
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005689 params.ap_isolate = -1;
Helmut Schaa50b12f52010-11-19 12:40:25 +01005690 params.ht_opmode = -1;
Johannes Berg53cabad2012-11-14 15:17:28 +01005691 params.p2p_ctwindow = -1;
5692 params.p2p_opp_ps = -1;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005693
5694 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
5695 params.use_cts_prot =
5696 nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
5697 if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
5698 params.use_short_preamble =
5699 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
5700 if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
5701 params.use_short_slot_time =
5702 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
Jouni Malinen90c97a02008-10-30 16:59:22 +02005703 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
5704 params.basic_rates =
5705 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5706 params.basic_rates_len =
5707 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5708 }
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005709 if (info->attrs[NL80211_ATTR_AP_ISOLATE])
5710 params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
Helmut Schaa50b12f52010-11-19 12:40:25 +01005711 if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
5712 params.ht_opmode =
5713 nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005714
Johannes Berg53cabad2012-11-14 15:17:28 +01005715 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
5716 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5717 return -EINVAL;
5718 params.p2p_ctwindow =
5719 nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
5720 if (params.p2p_ctwindow < 0)
5721 return -EINVAL;
5722 if (params.p2p_ctwindow != 0 &&
5723 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
5724 return -EINVAL;
5725 }
5726
5727 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
5728 u8 tmp;
5729
5730 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5731 return -EINVAL;
5732 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
5733 if (tmp > 1)
5734 return -EINVAL;
5735 params.p2p_opp_ps = tmp;
5736 if (params.p2p_opp_ps &&
5737 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
5738 return -EINVAL;
5739 }
5740
Johannes Berg4c476992010-10-04 21:36:35 +02005741 if (!rdev->ops->change_bss)
5742 return -EOPNOTSUPP;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005743
Johannes Berg074ac8d2010-09-16 14:58:22 +02005744 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Johannes Berg4c476992010-10-04 21:36:35 +02005745 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5746 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005747
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005748 wdev_lock(wdev);
5749 err = rdev_change_bss(rdev, dev, &params);
5750 wdev_unlock(wdev);
5751
5752 return err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005753}
5754
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005755static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
5756{
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005757 char *data = NULL;
Ilan peer05050752015-03-04 00:32:06 -05005758 bool is_indoor;
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005759 enum nl80211_user_reg_hint_type user_reg_hint_type;
Ilan peer05050752015-03-04 00:32:06 -05005760 u32 owner_nlportid;
5761
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005762 /*
5763 * You should only get this when cfg80211 hasn't yet initialized
5764 * completely when built-in to the kernel right between the time
5765 * window between nl80211_init() and regulatory_init(), if that is
5766 * even possible.
5767 */
Johannes Berg458f4f92012-12-06 15:47:38 +01005768 if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
Luis R. Rodriguezfe33eb32009-02-21 00:04:30 -05005769 return -EINPROGRESS;
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005770
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005771 if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
5772 user_reg_hint_type =
5773 nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
5774 else
5775 user_reg_hint_type = NL80211_USER_REG_HINT_USER;
5776
5777 switch (user_reg_hint_type) {
5778 case NL80211_USER_REG_HINT_USER:
5779 case NL80211_USER_REG_HINT_CELL_BASE:
Ilan Peer52616f22014-02-25 16:26:00 +02005780 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
5781 return -EINVAL;
5782
5783 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
5784 return regulatory_hint_user(data, user_reg_hint_type);
5785 case NL80211_USER_REG_HINT_INDOOR:
Ilan peer05050752015-03-04 00:32:06 -05005786 if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
5787 owner_nlportid = info->snd_portid;
5788 is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
5789 } else {
5790 owner_nlportid = 0;
5791 is_indoor = true;
5792 }
5793
5794 return regulatory_hint_indoor(is_indoor, owner_nlportid);
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005795 default:
5796 return -EINVAL;
5797 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005798}
5799
Johannes Berg1ea4ff32017-09-13 16:07:22 +02005800static int nl80211_reload_regdb(struct sk_buff *skb, struct genl_info *info)
5801{
5802 return reg_reload_regdb();
5803}
5804
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005805static int nl80211_get_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01005806 struct genl_info *info)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005807{
Johannes Berg4c476992010-10-04 21:36:35 +02005808 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02005809 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01005810 struct wireless_dev *wdev = dev->ieee80211_ptr;
5811 struct mesh_config cur_params;
5812 int err = 0;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005813 void *hdr;
5814 struct nlattr *pinfoattr;
5815 struct sk_buff *msg;
5816
Johannes Berg29cbe682010-12-03 09:20:44 +01005817 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
5818 return -EOPNOTSUPP;
5819
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005820 if (!rdev->ops->get_mesh_config)
Johannes Berg4c476992010-10-04 21:36:35 +02005821 return -EOPNOTSUPP;
Jouni Malinenf3f92582009-03-20 17:57:36 +02005822
Johannes Berg29cbe682010-12-03 09:20:44 +01005823 wdev_lock(wdev);
5824 /* If not connected, get default parameters */
5825 if (!wdev->mesh_id_len)
5826 memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
5827 else
Hila Gonene35e4d22012-06-27 17:19:42 +03005828 err = rdev_get_mesh_config(rdev, dev, &cur_params);
Johannes Berg29cbe682010-12-03 09:20:44 +01005829 wdev_unlock(wdev);
5830
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005831 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005832 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005833
5834 /* Draw up a netlink message to send back */
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005835 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02005836 if (!msg)
5837 return -ENOMEM;
Eric W. Biederman15e47302012-09-07 20:12:54 +00005838 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005839 NL80211_CMD_GET_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005840 if (!hdr)
Julia Lawallefe1cf02011-01-28 15:17:11 +01005841 goto out;
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005842 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005843 if (!pinfoattr)
5844 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005845 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5846 nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
5847 cur_params.dot11MeshRetryTimeout) ||
5848 nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
5849 cur_params.dot11MeshConfirmTimeout) ||
5850 nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
5851 cur_params.dot11MeshHoldingTimeout) ||
5852 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
5853 cur_params.dot11MeshMaxPeerLinks) ||
5854 nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
5855 cur_params.dot11MeshMaxRetries) ||
5856 nla_put_u8(msg, NL80211_MESHCONF_TTL,
5857 cur_params.dot11MeshTTL) ||
5858 nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
5859 cur_params.element_ttl) ||
5860 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
5861 cur_params.auto_open_plinks) ||
John W. Linville7eab0f62012-04-12 14:25:14 -04005862 nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
5863 cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04005864 nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
5865 cur_params.dot11MeshHWMPmaxPREQretries) ||
5866 nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
5867 cur_params.path_refresh_time) ||
5868 nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
5869 cur_params.min_discovery_timeout) ||
5870 nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
5871 cur_params.dot11MeshHWMPactivePathTimeout) ||
5872 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
5873 cur_params.dot11MeshHWMPpreqMinInterval) ||
5874 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
5875 cur_params.dot11MeshHWMPperrMinInterval) ||
5876 nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
5877 cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
5878 nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
5879 cur_params.dot11MeshHWMPRootMode) ||
5880 nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
5881 cur_params.dot11MeshHWMPRannInterval) ||
5882 nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
5883 cur_params.dot11MeshGateAnnouncementProtocol) ||
5884 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
5885 cur_params.dot11MeshForwarding) ||
Masashi Honma335d5342017-03-16 10:57:17 +09005886 nla_put_s32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
Ashok Nagarajan70c33ea2012-04-30 14:20:32 -07005887 cur_params.rssi_threshold) ||
5888 nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005889 cur_params.ht_opmode) ||
5890 nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
5891 cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
5892 nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005893 cur_params.dot11MeshHWMProotInterval) ||
5894 nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005895 cur_params.dot11MeshHWMPconfirmationInterval) ||
5896 nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
5897 cur_params.power_mode) ||
5898 nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005899 cur_params.dot11MeshAwakeWindowDuration) ||
5900 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
5901 cur_params.plink_timeout))
David S. Miller9360ffd2012-03-29 04:41:26 -04005902 goto nla_put_failure;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005903 nla_nest_end(msg, pinfoattr);
5904 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02005905 return genlmsg_reply(msg, info);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005906
Johannes Berg3b858752009-03-12 09:55:09 +01005907 nla_put_failure:
Julia Lawallefe1cf02011-01-28 15:17:11 +01005908 out:
Yuri Ershovd080e272010-06-29 15:08:07 +04005909 nlmsg_free(msg);
Johannes Berg4c476992010-10-04 21:36:35 +02005910 return -ENOBUFS;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005911}
5912
Alexey Dobriyanb54452b2010-02-18 08:14:31 +00005913static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005914 [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
5915 [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
5916 [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
5917 [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
5918 [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
5919 [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
Javier Cardona45904f22010-12-03 09:20:40 +01005920 [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005921 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
Javier Cardonad299a1f2012-03-31 11:31:33 -07005922 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005923 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
5924 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
5925 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
5926 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
5927 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
Thomas Pedersendca7e942011-11-24 17:15:24 -08005928 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005929 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
Javier Cardona699403d2011-08-09 16:45:09 -07005930 [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
Javier Cardona0507e152011-08-09 16:45:10 -07005931 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
Javier Cardona16dd7262011-08-09 16:45:11 -07005932 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
Chun-Yeow Yeoh94f90652012-01-21 01:02:16 +08005933 [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005934 [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
5935 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005936 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
5937 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005938 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005939 [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
5940 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005941 [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005942};
5943
Javier Cardonac80d5452010-12-16 17:37:49 -08005944static const struct nla_policy
5945 nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
Javier Cardonad299a1f2012-03-31 11:31:33 -07005946 [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
Javier Cardonac80d5452010-12-16 17:37:49 -08005947 [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
5948 [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
Javier Cardona15d5dda2011-04-07 15:08:28 -07005949 [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
Colleen Twitty6e16d902013-05-08 11:45:59 -07005950 [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 },
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08005951 [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
Javier Cardona581a8b02011-04-07 15:08:27 -07005952 [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005953 .len = IEEE80211_MAX_DATA_LEN },
Javier Cardonab130e5c2011-05-03 16:57:07 -07005954 [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
Javier Cardonac80d5452010-12-16 17:37:49 -08005955};
5956
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005957static int nl80211_check_bool(const struct nlattr *nla, u8 min, u8 max, bool *out)
5958{
5959 u8 val = nla_get_u8(nla);
5960 if (val < min || val > max)
5961 return -EINVAL;
5962 *out = val;
5963 return 0;
5964}
5965
5966static int nl80211_check_u8(const struct nlattr *nla, u8 min, u8 max, u8 *out)
5967{
5968 u8 val = nla_get_u8(nla);
5969 if (val < min || val > max)
5970 return -EINVAL;
5971 *out = val;
5972 return 0;
5973}
5974
5975static int nl80211_check_u16(const struct nlattr *nla, u16 min, u16 max, u16 *out)
5976{
5977 u16 val = nla_get_u16(nla);
5978 if (val < min || val > max)
5979 return -EINVAL;
5980 *out = val;
5981 return 0;
5982}
5983
5984static int nl80211_check_u32(const struct nlattr *nla, u32 min, u32 max, u32 *out)
5985{
5986 u32 val = nla_get_u32(nla);
5987 if (val < min || val > max)
5988 return -EINVAL;
5989 *out = val;
5990 return 0;
5991}
5992
5993static int nl80211_check_s32(const struct nlattr *nla, s32 min, s32 max, s32 *out)
5994{
5995 s32 val = nla_get_s32(nla);
5996 if (val < min || val > max)
5997 return -EINVAL;
5998 *out = val;
5999 return 0;
6000}
6001
Johannes Bergff9a71a2016-08-11 14:59:53 +02006002static int nl80211_check_power_mode(const struct nlattr *nla,
6003 enum nl80211_mesh_power_mode min,
6004 enum nl80211_mesh_power_mode max,
6005 enum nl80211_mesh_power_mode *out)
6006{
6007 u32 val = nla_get_u32(nla);
6008 if (val < min || val > max)
6009 return -EINVAL;
6010 *out = val;
6011 return 0;
6012}
6013
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006014static int nl80211_parse_mesh_config(struct genl_info *info,
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006015 struct mesh_config *cfg,
6016 u32 *mask_out)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006017{
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006018 struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006019 u32 mask = 0;
Masashi Honma97572352016-08-03 10:07:44 +09006020 u16 ht_opmode;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006021
Marco Porschea54fba2013-01-07 16:04:48 +01006022#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \
6023do { \
6024 if (tb[attr]) { \
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006025 if (fn(tb[attr], min, max, &cfg->param)) \
Marco Porschea54fba2013-01-07 16:04:48 +01006026 return -EINVAL; \
Marco Porschea54fba2013-01-07 16:04:48 +01006027 mask |= (1 << (attr - 1)); \
6028 } \
6029} while (0)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006030
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006031 if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006032 return -EINVAL;
6033 if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006034 info->attrs[NL80211_ATTR_MESH_CONFIG],
Johannes Bergfe521452017-04-12 14:34:08 +02006035 nl80211_meshconf_params_policy, info->extack))
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006036 return -EINVAL;
6037
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006038 /* This makes sure that there aren't more than 32 mesh config
6039 * parameters (otherwise our bitfield scheme would not work.) */
6040 BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
6041
6042 /* Fill in the params struct */
Marco Porschea54fba2013-01-07 16:04:48 +01006043 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006044 mask, NL80211_MESHCONF_RETRY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006045 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01006046 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006047 mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006048 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01006049 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006050 mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006051 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01006052 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006053 mask, NL80211_MESHCONF_MAX_PEER_LINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006054 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01006055 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006056 mask, NL80211_MESHCONF_MAX_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006057 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01006058 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006059 mask, NL80211_MESHCONF_TTL, nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01006060 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006061 mask, NL80211_MESHCONF_ELEMENT_TTL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006062 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01006063 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006064 mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006065 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01006066 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
6067 1, 255, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006068 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006069 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01006070 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006071 mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006072 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01006073 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006074 mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006075 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01006076 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006077 mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006078 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01006079 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
6080 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006081 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006082 nl80211_check_u32);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006083 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01006084 1, 65535, mask,
6085 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006086 nl80211_check_u16);
Thomas Pedersendca7e942011-11-24 17:15:24 -08006087 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01006088 1, 65535, mask,
6089 NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006090 nl80211_check_u16);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006091 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01006092 dot11MeshHWMPnetDiameterTraversalTime,
6093 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006094 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006095 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01006096 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4,
6097 mask, NL80211_MESHCONF_HWMP_ROOTMODE,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006098 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01006099 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, 1, 65535,
6100 mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006101 nl80211_check_u16);
Rui Paulo63c57232009-11-09 23:46:57 +00006102 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01006103 dot11MeshGateAnnouncementProtocol, 0, 1,
6104 mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006105 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01006106 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006107 mask, NL80211_MESHCONF_FORWARDING,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006108 nl80211_check_bool);
Chun-Yeow Yeoh83374fe2013-07-11 18:24:03 +08006109 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006110 mask, NL80211_MESHCONF_RSSI_THRESHOLD,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006111 nl80211_check_s32);
Masashi Honma97572352016-08-03 10:07:44 +09006112 /*
6113 * Check HT operation mode based on
6114 * IEEE 802.11 2012 8.4.2.59 HT Operation element.
6115 */
6116 if (tb[NL80211_MESHCONF_HT_OPMODE]) {
6117 ht_opmode = nla_get_u16(tb[NL80211_MESHCONF_HT_OPMODE]);
6118
6119 if (ht_opmode & ~(IEEE80211_HT_OP_MODE_PROTECTION |
6120 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
6121 IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
6122 return -EINVAL;
6123
6124 if ((ht_opmode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) &&
6125 (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
6126 return -EINVAL;
6127
6128 switch (ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION) {
6129 case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
6130 case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
6131 if (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT)
6132 return -EINVAL;
6133 break;
6134 case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
6135 case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
6136 if (!(ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
6137 return -EINVAL;
6138 break;
6139 }
6140 cfg->ht_opmode = ht_opmode;
Masashi Honmafd551ba2017-01-26 08:56:13 +09006141 mask |= (1 << (NL80211_MESHCONF_HT_OPMODE - 1));
Masashi Honma97572352016-08-03 10:07:44 +09006142 }
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08006143 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
Marco Porschea54fba2013-01-07 16:04:48 +01006144 1, 65535, mask,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08006145 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006146 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01006147 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08006148 mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006149 nl80211_check_u16);
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08006150 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01006151 dot11MeshHWMPconfirmationInterval,
6152 1, 65535, mask,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08006153 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006154 nl80211_check_u16);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01006155 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode,
6156 NL80211_MESH_POWER_ACTIVE,
6157 NL80211_MESH_POWER_MAX,
6158 mask, NL80211_MESHCONF_POWER_MODE,
Johannes Bergff9a71a2016-08-11 14:59:53 +02006159 nl80211_check_power_mode);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01006160 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
6161 0, 65535, mask,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006162 NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16);
Masashi Honma31f909a2015-02-24 22:42:16 +09006163 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07006164 mask, NL80211_MESHCONF_PLINK_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006165 nl80211_check_u32);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006166 if (mask_out)
6167 *mask_out = mask;
Javier Cardonac80d5452010-12-16 17:37:49 -08006168
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006169 return 0;
6170
6171#undef FILL_IN_MESH_PARAM_IF_SET
6172}
6173
Javier Cardonac80d5452010-12-16 17:37:49 -08006174static int nl80211_parse_mesh_setup(struct genl_info *info,
6175 struct mesh_setup *setup)
6176{
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006177 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Javier Cardonac80d5452010-12-16 17:37:49 -08006178 struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
6179
6180 if (!info->attrs[NL80211_ATTR_MESH_SETUP])
6181 return -EINVAL;
6182 if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX,
6183 info->attrs[NL80211_ATTR_MESH_SETUP],
Johannes Bergfe521452017-04-12 14:34:08 +02006184 nl80211_mesh_setup_params_policy, info->extack))
Javier Cardonac80d5452010-12-16 17:37:49 -08006185 return -EINVAL;
6186
Javier Cardonad299a1f2012-03-31 11:31:33 -07006187 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
6188 setup->sync_method =
6189 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
6190 IEEE80211_SYNC_METHOD_VENDOR :
6191 IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
6192
Javier Cardonac80d5452010-12-16 17:37:49 -08006193 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
6194 setup->path_sel_proto =
6195 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
6196 IEEE80211_PATH_PROTOCOL_VENDOR :
6197 IEEE80211_PATH_PROTOCOL_HWMP;
6198
6199 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
6200 setup->path_metric =
6201 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
6202 IEEE80211_PATH_METRIC_VENDOR :
6203 IEEE80211_PATH_METRIC_AIRTIME;
6204
Javier Cardona581a8b02011-04-07 15:08:27 -07006205 if (tb[NL80211_MESH_SETUP_IE]) {
Javier Cardonac80d5452010-12-16 17:37:49 -08006206 struct nlattr *ieattr =
Javier Cardona581a8b02011-04-07 15:08:27 -07006207 tb[NL80211_MESH_SETUP_IE];
Javier Cardonac80d5452010-12-16 17:37:49 -08006208 if (!is_valid_ie_attr(ieattr))
6209 return -EINVAL;
Javier Cardona581a8b02011-04-07 15:08:27 -07006210 setup->ie = nla_data(ieattr);
6211 setup->ie_len = nla_len(ieattr);
Javier Cardonac80d5452010-12-16 17:37:49 -08006212 }
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006213 if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
6214 !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
6215 return -EINVAL;
6216 setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
Javier Cardonab130e5c2011-05-03 16:57:07 -07006217 setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
6218 setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006219 if (setup->is_secure)
6220 setup->user_mpm = true;
Javier Cardonac80d5452010-12-16 17:37:49 -08006221
Colleen Twitty6e16d902013-05-08 11:45:59 -07006222 if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) {
6223 if (!setup->user_mpm)
6224 return -EINVAL;
6225 setup->auth_id =
6226 nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]);
6227 }
6228
Javier Cardonac80d5452010-12-16 17:37:49 -08006229 return 0;
6230}
6231
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006232static int nl80211_update_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01006233 struct genl_info *info)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006234{
6235 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6236 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01006237 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006238 struct mesh_config cfg;
6239 u32 mask;
6240 int err;
6241
Johannes Berg29cbe682010-12-03 09:20:44 +01006242 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
6243 return -EOPNOTSUPP;
6244
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006245 if (!rdev->ops->update_mesh_config)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006246 return -EOPNOTSUPP;
6247
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006248 err = nl80211_parse_mesh_config(info, &cfg, &mask);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006249 if (err)
6250 return err;
6251
Johannes Berg29cbe682010-12-03 09:20:44 +01006252 wdev_lock(wdev);
6253 if (!wdev->mesh_id_len)
6254 err = -ENOLINK;
6255
6256 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03006257 err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01006258
6259 wdev_unlock(wdev);
6260
6261 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006262}
6263
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006264static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
6265 struct sk_buff *msg)
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006266{
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006267 struct nlattr *nl_reg_rules;
6268 unsigned int i;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006269
Johannes Berg458f4f92012-12-06 15:47:38 +01006270 if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
6271 (regdom->dfs_region &&
6272 nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006273 goto nla_put_failure;
Johannes Berg458f4f92012-12-06 15:47:38 +01006274
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006275 nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
6276 if (!nl_reg_rules)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006277 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006278
Johannes Berg458f4f92012-12-06 15:47:38 +01006279 for (i = 0; i < regdom->n_reg_rules; i++) {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006280 struct nlattr *nl_reg_rule;
6281 const struct ieee80211_reg_rule *reg_rule;
6282 const struct ieee80211_freq_range *freq_range;
6283 const struct ieee80211_power_rule *power_rule;
Janusz Dziedzic97524822014-01-30 09:52:20 +01006284 unsigned int max_bandwidth_khz;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006285
Johannes Berg458f4f92012-12-06 15:47:38 +01006286 reg_rule = &regdom->reg_rules[i];
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006287 freq_range = &reg_rule->freq_range;
6288 power_rule = &reg_rule->power_rule;
6289
6290 nl_reg_rule = nla_nest_start(msg, i);
6291 if (!nl_reg_rule)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006292 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006293
Janusz Dziedzic97524822014-01-30 09:52:20 +01006294 max_bandwidth_khz = freq_range->max_bandwidth_khz;
6295 if (!max_bandwidth_khz)
6296 max_bandwidth_khz = reg_get_max_bandwidth(regdom,
6297 reg_rule);
6298
David S. Miller9360ffd2012-03-29 04:41:26 -04006299 if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
6300 reg_rule->flags) ||
6301 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
6302 freq_range->start_freq_khz) ||
6303 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
6304 freq_range->end_freq_khz) ||
6305 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
Janusz Dziedzic97524822014-01-30 09:52:20 +01006306 max_bandwidth_khz) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04006307 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
6308 power_rule->max_antenna_gain) ||
6309 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
Janusz Dziedzic089027e2014-02-21 19:46:12 +01006310 power_rule->max_eirp) ||
6311 nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
6312 reg_rule->dfs_cac_ms))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006313 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006314
6315 nla_nest_end(msg, nl_reg_rule);
6316 }
6317
6318 nla_nest_end(msg, nl_reg_rules);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006319 return 0;
6320
6321nla_put_failure:
6322 return -EMSGSIZE;
6323}
6324
6325static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
6326{
6327 const struct ieee80211_regdomain *regdom = NULL;
6328 struct cfg80211_registered_device *rdev;
6329 struct wiphy *wiphy = NULL;
6330 struct sk_buff *msg;
6331 void *hdr;
6332
6333 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6334 if (!msg)
6335 return -ENOBUFS;
6336
6337 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
6338 NL80211_CMD_GET_REG);
6339 if (!hdr)
6340 goto put_failure;
6341
6342 if (info->attrs[NL80211_ATTR_WIPHY]) {
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006343 bool self_managed;
6344
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006345 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
6346 if (IS_ERR(rdev)) {
6347 nlmsg_free(msg);
6348 return PTR_ERR(rdev);
6349 }
6350
6351 wiphy = &rdev->wiphy;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006352 self_managed = wiphy->regulatory_flags &
6353 REGULATORY_WIPHY_SELF_MANAGED;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006354 regdom = get_wiphy_regdom(wiphy);
6355
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006356 /* a self-managed-reg device must have a private regdom */
6357 if (WARN_ON(!regdom && self_managed)) {
6358 nlmsg_free(msg);
6359 return -EINVAL;
6360 }
6361
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006362 if (regdom &&
6363 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6364 goto nla_put_failure;
6365 }
6366
6367 if (!wiphy && reg_last_request_cell_base() &&
6368 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6369 NL80211_USER_REG_HINT_CELL_BASE))
6370 goto nla_put_failure;
6371
6372 rcu_read_lock();
6373
6374 if (!regdom)
6375 regdom = rcu_dereference(cfg80211_regdomain);
6376
6377 if (nl80211_put_regdom(regdom, msg))
6378 goto nla_put_failure_rcu;
6379
6380 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006381
6382 genlmsg_end(msg, hdr);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006383 return genlmsg_reply(msg, info);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006384
Johannes Berg458f4f92012-12-06 15:47:38 +01006385nla_put_failure_rcu:
6386 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006387nla_put_failure:
Julia Lawallefe1cf02011-01-28 15:17:11 +01006388put_failure:
Yuri Ershovd080e272010-06-29 15:08:07 +04006389 nlmsg_free(msg);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006390 return -EMSGSIZE;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006391}
6392
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006393static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
6394 u32 seq, int flags, struct wiphy *wiphy,
6395 const struct ieee80211_regdomain *regdom)
6396{
6397 void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
6398 NL80211_CMD_GET_REG);
6399
6400 if (!hdr)
6401 return -1;
6402
Michal Kubecek0a833c22017-11-15 13:09:32 +01006403 genl_dump_check_consistent(cb, hdr);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006404
6405 if (nl80211_put_regdom(regdom, msg))
6406 goto nla_put_failure;
6407
6408 if (!wiphy && reg_last_request_cell_base() &&
6409 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6410 NL80211_USER_REG_HINT_CELL_BASE))
6411 goto nla_put_failure;
6412
6413 if (wiphy &&
6414 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6415 goto nla_put_failure;
6416
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006417 if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
6418 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
6419 goto nla_put_failure;
6420
Johannes Berg053c0952015-01-16 22:09:00 +01006421 genlmsg_end(msg, hdr);
6422 return 0;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006423
6424nla_put_failure:
6425 genlmsg_cancel(msg, hdr);
6426 return -EMSGSIZE;
6427}
6428
6429static int nl80211_get_reg_dump(struct sk_buff *skb,
6430 struct netlink_callback *cb)
6431{
6432 const struct ieee80211_regdomain *regdom = NULL;
6433 struct cfg80211_registered_device *rdev;
6434 int err, reg_idx, start = cb->args[2];
6435
6436 rtnl_lock();
6437
6438 if (cfg80211_regdomain && start == 0) {
6439 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6440 NLM_F_MULTI, NULL,
6441 rtnl_dereference(cfg80211_regdomain));
6442 if (err < 0)
6443 goto out_err;
6444 }
6445
6446 /* the global regdom is idx 0 */
6447 reg_idx = 1;
6448 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
6449 regdom = get_wiphy_regdom(&rdev->wiphy);
6450 if (!regdom)
6451 continue;
6452
6453 if (++reg_idx <= start)
6454 continue;
6455
6456 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6457 NLM_F_MULTI, &rdev->wiphy, regdom);
6458 if (err < 0) {
6459 reg_idx--;
6460 break;
6461 }
6462 }
6463
6464 cb->args[2] = reg_idx;
6465 err = skb->len;
6466out_err:
6467 rtnl_unlock();
6468 return err;
6469}
6470
Johannes Bergb6863032015-10-15 09:25:18 +02006471#ifdef CONFIG_CFG80211_CRDA_SUPPORT
6472static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
6473 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
6474 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
6475 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
6476 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
6477 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
6478 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
6479 [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
6480};
6481
6482static int parse_reg_rule(struct nlattr *tb[],
6483 struct ieee80211_reg_rule *reg_rule)
6484{
6485 struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
6486 struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
6487
6488 if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
6489 return -EINVAL;
6490 if (!tb[NL80211_ATTR_FREQ_RANGE_START])
6491 return -EINVAL;
6492 if (!tb[NL80211_ATTR_FREQ_RANGE_END])
6493 return -EINVAL;
6494 if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
6495 return -EINVAL;
6496 if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
6497 return -EINVAL;
6498
6499 reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
6500
6501 freq_range->start_freq_khz =
6502 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
6503 freq_range->end_freq_khz =
6504 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
6505 freq_range->max_bandwidth_khz =
6506 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
6507
6508 power_rule->max_eirp =
6509 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
6510
6511 if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
6512 power_rule->max_antenna_gain =
6513 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
6514
6515 if (tb[NL80211_ATTR_DFS_CAC_TIME])
6516 reg_rule->dfs_cac_ms =
6517 nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
6518
6519 return 0;
6520}
6521
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006522static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
6523{
6524 struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
6525 struct nlattr *nl_reg_rule;
Johannes Bergea372c52014-11-28 14:54:31 +01006526 char *alpha2;
6527 int rem_reg_rules, r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006528 u32 num_rules = 0, rule_idx = 0, size_of_regd;
Luis R. Rodriguez4c7d3982013-11-13 18:54:02 +01006529 enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
Johannes Bergea372c52014-11-28 14:54:31 +01006530 struct ieee80211_regdomain *rd;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006531
6532 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
6533 return -EINVAL;
6534
6535 if (!info->attrs[NL80211_ATTR_REG_RULES])
6536 return -EINVAL;
6537
6538 alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
6539
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006540 if (info->attrs[NL80211_ATTR_DFS_REGION])
6541 dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
6542
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006543 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006544 rem_reg_rules) {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006545 num_rules++;
6546 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
Luis R. Rodriguez4776c6e2009-05-13 17:04:39 -04006547 return -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006548 }
6549
Luis R. Rodrigueze4387682013-11-05 09:18:01 -08006550 if (!reg_is_valid_request(alpha2))
6551 return -EINVAL;
6552
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006553 size_of_regd = sizeof(struct ieee80211_regdomain) +
Johannes Berg1a919312012-12-03 17:21:11 +01006554 num_rules * sizeof(struct ieee80211_reg_rule);
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006555
6556 rd = kzalloc(size_of_regd, GFP_KERNEL);
Johannes Berg6913b492012-12-04 00:48:59 +01006557 if (!rd)
6558 return -ENOMEM;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006559
6560 rd->n_reg_rules = num_rules;
6561 rd->alpha2[0] = alpha2[0];
6562 rd->alpha2[1] = alpha2[1];
6563
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006564 /*
6565 * Disable DFS master mode if the DFS region was
6566 * not supported or known on this kernel.
6567 */
6568 if (reg_supported_dfs_region(dfs_region))
6569 rd->dfs_region = dfs_region;
6570
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006571 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006572 rem_reg_rules) {
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006573 r = nla_parse_nested(tb, NL80211_REG_RULE_ATTR_MAX,
Johannes Bergfe521452017-04-12 14:34:08 +02006574 nl_reg_rule, reg_rule_policy,
6575 info->extack);
Johannes Bergae811e22014-01-24 10:17:47 +01006576 if (r)
6577 goto bad_reg;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006578 r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
6579 if (r)
6580 goto bad_reg;
6581
6582 rule_idx++;
6583
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006584 if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
6585 r = -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006586 goto bad_reg;
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006587 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006588 }
6589
Johannes Berg06627992016-06-09 10:40:09 +02006590 /* set_regdom takes ownership of rd */
6591 return set_regdom(rd, REGD_SOURCE_CRDA);
Johannes Bergd2372b32008-10-24 20:32:20 +02006592 bad_reg:
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006593 kfree(rd);
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006594 return r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006595}
Johannes Bergb6863032015-10-15 09:25:18 +02006596#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006597
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006598static int validate_scan_freqs(struct nlattr *freqs)
6599{
6600 struct nlattr *attr1, *attr2;
6601 int n_channels = 0, tmp1, tmp2;
6602
Srinivas Dasarid7f13f72017-07-07 01:43:42 +03006603 nla_for_each_nested(attr1, freqs, tmp1)
6604 if (nla_len(attr1) != sizeof(u32))
6605 return 0;
6606
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006607 nla_for_each_nested(attr1, freqs, tmp1) {
6608 n_channels++;
6609 /*
6610 * Some hardware has a limited channel list for
6611 * scanning, and it is pretty much nonsensical
6612 * to scan for a channel twice, so disallow that
6613 * and don't require drivers to check that the
6614 * channel list they get isn't longer than what
6615 * they can scan, as long as they can scan all
6616 * the channels they registered at once.
6617 */
6618 nla_for_each_nested(attr2, freqs, tmp2)
6619 if (attr1 != attr2 &&
6620 nla_get_u32(attr1) == nla_get_u32(attr2))
6621 return 0;
6622 }
6623
6624 return n_channels;
6625}
6626
Johannes Berg57fbcce2016-04-12 15:56:15 +02006627static bool is_band_valid(struct wiphy *wiphy, enum nl80211_band b)
Arend van Spriel38de03d2016-03-02 20:37:18 +01006628{
Johannes Berg57fbcce2016-04-12 15:56:15 +02006629 return b < NUM_NL80211_BANDS && wiphy->bands[b];
Arend van Spriel38de03d2016-03-02 20:37:18 +01006630}
6631
6632static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
6633 struct cfg80211_bss_selection *bss_select)
6634{
6635 struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
6636 struct nlattr *nest;
6637 int err;
6638 bool found = false;
6639 int i;
6640
6641 /* only process one nested attribute */
6642 nest = nla_data(nla);
6643 if (!nla_ok(nest, nla_len(nest)))
6644 return -EINVAL;
6645
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006646 err = nla_parse_nested(attr, NL80211_BSS_SELECT_ATTR_MAX, nest,
Johannes Bergfceb6432017-04-12 14:34:07 +02006647 nl80211_bss_select_policy, NULL);
Arend van Spriel38de03d2016-03-02 20:37:18 +01006648 if (err)
6649 return err;
6650
6651 /* only one attribute may be given */
6652 for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
6653 if (attr[i]) {
6654 if (found)
6655 return -EINVAL;
6656 found = true;
6657 }
6658 }
6659
6660 bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
6661
6662 if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
6663 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
6664
6665 if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
6666 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
6667 bss_select->param.band_pref =
6668 nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
6669 if (!is_band_valid(wiphy, bss_select->param.band_pref))
6670 return -EINVAL;
6671 }
6672
6673 if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
6674 struct nl80211_bss_select_rssi_adjust *adj_param;
6675
6676 adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
6677 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
6678 bss_select->param.adjust.band = adj_param->band;
6679 bss_select->param.adjust.delta = adj_param->delta;
6680 if (!is_band_valid(wiphy, bss_select->param.adjust.band))
6681 return -EINVAL;
6682 }
6683
6684 /* user-space did not provide behaviour attribute */
6685 if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
6686 return -EINVAL;
6687
6688 if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
6689 return -EINVAL;
6690
6691 return 0;
6692}
6693
Johannes Bergad2b26a2014-06-12 21:39:05 +02006694static int nl80211_parse_random_mac(struct nlattr **attrs,
6695 u8 *mac_addr, u8 *mac_addr_mask)
6696{
6697 int i;
6698
6699 if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
Joe Perchesd2beae12015-03-02 19:54:58 -08006700 eth_zero_addr(mac_addr);
6701 eth_zero_addr(mac_addr_mask);
Johannes Bergad2b26a2014-06-12 21:39:05 +02006702 mac_addr[0] = 0x2;
6703 mac_addr_mask[0] = 0x3;
6704
6705 return 0;
6706 }
6707
6708 /* need both or none */
6709 if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
6710 return -EINVAL;
6711
6712 memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
6713 memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
6714
6715 /* don't allow or configure an mcast address */
6716 if (!is_multicast_ether_addr(mac_addr_mask) ||
6717 is_multicast_ether_addr(mac_addr))
6718 return -EINVAL;
6719
6720 /*
6721 * allow users to pass a MAC address that has bits set outside
6722 * of the mask, but don't bother drivers with having to deal
6723 * with such bits
6724 */
6725 for (i = 0; i < ETH_ALEN; i++)
6726 mac_addr[i] &= mac_addr_mask[i];
6727
6728 return 0;
6729}
6730
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05306731static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
6732{
6733 ASSERT_WDEV_LOCK(wdev);
6734
6735 if (!cfg80211_beaconing_iface_active(wdev))
6736 return true;
6737
6738 if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
6739 return true;
6740
6741 return regulatory_pre_cac_allowed(wdev->wiphy);
6742}
6743
Roee Zamir2d23d072017-08-06 11:38:22 +03006744static int
6745nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
6746 void *request, struct nlattr **attrs,
6747 bool is_sched_scan)
6748{
6749 u8 *mac_addr, *mac_addr_mask;
6750 u32 *flags;
6751 enum nl80211_feature_flags randomness_flag;
6752
6753 if (!attrs[NL80211_ATTR_SCAN_FLAGS])
6754 return 0;
6755
6756 if (is_sched_scan) {
6757 struct cfg80211_sched_scan_request *req = request;
6758
6759 randomness_flag = wdev ?
6760 NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR :
6761 NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6762 flags = &req->flags;
6763 mac_addr = req->mac_addr;
6764 mac_addr_mask = req->mac_addr_mask;
6765 } else {
6766 struct cfg80211_scan_request *req = request;
6767
6768 randomness_flag = NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
6769 flags = &req->flags;
6770 mac_addr = req->mac_addr;
6771 mac_addr_mask = req->mac_addr_mask;
6772 }
6773
6774 *flags = nla_get_u32(attrs[NL80211_ATTR_SCAN_FLAGS]);
6775
Sunil Dutt5037a002018-01-25 17:13:37 +02006776 if (((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
6777 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
6778 ((*flags & NL80211_SCAN_FLAG_LOW_SPAN) &&
6779 !wiphy_ext_feature_isset(wiphy,
6780 NL80211_EXT_FEATURE_LOW_SPAN_SCAN)) ||
6781 ((*flags & NL80211_SCAN_FLAG_LOW_POWER) &&
6782 !wiphy_ext_feature_isset(wiphy,
6783 NL80211_EXT_FEATURE_LOW_POWER_SCAN)) ||
6784 ((*flags & NL80211_SCAN_FLAG_HIGH_ACCURACY) &&
6785 !wiphy_ext_feature_isset(wiphy,
6786 NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN)))
Roee Zamir2d23d072017-08-06 11:38:22 +03006787 return -EOPNOTSUPP;
6788
6789 if (*flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
6790 int err;
6791
6792 if (!(wiphy->features & randomness_flag) ||
6793 (wdev && wdev->current_bss))
6794 return -EOPNOTSUPP;
6795
6796 err = nl80211_parse_random_mac(attrs, mac_addr, mac_addr_mask);
6797 if (err)
6798 return err;
6799 }
6800
6801 if ((*flags & NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME) &&
6802 !wiphy_ext_feature_isset(wiphy,
6803 NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME))
6804 return -EOPNOTSUPP;
6805
6806 if ((*flags & NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP) &&
6807 !wiphy_ext_feature_isset(wiphy,
6808 NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP))
6809 return -EOPNOTSUPP;
6810
6811 if ((*flags & NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) &&
6812 !wiphy_ext_feature_isset(wiphy,
6813 NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION))
6814 return -EOPNOTSUPP;
6815
6816 if ((*flags & NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE) &&
6817 !wiphy_ext_feature_isset(wiphy,
6818 NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE))
6819 return -EOPNOTSUPP;
6820
6821 return 0;
6822}
6823
Johannes Berg2a519312009-02-10 21:25:55 +01006824static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
6825{
Johannes Berg4c476992010-10-04 21:36:35 +02006826 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfd014282012-06-18 19:17:03 +02006827 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2a519312009-02-10 21:25:55 +01006828 struct cfg80211_scan_request *request;
Johannes Berg2a519312009-02-10 21:25:55 +01006829 struct nlattr *attr;
6830 struct wiphy *wiphy;
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006831 int err, tmp, n_ssids = 0, n_channels, i;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006832 size_t ie_len;
Johannes Berg2a519312009-02-10 21:25:55 +01006833
Johannes Bergf4a11bb2009-03-27 12:40:28 +01006834 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
6835 return -EINVAL;
6836
Johannes Berg79c97e92009-07-07 03:56:12 +02006837 wiphy = &rdev->wiphy;
Johannes Berg2a519312009-02-10 21:25:55 +01006838
Ayala Bekercb3b7d82016-09-20 17:31:13 +03006839 if (wdev->iftype == NL80211_IFTYPE_NAN)
6840 return -EOPNOTSUPP;
6841
Johannes Berg4c476992010-10-04 21:36:35 +02006842 if (!rdev->ops->scan)
6843 return -EOPNOTSUPP;
Johannes Berg2a519312009-02-10 21:25:55 +01006844
Johannes Bergf9d15d12014-01-22 11:14:19 +02006845 if (rdev->scan_req || rdev->scan_msg) {
Johannes Bergf9f47522013-03-19 15:04:07 +01006846 err = -EBUSY;
6847 goto unlock;
6848 }
Johannes Berg2a519312009-02-10 21:25:55 +01006849
6850 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006851 n_channels = validate_scan_freqs(
6852 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Johannes Bergf9f47522013-03-19 15:04:07 +01006853 if (!n_channels) {
6854 err = -EINVAL;
6855 goto unlock;
6856 }
Johannes Berg2a519312009-02-10 21:25:55 +01006857 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02006858 n_channels = ieee80211_get_num_supported_channels(wiphy);
Johannes Berg2a519312009-02-10 21:25:55 +01006859 }
6860
6861 if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
6862 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
6863 n_ssids++;
6864
Johannes Bergf9f47522013-03-19 15:04:07 +01006865 if (n_ssids > wiphy->max_scan_ssids) {
6866 err = -EINVAL;
6867 goto unlock;
6868 }
Johannes Berg2a519312009-02-10 21:25:55 +01006869
Jouni Malinen70692ad2009-02-16 19:39:13 +02006870 if (info->attrs[NL80211_ATTR_IE])
6871 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
6872 else
6873 ie_len = 0;
6874
Johannes Bergf9f47522013-03-19 15:04:07 +01006875 if (ie_len > wiphy->max_scan_ie_len) {
6876 err = -EINVAL;
6877 goto unlock;
6878 }
Johannes Berg18a83652009-03-31 12:12:05 +02006879
Johannes Berg2a519312009-02-10 21:25:55 +01006880 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03006881 + sizeof(*request->ssids) * n_ssids
6882 + sizeof(*request->channels) * n_channels
Jouni Malinen70692ad2009-02-16 19:39:13 +02006883 + ie_len, GFP_KERNEL);
Johannes Bergf9f47522013-03-19 15:04:07 +01006884 if (!request) {
6885 err = -ENOMEM;
6886 goto unlock;
6887 }
Johannes Berg2a519312009-02-10 21:25:55 +01006888
Johannes Berg2a519312009-02-10 21:25:55 +01006889 if (n_ssids)
Johannes Berg5ba63532009-08-07 17:54:07 +02006890 request->ssids = (void *)&request->channels[n_channels];
Johannes Berg2a519312009-02-10 21:25:55 +01006891 request->n_ssids = n_ssids;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006892 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01006893 if (n_ssids)
Jouni Malinen70692ad2009-02-16 19:39:13 +02006894 request->ie = (void *)(request->ssids + n_ssids);
6895 else
6896 request->ie = (void *)(request->channels + n_channels);
6897 }
Johannes Berg2a519312009-02-10 21:25:55 +01006898
Johannes Berg584991d2009-11-02 13:32:03 +01006899 i = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01006900 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
6901 /* user specified, bail out if channel not found */
Johannes Berg2a519312009-02-10 21:25:55 +01006902 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
Johannes Berg584991d2009-11-02 13:32:03 +01006903 struct ieee80211_channel *chan;
6904
6905 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
6906
6907 if (!chan) {
Johannes Berg2a519312009-02-10 21:25:55 +01006908 err = -EINVAL;
6909 goto out_free;
6910 }
Johannes Berg584991d2009-11-02 13:32:03 +01006911
6912 /* ignore disabled channels */
6913 if (chan->flags & IEEE80211_CHAN_DISABLED)
6914 continue;
6915
6916 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006917 i++;
6918 }
6919 } else {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006920 enum nl80211_band band;
Johannes Berg34850ab2011-07-18 18:08:35 +02006921
Johannes Berg2a519312009-02-10 21:25:55 +01006922 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006923 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Johannes Berg2a519312009-02-10 21:25:55 +01006924 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07006925
Johannes Berg2a519312009-02-10 21:25:55 +01006926 if (!wiphy->bands[band])
6927 continue;
6928 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
Johannes Berg584991d2009-11-02 13:32:03 +01006929 struct ieee80211_channel *chan;
6930
6931 chan = &wiphy->bands[band]->channels[j];
6932
6933 if (chan->flags & IEEE80211_CHAN_DISABLED)
6934 continue;
6935
6936 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006937 i++;
6938 }
6939 }
6940 }
6941
Johannes Berg584991d2009-11-02 13:32:03 +01006942 if (!i) {
6943 err = -EINVAL;
6944 goto out_free;
6945 }
6946
6947 request->n_channels = i;
6948
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05306949 wdev_lock(wdev);
6950 if (!cfg80211_off_channel_oper_allowed(wdev)) {
6951 struct ieee80211_channel *chan;
6952
6953 if (request->n_channels != 1) {
6954 wdev_unlock(wdev);
6955 err = -EBUSY;
6956 goto out_free;
6957 }
6958
6959 chan = request->channels[0];
6960 if (chan->center_freq != wdev->chandef.chan->center_freq) {
6961 wdev_unlock(wdev);
6962 err = -EBUSY;
6963 goto out_free;
6964 }
6965 }
6966 wdev_unlock(wdev);
6967
Johannes Berg2a519312009-02-10 21:25:55 +01006968 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01006969 if (n_ssids) {
Johannes Berg2a519312009-02-10 21:25:55 +01006970 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03006971 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Johannes Berg2a519312009-02-10 21:25:55 +01006972 err = -EINVAL;
6973 goto out_free;
6974 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03006975 request->ssids[i].ssid_len = nla_len(attr);
Johannes Berg2a519312009-02-10 21:25:55 +01006976 memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
Johannes Berg2a519312009-02-10 21:25:55 +01006977 i++;
6978 }
6979 }
6980
Jouni Malinen70692ad2009-02-16 19:39:13 +02006981 if (info->attrs[NL80211_ATTR_IE]) {
6982 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Johannes Bergde95a542009-04-01 11:58:36 +02006983 memcpy((void *)request->ie,
6984 nla_data(info->attrs[NL80211_ATTR_IE]),
Jouni Malinen70692ad2009-02-16 19:39:13 +02006985 request->ie_len);
6986 }
6987
Johannes Berg57fbcce2016-04-12 15:56:15 +02006988 for (i = 0; i < NUM_NL80211_BANDS; i++)
Johannes Berga401d2b2011-07-20 00:52:16 +02006989 if (wiphy->bands[i])
6990 request->rates[i] =
6991 (1 << wiphy->bands[i]->n_bitrates) - 1;
Johannes Berg34850ab2011-07-18 18:08:35 +02006992
6993 if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
6994 nla_for_each_nested(attr,
6995 info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
6996 tmp) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006997 enum nl80211_band band = nla_type(attr);
Johannes Berg34850ab2011-07-18 18:08:35 +02006998
Johannes Berg57fbcce2016-04-12 15:56:15 +02006999 if (band < 0 || band >= NUM_NL80211_BANDS) {
Johannes Berg34850ab2011-07-18 18:08:35 +02007000 err = -EINVAL;
7001 goto out_free;
7002 }
Felix Fietkau1b09cd82013-11-20 19:40:41 +01007003
7004 if (!wiphy->bands[band])
7005 continue;
7006
Johannes Berg34850ab2011-07-18 18:08:35 +02007007 err = ieee80211_get_ratemask(wiphy->bands[band],
7008 nla_data(attr),
7009 nla_len(attr),
7010 &request->rates[band]);
7011 if (err)
7012 goto out_free;
7013 }
7014 }
7015
Avraham Stern1d762502016-07-05 17:10:13 +03007016 if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
7017 if (!wiphy_ext_feature_isset(wiphy,
7018 NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
7019 err = -EOPNOTSUPP;
7020 goto out_free;
7021 }
7022
7023 request->duration =
7024 nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
7025 request->duration_mandatory =
7026 nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
7027 }
7028
Roee Zamir2d23d072017-08-06 11:38:22 +03007029 err = nl80211_check_scan_flags(wiphy, wdev, request, info->attrs,
7030 false);
7031 if (err)
7032 goto out_free;
Sam Lefflered4737712012-10-11 21:03:31 -07007033
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05307034 request->no_cck =
7035 nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
7036
Vamsi Krishna2fa436b2016-12-02 23:59:08 +02007037 /* Initial implementation used NL80211_ATTR_MAC to set the specific
7038 * BSSID to scan for. This was problematic because that same attribute
7039 * was already used for another purpose (local random MAC address). The
7040 * NL80211_ATTR_BSSID attribute was added to fix this. For backwards
7041 * compatibility with older userspace components, also use the
7042 * NL80211_ATTR_MAC value here if it can be determined to be used for
7043 * the specific BSSID use case instead of the random MAC address
7044 * (NL80211_ATTR_SCAN_FLAGS is used to enable random MAC address use).
7045 */
7046 if (info->attrs[NL80211_ATTR_BSSID])
7047 memcpy(request->bssid,
7048 nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
7049 else if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
7050 info->attrs[NL80211_ATTR_MAC])
Jouni Malinen818965d2016-02-26 22:12:47 +02007051 memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
7052 ETH_ALEN);
7053 else
7054 eth_broadcast_addr(request->bssid);
7055
Johannes Bergfd014282012-06-18 19:17:03 +02007056 request->wdev = wdev;
Johannes Berg79c97e92009-07-07 03:56:12 +02007057 request->wiphy = &rdev->wiphy;
Sam Leffler15d60302012-10-11 21:03:34 -07007058 request->scan_start = jiffies;
Johannes Berg2a519312009-02-10 21:25:55 +01007059
Johannes Berg79c97e92009-07-07 03:56:12 +02007060 rdev->scan_req = request;
Hila Gonene35e4d22012-06-27 17:19:42 +03007061 err = rdev_scan(rdev, request);
Johannes Berg2a519312009-02-10 21:25:55 +01007062
Johannes Berg463d0182009-07-14 00:33:35 +02007063 if (!err) {
Johannes Bergfd014282012-06-18 19:17:03 +02007064 nl80211_send_scan_start(rdev, wdev);
7065 if (wdev->netdev)
7066 dev_hold(wdev->netdev);
Johannes Berg4c476992010-10-04 21:36:35 +02007067 } else {
Johannes Berg2a519312009-02-10 21:25:55 +01007068 out_free:
Johannes Berg79c97e92009-07-07 03:56:12 +02007069 rdev->scan_req = NULL;
Johannes Berg2a519312009-02-10 21:25:55 +01007070 kfree(request);
7071 }
Johannes Berg3b858752009-03-12 09:55:09 +01007072
Johannes Bergf9f47522013-03-19 15:04:07 +01007073 unlock:
Johannes Berg2a519312009-02-10 21:25:55 +01007074 return err;
7075}
7076
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +05307077static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
7078{
7079 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7080 struct wireless_dev *wdev = info->user_ptr[1];
7081
7082 if (!rdev->ops->abort_scan)
7083 return -EOPNOTSUPP;
7084
7085 if (rdev->scan_msg)
7086 return 0;
7087
7088 if (!rdev->scan_req)
7089 return -ENOENT;
7090
7091 rdev_abort_scan(rdev, wdev);
7092 return 0;
7093}
7094
Avraham Stern3b06d272015-10-12 09:51:34 +03007095static int
7096nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
7097 struct cfg80211_sched_scan_request *request,
7098 struct nlattr **attrs)
7099{
7100 int tmp, err, i = 0;
7101 struct nlattr *attr;
7102
7103 if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
7104 u32 interval;
7105
7106 /*
7107 * If scan plans are not specified,
Arend Van Spriel5a88de52016-11-17 09:02:40 +00007108 * %NL80211_ATTR_SCHED_SCAN_INTERVAL will be specified. In this
Avraham Stern3b06d272015-10-12 09:51:34 +03007109 * case one scan plan will be set with the specified scan
7110 * interval and infinite number of iterations.
7111 */
Avraham Stern3b06d272015-10-12 09:51:34 +03007112 interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
7113 if (!interval)
7114 return -EINVAL;
7115
7116 request->scan_plans[0].interval =
7117 DIV_ROUND_UP(interval, MSEC_PER_SEC);
7118 if (!request->scan_plans[0].interval)
7119 return -EINVAL;
7120
7121 if (request->scan_plans[0].interval >
7122 wiphy->max_sched_scan_plan_interval)
7123 request->scan_plans[0].interval =
7124 wiphy->max_sched_scan_plan_interval;
7125
7126 return 0;
7127 }
7128
7129 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
7130 struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
7131
7132 if (WARN_ON(i >= n_plans))
7133 return -EINVAL;
7134
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02007135 err = nla_parse_nested(plan, NL80211_SCHED_SCAN_PLAN_MAX,
Johannes Bergfceb6432017-04-12 14:34:07 +02007136 attr, nl80211_plan_policy, NULL);
Avraham Stern3b06d272015-10-12 09:51:34 +03007137 if (err)
7138 return err;
7139
7140 if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
7141 return -EINVAL;
7142
7143 request->scan_plans[i].interval =
7144 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
7145 if (!request->scan_plans[i].interval ||
7146 request->scan_plans[i].interval >
7147 wiphy->max_sched_scan_plan_interval)
7148 return -EINVAL;
7149
7150 if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
7151 request->scan_plans[i].iterations =
7152 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
7153 if (!request->scan_plans[i].iterations ||
7154 (request->scan_plans[i].iterations >
7155 wiphy->max_sched_scan_plan_iterations))
7156 return -EINVAL;
7157 } else if (i < n_plans - 1) {
7158 /*
7159 * All scan plans but the last one must specify
7160 * a finite number of iterations
7161 */
7162 return -EINVAL;
7163 }
7164
7165 i++;
7166 }
7167
7168 /*
7169 * The last scan plan must not specify the number of
7170 * iterations, it is supposed to run infinitely
7171 */
7172 if (request->scan_plans[n_plans - 1].iterations)
7173 return -EINVAL;
7174
7175 return 0;
7176}
7177
Luciano Coelho256da022014-11-10 16:13:46 +02007178static struct cfg80211_sched_scan_request *
Johannes Bergad2b26a2014-06-12 21:39:05 +02007179nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00007180 struct nlattr **attrs, int max_match_sets)
Luciano Coelho807f8a82011-05-11 17:09:35 +03007181{
7182 struct cfg80211_sched_scan_request *request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007183 struct nlattr *attr;
Avraham Stern3b06d272015-10-12 09:51:34 +03007184 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
Johannes Berg57fbcce2016-04-12 15:56:15 +02007185 enum nl80211_band band;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007186 size_t ie_len;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007187 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
Johannes Bergea73cbc2014-01-24 10:53:53 +01007188 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007189
Luciano Coelho256da022014-11-10 16:13:46 +02007190 if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE]))
7191 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007192
Luciano Coelho256da022014-11-10 16:13:46 +02007193 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007194 n_channels = validate_scan_freqs(
Luciano Coelho256da022014-11-10 16:13:46 +02007195 attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007196 if (!n_channels)
Luciano Coelho256da022014-11-10 16:13:46 +02007197 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007198 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02007199 n_channels = ieee80211_get_num_supported_channels(wiphy);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007200 }
7201
Luciano Coelho256da022014-11-10 16:13:46 +02007202 if (attrs[NL80211_ATTR_SCAN_SSIDS])
7203 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007204 tmp)
7205 n_ssids++;
7206
Luciano Coelho93b6aa62011-07-13 14:57:28 +03007207 if (n_ssids > wiphy->max_sched_scan_ssids)
Luciano Coelho256da022014-11-10 16:13:46 +02007208 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007209
Johannes Bergea73cbc2014-01-24 10:53:53 +01007210 /*
7211 * First, count the number of 'real' matchsets. Due to an issue with
7212 * the old implementation, matchsets containing only the RSSI attribute
7213 * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
7214 * RSSI for all matchsets, rather than their own matchset for reporting
7215 * all APs with a strong RSSI. This is needed to be compatible with
7216 * older userspace that treated a matchset with only the RSSI as the
7217 * global RSSI for all other matchsets - if there are other matchsets.
7218 */
Luciano Coelho256da022014-11-10 16:13:46 +02007219 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007220 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007221 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Johannes Bergea73cbc2014-01-24 10:53:53 +01007222 tmp) {
7223 struct nlattr *rssi;
7224
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02007225 err = nla_parse_nested(tb,
7226 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
Johannes Bergfceb6432017-04-12 14:34:07 +02007227 attr, nl80211_match_policy,
7228 NULL);
Johannes Bergea73cbc2014-01-24 10:53:53 +01007229 if (err)
Luciano Coelho256da022014-11-10 16:13:46 +02007230 return ERR_PTR(err);
Arend Van Spriel3007e352017-04-21 13:05:01 +01007231
7232 /* SSID and BSSID are mutually exclusive */
7233 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] &&
7234 tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID])
7235 return ERR_PTR(-EINVAL);
7236
Johannes Bergea73cbc2014-01-24 10:53:53 +01007237 /* add other standalone attributes here */
Arend Van Spriel3007e352017-04-21 13:05:01 +01007238 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] ||
7239 tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID]) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01007240 n_match_sets++;
7241 continue;
7242 }
7243 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
7244 if (rssi)
7245 default_match_rssi = nla_get_s32(rssi);
7246 }
7247 }
7248
7249 /* However, if there's no other matchset, add the RSSI one */
7250 if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
7251 n_match_sets = 1;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007252
Arend Van Sprielaad1e812017-01-27 12:27:44 +00007253 if (n_match_sets > max_match_sets)
Luciano Coelho256da022014-11-10 16:13:46 +02007254 return ERR_PTR(-EINVAL);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007255
Luciano Coelho256da022014-11-10 16:13:46 +02007256 if (attrs[NL80211_ATTR_IE])
7257 ie_len = nla_len(attrs[NL80211_ATTR_IE]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007258 else
7259 ie_len = 0;
7260
Luciano Coelho5a865ba2011-07-13 14:57:29 +03007261 if (ie_len > wiphy->max_sched_scan_ie_len)
Luciano Coelho256da022014-11-10 16:13:46 +02007262 return ERR_PTR(-EINVAL);
Luciano Coelhoc10841c2011-06-30 08:32:41 +03007263
Avraham Stern3b06d272015-10-12 09:51:34 +03007264 if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
7265 /*
7266 * NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
7267 * each scan plan already specifies its own interval
7268 */
7269 if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
7270 return ERR_PTR(-EINVAL);
7271
7272 nla_for_each_nested(attr,
7273 attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
7274 n_plans++;
7275 } else {
7276 /*
7277 * The scan interval attribute is kept for backward
7278 * compatibility. If no scan plans are specified and sched scan
7279 * interval is specified, one scan plan will be set with this
7280 * scan interval and infinite number of iterations.
7281 */
7282 if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
7283 return ERR_PTR(-EINVAL);
7284
7285 n_plans = 1;
7286 }
7287
7288 if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
7289 return ERR_PTR(-EINVAL);
7290
vamsi krishnabf95ecd2017-01-13 01:12:20 +02007291 if (!wiphy_ext_feature_isset(
7292 wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
7293 (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
7294 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
7295 return ERR_PTR(-EINVAL);
7296
Luciano Coelho807f8a82011-05-11 17:09:35 +03007297 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007298 + sizeof(*request->ssids) * n_ssids
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007299 + sizeof(*request->match_sets) * n_match_sets
Avraham Stern3b06d272015-10-12 09:51:34 +03007300 + sizeof(*request->scan_plans) * n_plans
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007301 + sizeof(*request->channels) * n_channels
Luciano Coelho807f8a82011-05-11 17:09:35 +03007302 + ie_len, GFP_KERNEL);
Luciano Coelho256da022014-11-10 16:13:46 +02007303 if (!request)
7304 return ERR_PTR(-ENOMEM);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007305
7306 if (n_ssids)
7307 request->ssids = (void *)&request->channels[n_channels];
7308 request->n_ssids = n_ssids;
7309 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01007310 if (n_ssids)
Luciano Coelho807f8a82011-05-11 17:09:35 +03007311 request->ie = (void *)(request->ssids + n_ssids);
7312 else
7313 request->ie = (void *)(request->channels + n_channels);
7314 }
7315
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007316 if (n_match_sets) {
7317 if (request->ie)
7318 request->match_sets = (void *)(request->ie + ie_len);
Johannes Berg13874e42015-01-23 11:25:20 +01007319 else if (n_ssids)
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007320 request->match_sets =
7321 (void *)(request->ssids + n_ssids);
7322 else
7323 request->match_sets =
7324 (void *)(request->channels + n_channels);
7325 }
7326 request->n_match_sets = n_match_sets;
7327
Avraham Stern3b06d272015-10-12 09:51:34 +03007328 if (n_match_sets)
7329 request->scan_plans = (void *)(request->match_sets +
7330 n_match_sets);
7331 else if (request->ie)
7332 request->scan_plans = (void *)(request->ie + ie_len);
7333 else if (n_ssids)
7334 request->scan_plans = (void *)(request->ssids + n_ssids);
7335 else
7336 request->scan_plans = (void *)(request->channels + n_channels);
7337
7338 request->n_scan_plans = n_plans;
7339
Luciano Coelho807f8a82011-05-11 17:09:35 +03007340 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007341 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007342 /* user specified, bail out if channel not found */
7343 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007344 attrs[NL80211_ATTR_SCAN_FREQUENCIES],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007345 tmp) {
7346 struct ieee80211_channel *chan;
7347
7348 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
7349
7350 if (!chan) {
7351 err = -EINVAL;
7352 goto out_free;
7353 }
7354
7355 /* ignore disabled channels */
7356 if (chan->flags & IEEE80211_CHAN_DISABLED)
7357 continue;
7358
7359 request->channels[i] = chan;
7360 i++;
7361 }
7362 } else {
7363 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02007364 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007365 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007366
Luciano Coelho807f8a82011-05-11 17:09:35 +03007367 if (!wiphy->bands[band])
7368 continue;
7369 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
7370 struct ieee80211_channel *chan;
7371
7372 chan = &wiphy->bands[band]->channels[j];
7373
7374 if (chan->flags & IEEE80211_CHAN_DISABLED)
7375 continue;
7376
7377 request->channels[i] = chan;
7378 i++;
7379 }
7380 }
7381 }
7382
7383 if (!i) {
7384 err = -EINVAL;
7385 goto out_free;
7386 }
7387
7388 request->n_channels = i;
7389
7390 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01007391 if (n_ssids) {
Luciano Coelho256da022014-11-10 16:13:46 +02007392 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007393 tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03007394 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007395 err = -EINVAL;
7396 goto out_free;
7397 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03007398 request->ssids[i].ssid_len = nla_len(attr);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007399 memcpy(request->ssids[i].ssid, nla_data(attr),
7400 nla_len(attr));
Luciano Coelho807f8a82011-05-11 17:09:35 +03007401 i++;
7402 }
7403 }
7404
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007405 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007406 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007407 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007408 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007409 tmp) {
Arend Van Spriel3007e352017-04-21 13:05:01 +01007410 struct nlattr *ssid, *bssid, *rssi;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007411
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02007412 err = nla_parse_nested(tb,
7413 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
Johannes Bergfceb6432017-04-12 14:34:07 +02007414 attr, nl80211_match_policy,
7415 NULL);
Johannes Bergae811e22014-01-24 10:17:47 +01007416 if (err)
7417 goto out_free;
Johannes Berg4a4ab0d2012-06-13 11:17:11 +02007418 ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
Arend Van Spriel3007e352017-04-21 13:05:01 +01007419 bssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID];
7420 if (ssid || bssid) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01007421 if (WARN_ON(i >= n_match_sets)) {
7422 /* this indicates a programming error,
7423 * the loop above should have verified
7424 * things properly
7425 */
7426 err = -EINVAL;
7427 goto out_free;
7428 }
7429
Arend Van Spriel3007e352017-04-21 13:05:01 +01007430 if (ssid) {
7431 if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
7432 err = -EINVAL;
7433 goto out_free;
7434 }
7435 memcpy(request->match_sets[i].ssid.ssid,
7436 nla_data(ssid), nla_len(ssid));
7437 request->match_sets[i].ssid.ssid_len =
7438 nla_len(ssid);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007439 }
Arend Van Spriel3007e352017-04-21 13:05:01 +01007440 if (bssid) {
7441 if (nla_len(bssid) != ETH_ALEN) {
7442 err = -EINVAL;
7443 goto out_free;
7444 }
7445 memcpy(request->match_sets[i].bssid,
7446 nla_data(bssid), ETH_ALEN);
7447 }
7448
Kirtika Ruchandani56ab3642016-05-29 19:54:10 -07007449 /* special attribute - old implementation w/a */
Johannes Bergea73cbc2014-01-24 10:53:53 +01007450 request->match_sets[i].rssi_thold =
7451 default_match_rssi;
7452 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
7453 if (rssi)
7454 request->match_sets[i].rssi_thold =
7455 nla_get_s32(rssi);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007456 }
7457 i++;
7458 }
Johannes Bergea73cbc2014-01-24 10:53:53 +01007459
7460 /* there was no other matchset, so the RSSI one is alone */
Luciano Coelhof89f46c2014-12-01 11:32:09 +02007461 if (i == 0 && n_match_sets)
Johannes Bergea73cbc2014-01-24 10:53:53 +01007462 request->match_sets[0].rssi_thold = default_match_rssi;
7463
7464 request->min_rssi_thold = INT_MAX;
7465 for (i = 0; i < n_match_sets; i++)
7466 request->min_rssi_thold =
7467 min(request->match_sets[i].rssi_thold,
7468 request->min_rssi_thold);
7469 } else {
7470 request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007471 }
7472
Johannes Berg9900e482014-02-04 21:01:25 +01007473 if (ie_len) {
7474 request->ie_len = ie_len;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007475 memcpy((void *)request->ie,
Luciano Coelho256da022014-11-10 16:13:46 +02007476 nla_data(attrs[NL80211_ATTR_IE]),
Luciano Coelho807f8a82011-05-11 17:09:35 +03007477 request->ie_len);
7478 }
7479
Roee Zamir2d23d072017-08-06 11:38:22 +03007480 err = nl80211_check_scan_flags(wiphy, wdev, request, attrs, true);
7481 if (err)
7482 goto out_free;
Sam Lefflered4737712012-10-11 21:03:31 -07007483
Luciano Coelho9c748932015-01-16 16:04:09 +02007484 if (attrs[NL80211_ATTR_SCHED_SCAN_DELAY])
7485 request->delay =
7486 nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
7487
vamsi krishnabf95ecd2017-01-13 01:12:20 +02007488 if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
7489 request->relative_rssi = nla_get_s8(
7490 attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
7491 request->relative_rssi_set = true;
7492 }
7493
7494 if (request->relative_rssi_set &&
7495 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
7496 struct nl80211_bss_select_rssi_adjust *rssi_adjust;
7497
7498 rssi_adjust = nla_data(
7499 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
7500 request->rssi_adjust.band = rssi_adjust->band;
7501 request->rssi_adjust.delta = rssi_adjust->delta;
7502 if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
7503 err = -EINVAL;
7504 goto out_free;
7505 }
7506 }
7507
Avraham Stern3b06d272015-10-12 09:51:34 +03007508 err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
7509 if (err)
7510 goto out_free;
7511
Sam Leffler15d60302012-10-11 21:03:34 -07007512 request->scan_start = jiffies;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007513
Luciano Coelho256da022014-11-10 16:13:46 +02007514 return request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007515
7516out_free:
7517 kfree(request);
Luciano Coelho256da022014-11-10 16:13:46 +02007518 return ERR_PTR(err);
7519}
7520
7521static int nl80211_start_sched_scan(struct sk_buff *skb,
7522 struct genl_info *info)
7523{
7524 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7525 struct net_device *dev = info->user_ptr[1];
Johannes Bergad2b26a2014-06-12 21:39:05 +02007526 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007527 struct cfg80211_sched_scan_request *sched_scan_req;
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007528 bool want_multi;
Luciano Coelho256da022014-11-10 16:13:46 +02007529 int err;
7530
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007531 if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_start)
Luciano Coelho256da022014-11-10 16:13:46 +02007532 return -EOPNOTSUPP;
7533
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007534 want_multi = info->attrs[NL80211_ATTR_SCHED_SCAN_MULTI];
7535 err = cfg80211_sched_scan_req_possible(rdev, want_multi);
7536 if (err)
7537 return err;
Luciano Coelho256da022014-11-10 16:13:46 +02007538
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007539 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00007540 info->attrs,
7541 rdev->wiphy.max_match_sets);
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007542
7543 err = PTR_ERR_OR_ZERO(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007544 if (err)
7545 goto out_err;
7546
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007547 /* leave request id zero for legacy request
7548 * or if driver does not support multi-scheduled scan
7549 */
7550 if (want_multi && rdev->wiphy.max_sched_scan_reqs > 1) {
7551 while (!sched_scan_req->reqid)
7552 sched_scan_req->reqid = rdev->wiphy.cookie_counter++;
7553 }
7554
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007555 err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007556 if (err)
7557 goto out_free;
7558
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007559 sched_scan_req->dev = dev;
7560 sched_scan_req->wiphy = &rdev->wiphy;
7561
Jukka Rissanen93a1e862014-12-15 13:25:39 +02007562 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
7563 sched_scan_req->owner_nlportid = info->snd_portid;
7564
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007565 cfg80211_add_sched_scan_req(rdev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007566
Arend Van Spriel96b08fd2017-04-13 13:06:27 +01007567 nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN);
Luciano Coelho256da022014-11-10 16:13:46 +02007568 return 0;
7569
7570out_free:
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007571 kfree(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007572out_err:
Luciano Coelho807f8a82011-05-11 17:09:35 +03007573 return err;
7574}
7575
7576static int nl80211_stop_sched_scan(struct sk_buff *skb,
7577 struct genl_info *info)
7578{
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007579 struct cfg80211_sched_scan_request *req;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007580 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007581 u64 cookie;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007582
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007583 if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_stop)
Luciano Coelho807f8a82011-05-11 17:09:35 +03007584 return -EOPNOTSUPP;
7585
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007586 if (info->attrs[NL80211_ATTR_COOKIE]) {
7587 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
7588 return __cfg80211_stop_sched_scan(rdev, cookie, false);
7589 }
7590
7591 req = list_first_or_null_rcu(&rdev->sched_scan_req_list,
7592 struct cfg80211_sched_scan_request,
7593 list);
7594 if (!req || req->reqid ||
7595 (req->owner_nlportid &&
7596 req->owner_nlportid != info->snd_portid))
7597 return -ENOENT;
7598
7599 return cfg80211_stop_sched_scan_req(rdev, req, false);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007600}
7601
Simon Wunderlich04f39042013-02-08 18:16:19 +01007602static int nl80211_start_radar_detection(struct sk_buff *skb,
7603 struct genl_info *info)
7604{
7605 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7606 struct net_device *dev = info->user_ptr[1];
7607 struct wireless_dev *wdev = dev->ieee80211_ptr;
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03007608 struct wiphy *wiphy = wdev->wiphy;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007609 struct cfg80211_chan_def chandef;
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007610 enum nl80211_dfs_regions dfs_region;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007611 unsigned int cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007612 int err;
7613
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03007614 dfs_region = reg_get_dfs_region(wiphy);
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007615 if (dfs_region == NL80211_DFS_UNSET)
7616 return -EINVAL;
7617
Simon Wunderlich04f39042013-02-08 18:16:19 +01007618 err = nl80211_parse_chandef(rdev, info, &chandef);
7619 if (err)
7620 return err;
7621
Simon Wunderlichff311bc2013-09-03 19:43:18 +02007622 if (netif_carrier_ok(dev))
7623 return -EBUSY;
7624
Simon Wunderlich04f39042013-02-08 18:16:19 +01007625 if (wdev->cac_started)
7626 return -EBUSY;
7627
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03007628 err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007629 if (err < 0)
7630 return err;
7631
7632 if (err == 0)
7633 return -EINVAL;
7634
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03007635 if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
Simon Wunderlich04f39042013-02-08 18:16:19 +01007636 return -EINVAL;
7637
Dmitry Lebed13cf6de2018-03-01 12:39:15 +03007638 /* CAC start is offloaded to HW and can't be started manually */
7639 if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))
7640 return -EOPNOTSUPP;
7641
Simon Wunderlich04f39042013-02-08 18:16:19 +01007642 if (!rdev->ops->start_radar_detection)
7643 return -EOPNOTSUPP;
7644
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007645 cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
7646 if (WARN_ON(!cac_time_ms))
7647 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
7648
Ilan Peera1056b1b2015-10-22 22:27:46 +03007649 err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007650 if (!err) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01007651 wdev->chandef = chandef;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007652 wdev->cac_started = true;
7653 wdev->cac_start_time = jiffies;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007654 wdev->cac_time_ms = cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007655 }
Simon Wunderlich04f39042013-02-08 18:16:19 +01007656 return err;
7657}
7658
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007659static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
7660{
7661 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7662 struct net_device *dev = info->user_ptr[1];
7663 struct wireless_dev *wdev = dev->ieee80211_ptr;
7664 struct cfg80211_csa_settings params;
7665 /* csa_attrs is defined static to avoid waste of stack size - this
7666 * function is called under RTNL lock, so this should not be a problem.
7667 */
7668 static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007669 int err;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007670 bool need_new_beacon = false;
Benjamin Berg8d9de162017-05-16 11:23:12 +02007671 bool need_handle_dfs_flag = true;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007672 int len, i;
Luciano Coelho252e07c2014-10-08 09:48:34 +03007673 u32 cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007674
7675 if (!rdev->ops->channel_switch ||
7676 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
7677 return -EOPNOTSUPP;
7678
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007679 switch (dev->ieee80211_ptr->iftype) {
7680 case NL80211_IFTYPE_AP:
7681 case NL80211_IFTYPE_P2P_GO:
7682 need_new_beacon = true;
Benjamin Berg8d9de162017-05-16 11:23:12 +02007683 /* For all modes except AP the handle_dfs flag needs to be
7684 * supplied to tell the kernel that userspace will handle radar
7685 * events when they happen. Otherwise a switch to a channel
7686 * requiring DFS will be rejected.
7687 */
7688 need_handle_dfs_flag = false;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007689
7690 /* useless if AP is not running */
7691 if (!wdev->beacon_interval)
Johannes Berg1ff79df2014-01-22 10:05:27 +01007692 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007693 break;
7694 case NL80211_IFTYPE_ADHOC:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007695 if (!wdev->ssid_len)
7696 return -ENOTCONN;
7697 break;
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07007698 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007699 if (!wdev->mesh_id_len)
7700 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007701 break;
7702 default:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007703 return -EOPNOTSUPP;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007704 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007705
7706 memset(&params, 0, sizeof(params));
7707
7708 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
7709 !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
7710 return -EINVAL;
7711
7712 /* only important for AP, IBSS and mesh create IEs internally */
Andrei Otcheretianskid0a361a2013-10-17 10:52:17 +02007713 if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007714 return -EINVAL;
7715
Luciano Coelho252e07c2014-10-08 09:48:34 +03007716 /* Even though the attribute is u32, the specification says
7717 * u8, so let's make sure we don't overflow.
7718 */
7719 cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
7720 if (cs_count > 255)
7721 return -EINVAL;
7722
7723 params.count = cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007724
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007725 if (!need_new_beacon)
7726 goto skip_beacons;
7727
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007728 err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
7729 if (err)
7730 return err;
7731
7732 err = nla_parse_nested(csa_attrs, NL80211_ATTR_MAX,
7733 info->attrs[NL80211_ATTR_CSA_IES],
Johannes Bergfe521452017-04-12 14:34:08 +02007734 nl80211_policy, info->extack);
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007735 if (err)
7736 return err;
7737
7738 err = nl80211_parse_beacon(csa_attrs, &params.beacon_csa);
7739 if (err)
7740 return err;
7741
7742 if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
7743 return -EINVAL;
7744
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007745 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7746 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007747 return -EINVAL;
7748
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007749 params.n_counter_offsets_beacon = len / sizeof(u16);
7750 if (rdev->wiphy.max_num_csa_counters &&
7751 (params.n_counter_offsets_beacon >
7752 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007753 return -EINVAL;
7754
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007755 params.counter_offsets_beacon =
7756 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7757
7758 /* sanity checks - counters should fit and be the same */
7759 for (i = 0; i < params.n_counter_offsets_beacon; i++) {
7760 u16 offset = params.counter_offsets_beacon[i];
7761
7762 if (offset >= params.beacon_csa.tail_len)
7763 return -EINVAL;
7764
7765 if (params.beacon_csa.tail[offset] != params.count)
7766 return -EINVAL;
7767 }
7768
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007769 if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007770 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7771 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007772 return -EINVAL;
7773
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007774 params.n_counter_offsets_presp = len / sizeof(u16);
7775 if (rdev->wiphy.max_num_csa_counters &&
Johannes Bergad5987b2016-09-13 15:53:55 +02007776 (params.n_counter_offsets_presp >
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007777 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007778 return -EINVAL;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007779
7780 params.counter_offsets_presp =
7781 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7782
7783 /* sanity checks - counters should fit and be the same */
7784 for (i = 0; i < params.n_counter_offsets_presp; i++) {
7785 u16 offset = params.counter_offsets_presp[i];
7786
7787 if (offset >= params.beacon_csa.probe_resp_len)
7788 return -EINVAL;
7789
7790 if (params.beacon_csa.probe_resp[offset] !=
7791 params.count)
7792 return -EINVAL;
7793 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007794 }
7795
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007796skip_beacons:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007797 err = nl80211_parse_chandef(rdev, info, &params.chandef);
7798 if (err)
7799 return err;
7800
Arik Nemtsov923b3522015-07-08 15:41:44 +03007801 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
7802 wdev->iftype))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007803 return -EINVAL;
7804
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007805 err = cfg80211_chandef_dfs_required(wdev->wiphy,
7806 &params.chandef,
7807 wdev->iftype);
7808 if (err < 0)
7809 return err;
7810
Benjamin Berg8d9de162017-05-16 11:23:12 +02007811 if (err > 0) {
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007812 params.radar_required = true;
Benjamin Berg8d9de162017-05-16 11:23:12 +02007813 if (need_handle_dfs_flag &&
7814 !nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) {
7815 return -EINVAL;
7816 }
7817 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007818
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007819 if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
7820 params.block_tx = true;
7821
Simon Wunderlichc56589e2013-11-21 18:19:49 +01007822 wdev_lock(wdev);
7823 err = rdev_channel_switch(rdev, dev, &params);
7824 wdev_unlock(wdev);
7825
7826 return err;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007827}
7828
Johannes Berg9720bb32011-06-21 09:45:33 +02007829static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
7830 u32 seq, int flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007831 struct cfg80211_registered_device *rdev,
Johannes Berg48ab9052009-07-10 18:42:31 +02007832 struct wireless_dev *wdev,
7833 struct cfg80211_internal_bss *intbss)
Johannes Berg2a519312009-02-10 21:25:55 +01007834{
Johannes Berg48ab9052009-07-10 18:42:31 +02007835 struct cfg80211_bss *res = &intbss->pub;
Johannes Berg9caf0362012-11-29 01:25:20 +01007836 const struct cfg80211_bss_ies *ies;
Johannes Berg2a519312009-02-10 21:25:55 +01007837 void *hdr;
7838 struct nlattr *bss;
Johannes Berg48ab9052009-07-10 18:42:31 +02007839
7840 ASSERT_WDEV_LOCK(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007841
Eric W. Biederman15e47302012-09-07 20:12:54 +00007842 hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007843 NL80211_CMD_NEW_SCAN_RESULTS);
7844 if (!hdr)
7845 return -1;
7846
Michal Kubecek0a833c22017-11-15 13:09:32 +01007847 genl_dump_check_consistent(cb, hdr);
Johannes Berg9720bb32011-06-21 09:45:33 +02007848
Johannes Berg97990a02013-04-19 01:02:55 +02007849 if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
7850 goto nla_put_failure;
7851 if (wdev->netdev &&
David S. Miller9360ffd2012-03-29 04:41:26 -04007852 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
7853 goto nla_put_failure;
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007854 if (nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
7855 NL80211_ATTR_PAD))
Johannes Berg97990a02013-04-19 01:02:55 +02007856 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007857
7858 bss = nla_nest_start(msg, NL80211_ATTR_BSS);
7859 if (!bss)
7860 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04007861 if ((!is_zero_ether_addr(res->bssid) &&
Johannes Berg9caf0362012-11-29 01:25:20 +01007862 nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
David S. Miller9360ffd2012-03-29 04:41:26 -04007863 goto nla_put_failure;
Johannes Berg9caf0362012-11-29 01:25:20 +01007864
7865 rcu_read_lock();
Johannes Berg0e227082014-08-12 20:34:30 +02007866 /* indicate whether we have probe response data or not */
7867 if (rcu_access_pointer(res->proberesp_ies) &&
7868 nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
7869 goto fail_unlock_rcu;
7870
7871 /* this pointer prefers to be pointed to probe response data
7872 * but is always valid
7873 */
Johannes Berg9caf0362012-11-29 01:25:20 +01007874 ies = rcu_dereference(res->ies);
Johannes Berg8cef2c92013-02-05 16:54:31 +01007875 if (ies) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007876 if (nla_put_u64_64bit(msg, NL80211_BSS_TSF, ies->tsf,
7877 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007878 goto fail_unlock_rcu;
Johannes Berg8cef2c92013-02-05 16:54:31 +01007879 if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
7880 ies->len, ies->data))
7881 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007882 }
Johannes Berg0e227082014-08-12 20:34:30 +02007883
7884 /* and this pointer is always (unless driver didn't know) beacon data */
Johannes Berg9caf0362012-11-29 01:25:20 +01007885 ies = rcu_dereference(res->beacon_ies);
Johannes Berg0e227082014-08-12 20:34:30 +02007886 if (ies && ies->from_beacon) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007887 if (nla_put_u64_64bit(msg, NL80211_BSS_BEACON_TSF, ies->tsf,
7888 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007889 goto fail_unlock_rcu;
7890 if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
7891 ies->len, ies->data))
7892 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007893 }
7894 rcu_read_unlock();
7895
David S. Miller9360ffd2012-03-29 04:41:26 -04007896 if (res->beacon_interval &&
7897 nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
7898 goto nla_put_failure;
7899 if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
7900 nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
Simon Wunderlichdcd6eac2013-07-08 16:55:49 +02007901 nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04007902 nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
7903 jiffies_to_msecs(jiffies - intbss->ts)))
7904 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007905
Avraham Stern1d762502016-07-05 17:10:13 +03007906 if (intbss->parent_tsf &&
7907 (nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
7908 intbss->parent_tsf, NL80211_BSS_PAD) ||
7909 nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
7910 intbss->parent_bssid)))
7911 goto nla_put_failure;
7912
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007913 if (intbss->ts_boottime &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007914 nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
7915 intbss->ts_boottime, NL80211_BSS_PAD))
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007916 goto nla_put_failure;
7917
Sunil Dutt983dafa2017-12-13 19:51:36 +02007918 if (!nl80211_put_signal(msg, intbss->pub.chains,
7919 intbss->pub.chain_signal,
7920 NL80211_BSS_CHAIN_SIGNAL))
7921 goto nla_put_failure;
7922
Johannes Berg77965c92009-02-18 18:45:06 +01007923 switch (rdev->wiphy.signal_type) {
Johannes Berg2a519312009-02-10 21:25:55 +01007924 case CFG80211_SIGNAL_TYPE_MBM:
David S. Miller9360ffd2012-03-29 04:41:26 -04007925 if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
7926 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007927 break;
7928 case CFG80211_SIGNAL_TYPE_UNSPEC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007929 if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
7930 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007931 break;
7932 default:
7933 break;
7934 }
7935
Johannes Berg48ab9052009-07-10 18:42:31 +02007936 switch (wdev->iftype) {
Johannes Berg074ac8d2010-09-16 14:58:22 +02007937 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg48ab9052009-07-10 18:42:31 +02007938 case NL80211_IFTYPE_STATION:
David S. Miller9360ffd2012-03-29 04:41:26 -04007939 if (intbss == wdev->current_bss &&
7940 nla_put_u32(msg, NL80211_BSS_STATUS,
7941 NL80211_BSS_STATUS_ASSOCIATED))
7942 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007943 break;
7944 case NL80211_IFTYPE_ADHOC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007945 if (intbss == wdev->current_bss &&
7946 nla_put_u32(msg, NL80211_BSS_STATUS,
7947 NL80211_BSS_STATUS_IBSS_JOINED))
7948 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007949 break;
7950 default:
7951 break;
7952 }
7953
Johannes Berg2a519312009-02-10 21:25:55 +01007954 nla_nest_end(msg, bss);
7955
Johannes Berg053c0952015-01-16 22:09:00 +01007956 genlmsg_end(msg, hdr);
7957 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007958
Johannes Berg8cef2c92013-02-05 16:54:31 +01007959 fail_unlock_rcu:
7960 rcu_read_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01007961 nla_put_failure:
7962 genlmsg_cancel(msg, hdr);
7963 return -EMSGSIZE;
7964}
7965
Johannes Berg97990a02013-04-19 01:02:55 +02007966static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
Johannes Berg2a519312009-02-10 21:25:55 +01007967{
Johannes Berg48ab9052009-07-10 18:42:31 +02007968 struct cfg80211_registered_device *rdev;
Johannes Berg2a519312009-02-10 21:25:55 +01007969 struct cfg80211_internal_bss *scan;
Johannes Berg48ab9052009-07-10 18:42:31 +02007970 struct wireless_dev *wdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007971 int start = cb->args[2], idx = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007972 int err;
7973
Johannes Bergea90e0d2017-03-15 14:26:04 +01007974 rtnl_lock();
Johannes Berg97990a02013-04-19 01:02:55 +02007975 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Bergea90e0d2017-03-15 14:26:04 +01007976 if (err) {
7977 rtnl_unlock();
Johannes Berg67748892010-10-04 21:14:06 +02007978 return err;
Johannes Bergea90e0d2017-03-15 14:26:04 +01007979 }
Johannes Berg2a519312009-02-10 21:25:55 +01007980
Johannes Berg48ab9052009-07-10 18:42:31 +02007981 wdev_lock(wdev);
7982 spin_lock_bh(&rdev->bss_lock);
7983 cfg80211_bss_expire(rdev);
7984
Johannes Berg9720bb32011-06-21 09:45:33 +02007985 cb->seq = rdev->bss_generation;
7986
Johannes Berg48ab9052009-07-10 18:42:31 +02007987 list_for_each_entry(scan, &rdev->bss_list, list) {
Johannes Berg2a519312009-02-10 21:25:55 +01007988 if (++idx <= start)
7989 continue;
Johannes Berg9720bb32011-06-21 09:45:33 +02007990 if (nl80211_send_bss(skb, cb,
Johannes Berg2a519312009-02-10 21:25:55 +01007991 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg48ab9052009-07-10 18:42:31 +02007992 rdev, wdev, scan) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +01007993 idx--;
Johannes Berg67748892010-10-04 21:14:06 +02007994 break;
Johannes Berg2a519312009-02-10 21:25:55 +01007995 }
7996 }
7997
Johannes Berg48ab9052009-07-10 18:42:31 +02007998 spin_unlock_bh(&rdev->bss_lock);
7999 wdev_unlock(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01008000
Johannes Berg97990a02013-04-19 01:02:55 +02008001 cb->args[2] = idx;
Johannes Bergea90e0d2017-03-15 14:26:04 +01008002 rtnl_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01008003
Johannes Berg67748892010-10-04 21:14:06 +02008004 return skb->len;
Johannes Berg2a519312009-02-10 21:25:55 +01008005}
8006
Eric W. Biederman15e47302012-09-07 20:12:54 +00008007static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg11f78ac2014-11-14 16:43:50 +01008008 int flags, struct net_device *dev,
8009 bool allow_radio_stats,
8010 struct survey_info *survey)
Holger Schurig61fa7132009-11-11 12:25:40 +01008011{
8012 void *hdr;
8013 struct nlattr *infoattr;
8014
Johannes Berg11f78ac2014-11-14 16:43:50 +01008015 /* skip radio stats if userspace didn't request them */
8016 if (!survey->channel && !allow_radio_stats)
8017 return 0;
8018
Eric W. Biederman15e47302012-09-07 20:12:54 +00008019 hdr = nl80211hdr_put(msg, portid, seq, flags,
Holger Schurig61fa7132009-11-11 12:25:40 +01008020 NL80211_CMD_NEW_SURVEY_RESULTS);
8021 if (!hdr)
8022 return -ENOMEM;
8023
David S. Miller9360ffd2012-03-29 04:41:26 -04008024 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
8025 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01008026
8027 infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
8028 if (!infoattr)
8029 goto nla_put_failure;
8030
Johannes Berg11f78ac2014-11-14 16:43:50 +01008031 if (survey->channel &&
8032 nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
David S. Miller9360ffd2012-03-29 04:41:26 -04008033 survey->channel->center_freq))
8034 goto nla_put_failure;
8035
8036 if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
8037 nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
8038 goto nla_put_failure;
8039 if ((survey->filled & SURVEY_INFO_IN_USE) &&
8040 nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
8041 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01008042 if ((survey->filled & SURVEY_INFO_TIME) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008043 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME,
8044 survey->time, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04008045 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01008046 if ((survey->filled & SURVEY_INFO_TIME_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008047 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BUSY,
8048 survey->time_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04008049 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01008050 if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008051 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
8052 survey->time_ext_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04008053 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01008054 if ((survey->filled & SURVEY_INFO_TIME_RX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008055 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_RX,
8056 survey->time_rx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04008057 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01008058 if ((survey->filled & SURVEY_INFO_TIME_TX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008059 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_TX,
8060 survey->time_tx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04008061 goto nla_put_failure;
Johannes Berg052536a2014-11-14 16:44:11 +01008062 if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008063 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_SCAN,
8064 survey->time_scan, NL80211_SURVEY_INFO_PAD))
Johannes Berg052536a2014-11-14 16:44:11 +01008065 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01008066
8067 nla_nest_end(msg, infoattr);
8068
Johannes Berg053c0952015-01-16 22:09:00 +01008069 genlmsg_end(msg, hdr);
8070 return 0;
Holger Schurig61fa7132009-11-11 12:25:40 +01008071
8072 nla_put_failure:
8073 genlmsg_cancel(msg, hdr);
8074 return -EMSGSIZE;
8075}
8076
Johannes Berg11f78ac2014-11-14 16:43:50 +01008077static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
Holger Schurig61fa7132009-11-11 12:25:40 +01008078{
Johannes Bergc90c39d2016-10-24 14:40:01 +02008079 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
Holger Schurig61fa7132009-11-11 12:25:40 +01008080 struct survey_info survey;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08008081 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02008082 struct wireless_dev *wdev;
8083 int survey_idx = cb->args[2];
Holger Schurig61fa7132009-11-11 12:25:40 +01008084 int res;
Johannes Berg11f78ac2014-11-14 16:43:50 +01008085 bool radio_stats;
Holger Schurig61fa7132009-11-11 12:25:40 +01008086
Johannes Bergea90e0d2017-03-15 14:26:04 +01008087 rtnl_lock();
Zhao, Gang1b8ec872014-04-21 12:53:02 +08008088 res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02008089 if (res)
Johannes Bergea90e0d2017-03-15 14:26:04 +01008090 goto out_err;
Holger Schurig61fa7132009-11-11 12:25:40 +01008091
Johannes Berg11f78ac2014-11-14 16:43:50 +01008092 /* prepare_wdev_dump parsed the attributes */
Johannes Bergc90c39d2016-10-24 14:40:01 +02008093 radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
Johannes Berg11f78ac2014-11-14 16:43:50 +01008094
Johannes Berg97990a02013-04-19 01:02:55 +02008095 if (!wdev->netdev) {
8096 res = -EINVAL;
8097 goto out_err;
8098 }
8099
Zhao, Gang1b8ec872014-04-21 12:53:02 +08008100 if (!rdev->ops->dump_survey) {
Holger Schurig61fa7132009-11-11 12:25:40 +01008101 res = -EOPNOTSUPP;
8102 goto out_err;
8103 }
8104
8105 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08008106 res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
Holger Schurig61fa7132009-11-11 12:25:40 +01008107 if (res == -ENOENT)
8108 break;
8109 if (res)
8110 goto out_err;
8111
Johannes Berg11f78ac2014-11-14 16:43:50 +01008112 /* don't send disabled channels, but do send non-channel data */
8113 if (survey.channel &&
8114 survey.channel->flags & IEEE80211_CHAN_DISABLED) {
Luis R. Rodriguez180cdc72011-05-27 07:24:02 -07008115 survey_idx++;
8116 continue;
8117 }
8118
Holger Schurig61fa7132009-11-11 12:25:40 +01008119 if (nl80211_send_survey(skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00008120 NETLINK_CB(cb->skb).portid,
Holger Schurig61fa7132009-11-11 12:25:40 +01008121 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg11f78ac2014-11-14 16:43:50 +01008122 wdev->netdev, radio_stats, &survey) < 0)
Holger Schurig61fa7132009-11-11 12:25:40 +01008123 goto out;
8124 survey_idx++;
8125 }
8126
8127 out:
Johannes Berg97990a02013-04-19 01:02:55 +02008128 cb->args[2] = survey_idx;
Holger Schurig61fa7132009-11-11 12:25:40 +01008129 res = skb->len;
8130 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01008131 rtnl_unlock();
Holger Schurig61fa7132009-11-11 12:25:40 +01008132 return res;
8133}
8134
Samuel Ortizb23aa672009-07-01 21:26:54 +02008135static bool nl80211_valid_wpa_versions(u32 wpa_versions)
8136{
8137 return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
8138 NL80211_WPA_VERSION_2));
8139}
8140
Jouni Malinen636a5d32009-03-19 13:39:22 +02008141static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
8142{
Johannes Berg4c476992010-10-04 21:36:35 +02008143 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8144 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008145 struct ieee80211_channel *chan;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008146 const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
8147 int err, ssid_len, ie_len = 0, auth_data_len = 0;
Johannes Berg19957bb2009-07-02 17:20:43 +02008148 enum nl80211_auth_type auth_type;
Johannes Bergfffd0932009-07-08 14:22:54 +02008149 struct key_parse key;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008150 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008151
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008152 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8153 return -EINVAL;
8154
8155 if (!info->attrs[NL80211_ATTR_MAC])
8156 return -EINVAL;
8157
Jouni Malinen17780922009-03-27 20:52:47 +02008158 if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
8159 return -EINVAL;
8160
Johannes Berg19957bb2009-07-02 17:20:43 +02008161 if (!info->attrs[NL80211_ATTR_SSID])
8162 return -EINVAL;
8163
8164 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
8165 return -EINVAL;
8166
Johannes Bergfffd0932009-07-08 14:22:54 +02008167 err = nl80211_parse_key(info, &key);
8168 if (err)
8169 return err;
8170
8171 if (key.idx >= 0) {
Johannes Berge31b8212010-10-05 19:39:30 +02008172 if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
8173 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02008174 if (!key.p.key || !key.p.key_len)
8175 return -EINVAL;
8176 if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
8177 key.p.key_len != WLAN_KEY_LEN_WEP40) &&
8178 (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
8179 key.p.key_len != WLAN_KEY_LEN_WEP104))
8180 return -EINVAL;
Johannes Bergb6b55552016-09-13 16:25:58 +02008181 if (key.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +02008182 return -EINVAL;
8183 } else {
8184 key.p.key_len = 0;
8185 key.p.key = NULL;
8186 }
8187
Johannes Bergafea0b72010-08-10 09:46:42 +02008188 if (key.idx >= 0) {
8189 int i;
8190 bool ok = false;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07008191
Johannes Bergafea0b72010-08-10 09:46:42 +02008192 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
8193 if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
8194 ok = true;
8195 break;
8196 }
8197 }
Johannes Berg4c476992010-10-04 21:36:35 +02008198 if (!ok)
8199 return -EINVAL;
Johannes Bergafea0b72010-08-10 09:46:42 +02008200 }
8201
Johannes Berg4c476992010-10-04 21:36:35 +02008202 if (!rdev->ops->auth)
8203 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008204
Johannes Berg074ac8d2010-09-16 14:58:22 +02008205 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008206 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8207 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008208
Johannes Berg19957bb2009-07-02 17:20:43 +02008209 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen664834d2014-01-15 00:01:44 +02008210 chan = nl80211_get_valid_chan(&rdev->wiphy,
8211 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8212 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02008213 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008214
Johannes Berg19957bb2009-07-02 17:20:43 +02008215 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8216 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8217
8218 if (info->attrs[NL80211_ATTR_IE]) {
8219 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8220 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8221 }
8222
8223 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03008224 if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
Johannes Berg4c476992010-10-04 21:36:35 +02008225 return -EINVAL;
Johannes Berg19957bb2009-07-02 17:20:43 +02008226
Jouni Malinen63181062016-10-27 00:42:02 +03008227 if ((auth_type == NL80211_AUTHTYPE_SAE ||
8228 auth_type == NL80211_AUTHTYPE_FILS_SK ||
8229 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
8230 auth_type == NL80211_AUTHTYPE_FILS_PK) &&
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008231 !info->attrs[NL80211_ATTR_AUTH_DATA])
Jouni Malinene39e5b52012-09-30 19:29:39 +03008232 return -EINVAL;
8233
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008234 if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
Jouni Malinen63181062016-10-27 00:42:02 +03008235 if (auth_type != NL80211_AUTHTYPE_SAE &&
8236 auth_type != NL80211_AUTHTYPE_FILS_SK &&
8237 auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
8238 auth_type != NL80211_AUTHTYPE_FILS_PK)
Jouni Malinene39e5b52012-09-30 19:29:39 +03008239 return -EINVAL;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008240 auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
8241 auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03008242 /* need to include at least Auth Transaction and Status Code */
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008243 if (auth_data_len < 4)
Jouni Malinene39e5b52012-09-30 19:29:39 +03008244 return -EINVAL;
8245 }
8246
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008247 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8248
Johannes Berg95de8172012-01-20 13:55:25 +01008249 /*
8250 * Since we no longer track auth state, ignore
8251 * requests to only change local state.
8252 */
8253 if (local_state_change)
8254 return 0;
8255
Johannes Berg91bf9b22013-05-15 17:44:01 +02008256 wdev_lock(dev->ieee80211_ptr);
8257 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
8258 ssid, ssid_len, ie, ie_len,
8259 key.p.key, key.p.key_len, key.idx,
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008260 auth_data, auth_data_len);
Johannes Berg91bf9b22013-05-15 17:44:01 +02008261 wdev_unlock(dev->ieee80211_ptr);
8262 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008263}
8264
Denis Kenzior64bf3d42018-03-26 12:52:43 -05008265static int validate_pae_over_nl80211(struct cfg80211_registered_device *rdev,
8266 struct genl_info *info)
8267{
8268 if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8269 GENL_SET_ERR_MSG(info, "SOCKET_OWNER not set");
8270 return -EINVAL;
8271 }
8272
8273 if (!rdev->ops->tx_control_port ||
8274 !wiphy_ext_feature_isset(&rdev->wiphy,
8275 NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
8276 return -EOPNOTSUPP;
8277
8278 return 0;
8279}
8280
Johannes Bergc0692b82010-08-27 14:26:53 +03008281static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
8282 struct genl_info *info,
Johannes Berg3dc27d22009-07-02 21:36:37 +02008283 struct cfg80211_crypto_settings *settings,
8284 int cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02008285{
Johannes Bergc0b2bbd2009-07-25 16:54:36 +02008286 memset(settings, 0, sizeof(*settings));
8287
Samuel Ortizb23aa672009-07-01 21:26:54 +02008288 settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
8289
Johannes Bergc0692b82010-08-27 14:26:53 +03008290 if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
8291 u16 proto;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07008292
Johannes Bergc0692b82010-08-27 14:26:53 +03008293 proto = nla_get_u16(
8294 info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
8295 settings->control_port_ethertype = cpu_to_be16(proto);
8296 if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
8297 proto != ETH_P_PAE)
8298 return -EINVAL;
8299 if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
8300 settings->control_port_no_encrypt = true;
8301 } else
8302 settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
8303
Denis Kenzior64bf3d42018-03-26 12:52:43 -05008304 if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
8305 int r = validate_pae_over_nl80211(rdev, info);
8306
8307 if (r < 0)
8308 return r;
8309
8310 settings->control_port_over_nl80211 = true;
8311 }
8312
Samuel Ortizb23aa672009-07-01 21:26:54 +02008313 if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
8314 void *data;
8315 int len, i;
8316
8317 data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
8318 len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
8319 settings->n_ciphers_pairwise = len / sizeof(u32);
8320
8321 if (len % sizeof(u32))
8322 return -EINVAL;
8323
Johannes Berg3dc27d22009-07-02 21:36:37 +02008324 if (settings->n_ciphers_pairwise > cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02008325 return -EINVAL;
8326
8327 memcpy(settings->ciphers_pairwise, data, len);
8328
8329 for (i = 0; i < settings->n_ciphers_pairwise; i++)
Jouni Malinen38ba3c52011-09-21 18:14:56 +03008330 if (!cfg80211_supported_cipher_suite(
8331 &rdev->wiphy,
Samuel Ortizb23aa672009-07-01 21:26:54 +02008332 settings->ciphers_pairwise[i]))
8333 return -EINVAL;
8334 }
8335
8336 if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
8337 settings->cipher_group =
8338 nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
Jouni Malinen38ba3c52011-09-21 18:14:56 +03008339 if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
8340 settings->cipher_group))
Samuel Ortizb23aa672009-07-01 21:26:54 +02008341 return -EINVAL;
8342 }
8343
8344 if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
8345 settings->wpa_versions =
8346 nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
8347 if (!nl80211_valid_wpa_versions(settings->wpa_versions))
8348 return -EINVAL;
8349 }
8350
8351 if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
8352 void *data;
Jouni Malinen6d302402011-09-21 18:11:33 +03008353 int len;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008354
8355 data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
8356 len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
8357 settings->n_akm_suites = len / sizeof(u32);
8358
8359 if (len % sizeof(u32))
8360 return -EINVAL;
8361
Jouni Malinen1b9ca022011-09-21 16:13:07 +03008362 if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
8363 return -EINVAL;
8364
Samuel Ortizb23aa672009-07-01 21:26:54 +02008365 memcpy(settings->akm_suites, data, len);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008366 }
8367
Eliad Peller91b5ab62017-06-09 13:08:42 +01008368 if (info->attrs[NL80211_ATTR_PMK]) {
8369 if (nla_len(info->attrs[NL80211_ATTR_PMK]) != WLAN_PMK_LEN)
8370 return -EINVAL;
8371 if (!wiphy_ext_feature_isset(&rdev->wiphy,
8372 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK))
8373 return -EINVAL;
8374 settings->psk = nla_data(info->attrs[NL80211_ATTR_PMK]);
8375 }
8376
Samuel Ortizb23aa672009-07-01 21:26:54 +02008377 return 0;
8378}
8379
Jouni Malinen636a5d32009-03-19 13:39:22 +02008380static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
8381{
Johannes Berg4c476992010-10-04 21:36:35 +02008382 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8383 struct net_device *dev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02008384 struct ieee80211_channel *chan;
Johannes Bergf62fab72013-02-21 20:09:09 +01008385 struct cfg80211_assoc_request req = {};
8386 const u8 *bssid, *ssid;
8387 int err, ssid_len = 0;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008388
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008389 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8390 return -EINVAL;
8391
8392 if (!info->attrs[NL80211_ATTR_MAC] ||
Johannes Berg19957bb2009-07-02 17:20:43 +02008393 !info->attrs[NL80211_ATTR_SSID] ||
8394 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008395 return -EINVAL;
8396
Johannes Berg4c476992010-10-04 21:36:35 +02008397 if (!rdev->ops->assoc)
8398 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008399
Johannes Berg074ac8d2010-09-16 14:58:22 +02008400 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008401 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8402 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008403
Johannes Berg19957bb2009-07-02 17:20:43 +02008404 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008405
Jouni Malinen664834d2014-01-15 00:01:44 +02008406 chan = nl80211_get_valid_chan(&rdev->wiphy,
8407 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8408 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02008409 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008410
Johannes Berg19957bb2009-07-02 17:20:43 +02008411 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8412 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008413
8414 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008415 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8416 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008417 }
8418
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008419 if (info->attrs[NL80211_ATTR_USE_MFP]) {
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008420 enum nl80211_mfp mfp =
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008421 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008422 if (mfp == NL80211_MFP_REQUIRED)
Johannes Bergf62fab72013-02-21 20:09:09 +01008423 req.use_mfp = true;
Johannes Berg4c476992010-10-04 21:36:35 +02008424 else if (mfp != NL80211_MFP_NO)
8425 return -EINVAL;
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008426 }
8427
Johannes Berg3e5d7642009-07-07 14:37:26 +02008428 if (info->attrs[NL80211_ATTR_PREV_BSSID])
Johannes Bergf62fab72013-02-21 20:09:09 +01008429 req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
Johannes Berg3e5d7642009-07-07 14:37:26 +02008430
Ben Greear7e7c8922011-11-18 11:31:59 -08008431 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008432 req.flags |= ASSOC_REQ_DISABLE_HT;
Ben Greear7e7c8922011-11-18 11:31:59 -08008433
8434 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008435 memcpy(&req.ht_capa_mask,
8436 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8437 sizeof(req.ht_capa_mask));
Ben Greear7e7c8922011-11-18 11:31:59 -08008438
8439 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008440 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Ben Greear7e7c8922011-11-18 11:31:59 -08008441 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008442 memcpy(&req.ht_capa,
8443 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8444 sizeof(req.ht_capa));
Ben Greear7e7c8922011-11-18 11:31:59 -08008445 }
8446
Johannes Bergee2aca32013-02-21 17:36:01 +01008447 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008448 req.flags |= ASSOC_REQ_DISABLE_VHT;
Johannes Bergee2aca32013-02-21 17:36:01 +01008449
8450 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008451 memcpy(&req.vht_capa_mask,
8452 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
8453 sizeof(req.vht_capa_mask));
Johannes Bergee2aca32013-02-21 17:36:01 +01008454
8455 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008456 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergee2aca32013-02-21 17:36:01 +01008457 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008458 memcpy(&req.vht_capa,
8459 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
8460 sizeof(req.vht_capa));
Johannes Bergee2aca32013-02-21 17:36:01 +01008461 }
8462
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008463 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02008464 if (!((rdev->wiphy.features &
8465 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
8466 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
8467 !wiphy_ext_feature_isset(&rdev->wiphy,
8468 NL80211_EXT_FEATURE_RRM))
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008469 return -EINVAL;
8470 req.flags |= ASSOC_REQ_USE_RRM;
8471 }
8472
Jouni Malinen348bd452016-10-27 00:42:03 +03008473 if (info->attrs[NL80211_ATTR_FILS_KEK]) {
8474 req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
8475 req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
8476 if (!info->attrs[NL80211_ATTR_FILS_NONCES])
8477 return -EINVAL;
8478 req.fils_nonces =
8479 nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
8480 }
8481
Johannes Bergf62fab72013-02-21 20:09:09 +01008482 err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
Johannes Berg91bf9b22013-05-15 17:44:01 +02008483 if (!err) {
8484 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008485
Johannes Bergf62fab72013-02-21 20:09:09 +01008486 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
8487 ssid, ssid_len, &req);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008488
8489 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8490 dev->ieee80211_ptr->conn_owner_nlportid =
8491 info->snd_portid;
8492 memcpy(dev->ieee80211_ptr->disconnect_bssid,
8493 bssid, ETH_ALEN);
8494 }
8495
Johannes Berg91bf9b22013-05-15 17:44:01 +02008496 wdev_unlock(dev->ieee80211_ptr);
8497 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008498
Jouni Malinen636a5d32009-03-19 13:39:22 +02008499 return err;
8500}
8501
8502static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
8503{
Johannes Berg4c476992010-10-04 21:36:35 +02008504 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8505 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008506 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008507 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008508 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008509 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008510
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008511 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8512 return -EINVAL;
8513
8514 if (!info->attrs[NL80211_ATTR_MAC])
8515 return -EINVAL;
8516
8517 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8518 return -EINVAL;
8519
Johannes Berg4c476992010-10-04 21:36:35 +02008520 if (!rdev->ops->deauth)
8521 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008522
Johannes Berg074ac8d2010-09-16 14:58:22 +02008523 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008524 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8525 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008526
Johannes Berg19957bb2009-07-02 17:20:43 +02008527 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008528
Johannes Berg19957bb2009-07-02 17:20:43 +02008529 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8530 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008531 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008532 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008533 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008534
8535 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008536 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8537 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008538 }
8539
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008540 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8541
Johannes Berg91bf9b22013-05-15 17:44:01 +02008542 wdev_lock(dev->ieee80211_ptr);
8543 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
8544 local_state_change);
8545 wdev_unlock(dev->ieee80211_ptr);
8546 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008547}
8548
8549static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
8550{
Johannes Berg4c476992010-10-04 21:36:35 +02008551 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8552 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008553 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008554 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008555 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008556 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008557
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008558 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8559 return -EINVAL;
8560
8561 if (!info->attrs[NL80211_ATTR_MAC])
8562 return -EINVAL;
8563
8564 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8565 return -EINVAL;
8566
Johannes Berg4c476992010-10-04 21:36:35 +02008567 if (!rdev->ops->disassoc)
8568 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008569
Johannes Berg074ac8d2010-09-16 14:58:22 +02008570 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008571 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8572 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008573
Johannes Berg19957bb2009-07-02 17:20:43 +02008574 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008575
Johannes Berg19957bb2009-07-02 17:20:43 +02008576 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8577 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008578 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008579 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008580 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008581
8582 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008583 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8584 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008585 }
8586
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008587 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8588
Johannes Berg91bf9b22013-05-15 17:44:01 +02008589 wdev_lock(dev->ieee80211_ptr);
8590 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
8591 local_state_change);
8592 wdev_unlock(dev->ieee80211_ptr);
8593 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008594}
8595
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008596static bool
8597nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
Johannes Berg57fbcce2016-04-12 15:56:15 +02008598 int mcast_rate[NUM_NL80211_BANDS],
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008599 int rateval)
8600{
8601 struct wiphy *wiphy = &rdev->wiphy;
8602 bool found = false;
8603 int band, i;
8604
Johannes Berg57fbcce2016-04-12 15:56:15 +02008605 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008606 struct ieee80211_supported_band *sband;
8607
8608 sband = wiphy->bands[band];
8609 if (!sband)
8610 continue;
8611
8612 for (i = 0; i < sband->n_bitrates; i++) {
8613 if (sband->bitrates[i].bitrate == rateval) {
8614 mcast_rate[band] = i + 1;
8615 found = true;
8616 break;
8617 }
8618 }
8619 }
8620
8621 return found;
8622}
8623
Johannes Berg04a773a2009-04-19 21:24:32 +02008624static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
8625{
Johannes Berg4c476992010-10-04 21:36:35 +02008626 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8627 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008628 struct cfg80211_ibss_params ibss;
8629 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008630 struct cfg80211_cached_keys *connkeys = NULL;
Johannes Berg04a773a2009-04-19 21:24:32 +02008631 int err;
8632
Johannes Berg8e30bc52009-04-22 17:45:38 +02008633 memset(&ibss, 0, sizeof(ibss));
8634
Johannes Berg04a773a2009-04-19 21:24:32 +02008635 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8636 return -EINVAL;
8637
Johannes Berg683b6d32012-11-08 21:25:48 +01008638 if (!info->attrs[NL80211_ATTR_SSID] ||
Johannes Berg04a773a2009-04-19 21:24:32 +02008639 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8640 return -EINVAL;
8641
Johannes Berg8e30bc52009-04-22 17:45:38 +02008642 ibss.beacon_interval = 100;
8643
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308644 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
Johannes Berg8e30bc52009-04-22 17:45:38 +02008645 ibss.beacon_interval =
8646 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308647
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05308648 err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
8649 ibss.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308650 if (err)
8651 return err;
Johannes Berg8e30bc52009-04-22 17:45:38 +02008652
Johannes Berg4c476992010-10-04 21:36:35 +02008653 if (!rdev->ops->join_ibss)
8654 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008655
Johannes Berg4c476992010-10-04 21:36:35 +02008656 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8657 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008658
Johannes Berg79c97e92009-07-07 03:56:12 +02008659 wiphy = &rdev->wiphy;
Johannes Berg04a773a2009-04-19 21:24:32 +02008660
Johannes Berg39193492011-09-16 13:45:25 +02008661 if (info->attrs[NL80211_ATTR_MAC]) {
Johannes Berg04a773a2009-04-19 21:24:32 +02008662 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg39193492011-09-16 13:45:25 +02008663
8664 if (!is_valid_ether_addr(ibss.bssid))
8665 return -EINVAL;
8666 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008667 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8668 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8669
8670 if (info->attrs[NL80211_ATTR_IE]) {
8671 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8672 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8673 }
8674
Johannes Berg683b6d32012-11-08 21:25:48 +01008675 err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
8676 if (err)
8677 return err;
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008678
Ilan Peer174e0cd2014-02-23 09:13:01 +02008679 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
8680 NL80211_IFTYPE_ADHOC))
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008681 return -EINVAL;
8682
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008683 switch (ibss.chandef.width) {
Simon Wunderlichbf372642013-07-08 16:55:58 +02008684 case NL80211_CHAN_WIDTH_5:
8685 case NL80211_CHAN_WIDTH_10:
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008686 case NL80211_CHAN_WIDTH_20_NOHT:
8687 break;
8688 case NL80211_CHAN_WIDTH_20:
8689 case NL80211_CHAN_WIDTH_40:
Janusz.Dziedzic@tieto.comffc11992015-02-21 16:52:39 +01008690 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8691 return -EINVAL;
8692 break;
8693 case NL80211_CHAN_WIDTH_80:
8694 case NL80211_CHAN_WIDTH_80P80:
8695 case NL80211_CHAN_WIDTH_160:
8696 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8697 return -EINVAL;
8698 if (!wiphy_ext_feature_isset(&rdev->wiphy,
8699 NL80211_EXT_FEATURE_VHT_IBSS))
8700 return -EINVAL;
8701 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008702 default:
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008703 return -EINVAL;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008704 }
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008705
Johannes Berg04a773a2009-04-19 21:24:32 +02008706 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
Johannes Bergfffd0932009-07-08 14:22:54 +02008707 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
Johannes Berg04a773a2009-04-19 21:24:32 +02008708
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008709 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
8710 u8 *rates =
8711 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8712 int n_rates =
8713 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8714 struct ieee80211_supported_band *sband =
Johannes Berg683b6d32012-11-08 21:25:48 +01008715 wiphy->bands[ibss.chandef.chan->band];
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008716
Johannes Berg34850ab2011-07-18 18:08:35 +02008717 err = ieee80211_get_ratemask(sband, rates, n_rates,
8718 &ibss.basic_rates);
8719 if (err)
8720 return err;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008721 }
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008722
Simon Wunderlich803768f2013-06-28 10:39:58 +02008723 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8724 memcpy(&ibss.ht_capa_mask,
8725 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8726 sizeof(ibss.ht_capa_mask));
8727
8728 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
8729 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8730 return -EINVAL;
8731 memcpy(&ibss.ht_capa,
8732 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8733 sizeof(ibss.ht_capa));
8734 }
8735
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008736 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
8737 !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
8738 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
8739 return -EINVAL;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008740
Johannes Berg4c476992010-10-04 21:36:35 +02008741 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Sujith Manoharande7044e2012-10-18 10:19:28 +05308742 bool no_ht = false;
8743
Johannes Berg768075e2017-11-13 15:35:06 +01008744 connkeys = nl80211_parse_connkeys(rdev, info, &no_ht);
Johannes Berg4c476992010-10-04 21:36:35 +02008745 if (IS_ERR(connkeys))
8746 return PTR_ERR(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308747
Johannes Berg3d9d1d62012-11-08 23:14:50 +01008748 if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
8749 no_ht) {
Ola Olsson5e950a72016-02-11 01:00:22 +01008750 kzfree(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308751 return -EINVAL;
8752 }
Johannes Berg4c476992010-10-04 21:36:35 +02008753 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008754
Antonio Quartulli267335d2012-01-31 20:25:47 +01008755 ibss.control_port =
8756 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
8757
Denis Kenziorc3bfe1f2018-03-26 12:52:48 -05008758 if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
8759 int r = validate_pae_over_nl80211(rdev, info);
8760
8761 if (r < 0)
8762 return r;
8763
8764 ibss.control_port_over_nl80211 = true;
8765 }
8766
Simon Wunderlich5336fa82013-10-07 18:41:05 +02008767 ibss.userspace_handles_dfs =
8768 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
8769
Denis Kenziorf8d16d32018-03-26 12:52:45 -05008770 wdev_lock(dev->ieee80211_ptr);
8771 err = __cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02008772 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03008773 kzfree(connkeys);
Denis Kenziorf8d16d32018-03-26 12:52:45 -05008774 else if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
8775 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
8776 wdev_unlock(dev->ieee80211_ptr);
8777
Johannes Berg04a773a2009-04-19 21:24:32 +02008778 return err;
8779}
8780
8781static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
8782{
Johannes Berg4c476992010-10-04 21:36:35 +02008783 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8784 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008785
Johannes Berg4c476992010-10-04 21:36:35 +02008786 if (!rdev->ops->leave_ibss)
8787 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008788
Johannes Berg4c476992010-10-04 21:36:35 +02008789 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8790 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008791
Johannes Berg4c476992010-10-04 21:36:35 +02008792 return cfg80211_leave_ibss(rdev, dev, false);
Johannes Berg04a773a2009-04-19 21:24:32 +02008793}
8794
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008795static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
8796{
8797 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8798 struct net_device *dev = info->user_ptr[1];
Johannes Berg57fbcce2016-04-12 15:56:15 +02008799 int mcast_rate[NUM_NL80211_BANDS];
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008800 u32 nla_rate;
8801 int err;
8802
8803 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
Bertold Van den Bergh876dc932015-08-05 16:02:21 +02008804 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
8805 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008806 return -EOPNOTSUPP;
8807
8808 if (!rdev->ops->set_mcast_rate)
8809 return -EOPNOTSUPP;
8810
8811 memset(mcast_rate, 0, sizeof(mcast_rate));
8812
8813 if (!info->attrs[NL80211_ATTR_MCAST_RATE])
8814 return -EINVAL;
8815
8816 nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
8817 if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
8818 return -EINVAL;
8819
Ilan Peera1056b1b2015-10-22 22:27:46 +03008820 err = rdev_set_mcast_rate(rdev, dev, mcast_rate);
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008821
8822 return err;
8823}
8824
Johannes Bergad7e7182013-11-13 13:37:47 +01008825static struct sk_buff *
8826__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008827 struct wireless_dev *wdev, int approxlen,
8828 u32 portid, u32 seq, enum nl80211_commands cmd,
Johannes Berg567ffc32013-12-18 14:43:31 +01008829 enum nl80211_attrs attr,
8830 const struct nl80211_vendor_cmd_info *info,
8831 gfp_t gfp)
Johannes Bergad7e7182013-11-13 13:37:47 +01008832{
8833 struct sk_buff *skb;
8834 void *hdr;
8835 struct nlattr *data;
8836
8837 skb = nlmsg_new(approxlen + 100, gfp);
8838 if (!skb)
8839 return NULL;
8840
8841 hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
8842 if (!hdr) {
8843 kfree_skb(skb);
8844 return NULL;
8845 }
8846
8847 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
8848 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01008849
8850 if (info) {
8851 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
8852 info->vendor_id))
8853 goto nla_put_failure;
8854 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
8855 info->subcmd))
8856 goto nla_put_failure;
8857 }
8858
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008859 if (wdev) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008860 if (nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
8861 wdev_id(wdev), NL80211_ATTR_PAD))
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008862 goto nla_put_failure;
8863 if (wdev->netdev &&
8864 nla_put_u32(skb, NL80211_ATTR_IFINDEX,
8865 wdev->netdev->ifindex))
8866 goto nla_put_failure;
8867 }
8868
Johannes Bergad7e7182013-11-13 13:37:47 +01008869 data = nla_nest_start(skb, attr);
Johannes Berg76e1fb42016-09-14 09:55:57 +02008870 if (!data)
8871 goto nla_put_failure;
Johannes Bergad7e7182013-11-13 13:37:47 +01008872
8873 ((void **)skb->cb)[0] = rdev;
8874 ((void **)skb->cb)[1] = hdr;
8875 ((void **)skb->cb)[2] = data;
8876
8877 return skb;
8878
8879 nla_put_failure:
8880 kfree_skb(skb);
8881 return NULL;
8882}
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008883
Johannes Berge03ad6e2014-01-01 17:22:30 +01008884struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008885 struct wireless_dev *wdev,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008886 enum nl80211_commands cmd,
8887 enum nl80211_attrs attr,
8888 int vendor_event_idx,
8889 int approxlen, gfp_t gfp)
8890{
Zhao, Gangf26cbf42014-04-21 12:53:03 +08008891 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berge03ad6e2014-01-01 17:22:30 +01008892 const struct nl80211_vendor_cmd_info *info;
8893
8894 switch (cmd) {
8895 case NL80211_CMD_TESTMODE:
8896 if (WARN_ON(vendor_event_idx != -1))
8897 return NULL;
8898 info = NULL;
8899 break;
8900 case NL80211_CMD_VENDOR:
8901 if (WARN_ON(vendor_event_idx < 0 ||
8902 vendor_event_idx >= wiphy->n_vendor_events))
8903 return NULL;
8904 info = &wiphy->vendor_events[vendor_event_idx];
8905 break;
8906 default:
8907 WARN_ON(1);
8908 return NULL;
8909 }
8910
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008911 return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008912 cmd, attr, info, gfp);
8913}
8914EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
8915
8916void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
8917{
8918 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
8919 void *hdr = ((void **)skb->cb)[1];
8920 struct nlattr *data = ((void **)skb->cb)[2];
8921 enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
8922
Johannes Bergbd8c78e2014-07-30 14:55:26 +02008923 /* clear CB data for netlink core to own from now on */
8924 memset(skb->cb, 0, sizeof(skb->cb));
8925
Johannes Berge03ad6e2014-01-01 17:22:30 +01008926 nla_nest_end(skb, data);
8927 genlmsg_end(skb, hdr);
8928
8929 if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
8930 mcgrp = NL80211_MCGRP_VENDOR;
8931
8932 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
8933 mcgrp, gfp);
8934}
8935EXPORT_SYMBOL(__cfg80211_send_event_skb);
8936
Johannes Bergaff89a92009-07-01 21:26:51 +02008937#ifdef CONFIG_NL80211_TESTMODE
Johannes Bergaff89a92009-07-01 21:26:51 +02008938static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
8939{
Johannes Berg4c476992010-10-04 21:36:35 +02008940 struct cfg80211_registered_device *rdev = info->user_ptr[0];
David Spinadelfc73f112013-07-31 18:04:15 +03008941 struct wireless_dev *wdev =
8942 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
Johannes Bergaff89a92009-07-01 21:26:51 +02008943 int err;
8944
David Spinadelfc73f112013-07-31 18:04:15 +03008945 if (!rdev->ops->testmode_cmd)
8946 return -EOPNOTSUPP;
8947
8948 if (IS_ERR(wdev)) {
8949 err = PTR_ERR(wdev);
8950 if (err != -EINVAL)
8951 return err;
8952 wdev = NULL;
8953 } else if (wdev->wiphy != &rdev->wiphy) {
8954 return -EINVAL;
8955 }
8956
Johannes Bergaff89a92009-07-01 21:26:51 +02008957 if (!info->attrs[NL80211_ATTR_TESTDATA])
8958 return -EINVAL;
8959
Johannes Bergad7e7182013-11-13 13:37:47 +01008960 rdev->cur_cmd_info = info;
David Spinadelfc73f112013-07-31 18:04:15 +03008961 err = rdev_testmode_cmd(rdev, wdev,
Johannes Bergaff89a92009-07-01 21:26:51 +02008962 nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
8963 nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
Johannes Bergad7e7182013-11-13 13:37:47 +01008964 rdev->cur_cmd_info = NULL;
Johannes Bergaff89a92009-07-01 21:26:51 +02008965
Johannes Bergaff89a92009-07-01 21:26:51 +02008966 return err;
8967}
8968
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008969static int nl80211_testmode_dump(struct sk_buff *skb,
8970 struct netlink_callback *cb)
8971{
Johannes Berg00918d32011-12-13 17:22:05 +01008972 struct cfg80211_registered_device *rdev;
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008973 int err;
8974 long phy_idx;
8975 void *data = NULL;
8976 int data_len = 0;
8977
Johannes Berg5fe231e2013-05-08 21:45:15 +02008978 rtnl_lock();
8979
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008980 if (cb->args[0]) {
8981 /*
8982 * 0 is a valid index, but not valid for args[0],
8983 * so we need to offset by 1.
8984 */
8985 phy_idx = cb->args[0] - 1;
Luca Coelhoa4956dc2017-02-07 22:13:56 +02008986
8987 rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
8988 if (!rdev) {
8989 err = -ENOENT;
8990 goto out_err;
8991 }
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008992 } else {
Johannes Bergc90c39d2016-10-24 14:40:01 +02008993 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
8994
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008995 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergfceb6432017-04-12 14:34:07 +02008996 attrbuf, nl80211_fam.maxattr,
8997 nl80211_policy, NULL);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008998 if (err)
Johannes Berg5fe231e2013-05-08 21:45:15 +02008999 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01009000
Johannes Bergc90c39d2016-10-24 14:40:01 +02009001 rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg2bd7e352012-06-15 14:23:16 +02009002 if (IS_ERR(rdev)) {
Johannes Berg5fe231e2013-05-08 21:45:15 +02009003 err = PTR_ERR(rdev);
9004 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01009005 }
Johannes Berg2bd7e352012-06-15 14:23:16 +02009006 phy_idx = rdev->wiphy_idx;
Johannes Berg2bd7e352012-06-15 14:23:16 +02009007
Johannes Bergc90c39d2016-10-24 14:40:01 +02009008 if (attrbuf[NL80211_ATTR_TESTDATA])
9009 cb->args[1] = (long)attrbuf[NL80211_ATTR_TESTDATA];
Wey-Yi Guy71063f02011-05-20 09:05:54 -07009010 }
9011
9012 if (cb->args[1]) {
9013 data = nla_data((void *)cb->args[1]);
9014 data_len = nla_len((void *)cb->args[1]);
9015 }
9016
Johannes Berg00918d32011-12-13 17:22:05 +01009017 if (!rdev->ops->testmode_dump) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07009018 err = -EOPNOTSUPP;
9019 goto out_err;
9020 }
9021
9022 while (1) {
Eric W. Biederman15e47302012-09-07 20:12:54 +00009023 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
Wey-Yi Guy71063f02011-05-20 09:05:54 -07009024 cb->nlh->nlmsg_seq, NLM_F_MULTI,
9025 NL80211_CMD_TESTMODE);
9026 struct nlattr *tmdata;
9027
Dan Carpentercb35fba2013-08-14 14:50:01 +03009028 if (!hdr)
9029 break;
9030
David S. Miller9360ffd2012-03-29 04:41:26 -04009031 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07009032 genlmsg_cancel(skb, hdr);
9033 break;
9034 }
9035
9036 tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
9037 if (!tmdata) {
9038 genlmsg_cancel(skb, hdr);
9039 break;
9040 }
Hila Gonene35e4d22012-06-27 17:19:42 +03009041 err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07009042 nla_nest_end(skb, tmdata);
9043
9044 if (err == -ENOBUFS || err == -ENOENT) {
9045 genlmsg_cancel(skb, hdr);
9046 break;
9047 } else if (err) {
9048 genlmsg_cancel(skb, hdr);
9049 goto out_err;
9050 }
9051
9052 genlmsg_end(skb, hdr);
9053 }
9054
9055 err = skb->len;
9056 /* see above */
9057 cb->args[0] = phy_idx + 1;
9058 out_err:
Johannes Berg5fe231e2013-05-08 21:45:15 +02009059 rtnl_unlock();
Wey-Yi Guy71063f02011-05-20 09:05:54 -07009060 return err;
9061}
Johannes Bergaff89a92009-07-01 21:26:51 +02009062#endif
9063
Samuel Ortizb23aa672009-07-01 21:26:54 +02009064static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
9065{
Johannes Berg4c476992010-10-04 21:36:35 +02009066 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9067 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02009068 struct cfg80211_connect_params connect;
9069 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02009070 struct cfg80211_cached_keys *connkeys = NULL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009071 int err;
9072
9073 memset(&connect, 0, sizeof(connect));
9074
9075 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
9076 return -EINVAL;
9077
9078 if (!info->attrs[NL80211_ATTR_SSID] ||
9079 !nla_len(info->attrs[NL80211_ATTR_SSID]))
9080 return -EINVAL;
9081
9082 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
9083 connect.auth_type =
9084 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03009085 if (!nl80211_valid_auth_type(rdev, connect.auth_type,
9086 NL80211_CMD_CONNECT))
Samuel Ortizb23aa672009-07-01 21:26:54 +02009087 return -EINVAL;
9088 } else
9089 connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
9090
9091 connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
9092
Avraham Stern3a00df52017-06-09 13:08:43 +01009093 if (info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS] &&
9094 !wiphy_ext_feature_isset(&rdev->wiphy,
9095 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
9096 return -EINVAL;
9097 connect.want_1x = info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS];
9098
Johannes Bergc0692b82010-08-27 14:26:53 +03009099 err = nl80211_crypto_settings(rdev, info, &connect.crypto,
Johannes Berg3dc27d22009-07-02 21:36:37 +02009100 NL80211_MAX_NR_CIPHER_SUITES);
Samuel Ortizb23aa672009-07-01 21:26:54 +02009101 if (err)
9102 return err;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009103
Johannes Berg074ac8d2010-09-16 14:58:22 +02009104 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009105 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9106 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009107
Johannes Berg79c97e92009-07-07 03:56:12 +02009108 wiphy = &rdev->wiphy;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009109
Bala Shanmugam4486ea92012-03-07 17:27:12 +05309110 connect.bg_scan_period = -1;
9111 if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
9112 (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
9113 connect.bg_scan_period =
9114 nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
9115 }
9116
Samuel Ortizb23aa672009-07-01 21:26:54 +02009117 if (info->attrs[NL80211_ATTR_MAC])
9118 connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen1df4a512014-01-15 00:00:47 +02009119 else if (info->attrs[NL80211_ATTR_MAC_HINT])
9120 connect.bssid_hint =
9121 nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
Samuel Ortizb23aa672009-07-01 21:26:54 +02009122 connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9123 connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9124
9125 if (info->attrs[NL80211_ATTR_IE]) {
9126 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9127 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9128 }
9129
Jouni Malinencee00a92013-01-15 17:15:57 +02009130 if (info->attrs[NL80211_ATTR_USE_MFP]) {
9131 connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Emmanuel Grumbach65026002017-08-18 15:31:41 +03009132 if (connect.mfp == NL80211_MFP_OPTIONAL &&
9133 !wiphy_ext_feature_isset(&rdev->wiphy,
9134 NL80211_EXT_FEATURE_MFP_OPTIONAL))
9135 return -EOPNOTSUPP;
9136
Jouni Malinencee00a92013-01-15 17:15:57 +02009137 if (connect.mfp != NL80211_MFP_REQUIRED &&
Emmanuel Grumbach65026002017-08-18 15:31:41 +03009138 connect.mfp != NL80211_MFP_NO &&
9139 connect.mfp != NL80211_MFP_OPTIONAL)
Jouni Malinencee00a92013-01-15 17:15:57 +02009140 return -EINVAL;
9141 } else {
9142 connect.mfp = NL80211_MFP_NO;
9143 }
9144
Jouni Malinenba6fbac2016-03-29 13:53:27 +03009145 if (info->attrs[NL80211_ATTR_PREV_BSSID])
9146 connect.prev_bssid =
9147 nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
9148
Samuel Ortizb23aa672009-07-01 21:26:54 +02009149 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02009150 connect.channel = nl80211_get_valid_chan(
9151 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
9152 if (!connect.channel)
Johannes Berg4c476992010-10-04 21:36:35 +02009153 return -EINVAL;
Jouni Malinen1df4a512014-01-15 00:00:47 +02009154 } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02009155 connect.channel_hint = nl80211_get_valid_chan(
9156 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
9157 if (!connect.channel_hint)
Jouni Malinen1df4a512014-01-15 00:00:47 +02009158 return -EINVAL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009159 }
9160
Johannes Bergfffd0932009-07-08 14:22:54 +02009161 if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Johannes Berg768075e2017-11-13 15:35:06 +01009162 connkeys = nl80211_parse_connkeys(rdev, info, NULL);
Johannes Berg4c476992010-10-04 21:36:35 +02009163 if (IS_ERR(connkeys))
9164 return PTR_ERR(connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02009165 }
9166
Ben Greear7e7c8922011-11-18 11:31:59 -08009167 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
9168 connect.flags |= ASSOC_REQ_DISABLE_HT;
9169
9170 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
9171 memcpy(&connect.ht_capa_mask,
9172 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
9173 sizeof(connect.ht_capa_mask));
9174
9175 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Wei Yongjunb4e4f472012-09-02 21:41:04 +08009176 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03009177 kzfree(connkeys);
Ben Greear7e7c8922011-11-18 11:31:59 -08009178 return -EINVAL;
Wei Yongjunb4e4f472012-09-02 21:41:04 +08009179 }
Ben Greear7e7c8922011-11-18 11:31:59 -08009180 memcpy(&connect.ht_capa,
9181 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
9182 sizeof(connect.ht_capa));
9183 }
9184
Johannes Bergee2aca32013-02-21 17:36:01 +01009185 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
9186 connect.flags |= ASSOC_REQ_DISABLE_VHT;
9187
9188 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
9189 memcpy(&connect.vht_capa_mask,
9190 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
9191 sizeof(connect.vht_capa_mask));
9192
9193 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
9194 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03009195 kzfree(connkeys);
Johannes Bergee2aca32013-02-21 17:36:01 +01009196 return -EINVAL;
9197 }
9198 memcpy(&connect.vht_capa,
9199 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
9200 sizeof(connect.vht_capa));
9201 }
9202
Assaf Kraussbab5ab72014-09-03 15:25:01 +03009203 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02009204 if (!((rdev->wiphy.features &
9205 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
9206 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
9207 !wiphy_ext_feature_isset(&rdev->wiphy,
9208 NL80211_EXT_FEATURE_RRM)) {
Ola Olsson707554b2015-12-11 21:04:52 +01009209 kzfree(connkeys);
Assaf Kraussbab5ab72014-09-03 15:25:01 +03009210 return -EINVAL;
Ola Olsson707554b2015-12-11 21:04:52 +01009211 }
Assaf Kraussbab5ab72014-09-03 15:25:01 +03009212 connect.flags |= ASSOC_REQ_USE_RRM;
9213 }
9214
Lior David34d50512016-01-28 10:58:25 +02009215 connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
Johannes Berg57fbcce2016-04-12 15:56:15 +02009216 if (connect.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
Lior David34d50512016-01-28 10:58:25 +02009217 kzfree(connkeys);
9218 return -EOPNOTSUPP;
9219 }
9220
Arend van Spriel38de03d2016-03-02 20:37:18 +01009221 if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
9222 /* bss selection makes no sense if bssid is set */
9223 if (connect.bssid) {
9224 kzfree(connkeys);
9225 return -EINVAL;
9226 }
9227
9228 err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
9229 wiphy, &connect.bss_select);
9230 if (err) {
9231 kzfree(connkeys);
9232 return err;
9233 }
9234 }
9235
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03009236 if (wiphy_ext_feature_isset(&rdev->wiphy,
9237 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
9238 info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
9239 info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
9240 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
9241 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
9242 connect.fils_erp_username =
9243 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
9244 connect.fils_erp_username_len =
9245 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
9246 connect.fils_erp_realm =
9247 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
9248 connect.fils_erp_realm_len =
9249 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
9250 connect.fils_erp_next_seq_num =
9251 nla_get_u16(
9252 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
9253 connect.fils_erp_rrk =
9254 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
9255 connect.fils_erp_rrk_len =
9256 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
9257 } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
9258 info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
9259 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
9260 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
9261 kzfree(connkeys);
9262 return -EINVAL;
9263 }
9264
Srinivas Dasari40cbfa92018-01-25 17:13:38 +02009265 if (nla_get_flag(info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])) {
9266 if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
9267 GENL_SET_ERR_MSG(info,
9268 "external auth requires connection ownership");
9269 return -EINVAL;
9270 }
9271 connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT;
9272 }
9273
Johannes Berg83739b02013-05-15 17:44:01 +02009274 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05009275
Jouni Malinen4ce2bd9c42016-03-29 13:53:28 +03009276 err = cfg80211_connect(rdev, dev, &connect, connkeys,
9277 connect.prev_bssid);
Johannes Bergfffd0932009-07-08 14:22:54 +02009278 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03009279 kzfree(connkeys);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05009280
9281 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
9282 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
9283 if (connect.bssid)
9284 memcpy(dev->ieee80211_ptr->disconnect_bssid,
9285 connect.bssid, ETH_ALEN);
9286 else
9287 memset(dev->ieee80211_ptr->disconnect_bssid,
9288 0, ETH_ALEN);
9289 }
9290
9291 wdev_unlock(dev->ieee80211_ptr);
9292
Samuel Ortizb23aa672009-07-01 21:26:54 +02009293 return err;
9294}
9295
vamsi krishna088e8df2016-10-27 16:51:11 +03009296static int nl80211_update_connect_params(struct sk_buff *skb,
9297 struct genl_info *info)
9298{
9299 struct cfg80211_connect_params connect = {};
9300 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9301 struct net_device *dev = info->user_ptr[1];
9302 struct wireless_dev *wdev = dev->ieee80211_ptr;
9303 u32 changed = 0;
9304 int ret;
9305
9306 if (!rdev->ops->update_connect_params)
9307 return -EOPNOTSUPP;
9308
9309 if (info->attrs[NL80211_ATTR_IE]) {
9310 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
9311 return -EINVAL;
9312 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9313 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9314 changed |= UPDATE_ASSOC_IES;
9315 }
9316
9317 wdev_lock(dev->ieee80211_ptr);
9318 if (!wdev->current_bss)
9319 ret = -ENOLINK;
9320 else
9321 ret = rdev_update_connect_params(rdev, dev, &connect, changed);
9322 wdev_unlock(dev->ieee80211_ptr);
9323
9324 return ret;
9325}
9326
Samuel Ortizb23aa672009-07-01 21:26:54 +02009327static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
9328{
Johannes Berg4c476992010-10-04 21:36:35 +02009329 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9330 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02009331 u16 reason;
Johannes Berg83739b02013-05-15 17:44:01 +02009332 int ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009333
9334 if (!info->attrs[NL80211_ATTR_REASON_CODE])
9335 reason = WLAN_REASON_DEAUTH_LEAVING;
9336 else
9337 reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
9338
9339 if (reason == 0)
9340 return -EINVAL;
9341
Johannes Berg074ac8d2010-09-16 14:58:22 +02009342 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009343 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9344 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009345
Johannes Berg83739b02013-05-15 17:44:01 +02009346 wdev_lock(dev->ieee80211_ptr);
9347 ret = cfg80211_disconnect(rdev, dev, reason, true);
9348 wdev_unlock(dev->ieee80211_ptr);
9349 return ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009350}
9351
Johannes Berg463d0182009-07-14 00:33:35 +02009352static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
9353{
Johannes Berg4c476992010-10-04 21:36:35 +02009354 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg463d0182009-07-14 00:33:35 +02009355 struct net *net;
9356 int err;
Johannes Berg463d0182009-07-14 00:33:35 +02009357
Vadim Kochan4b681c82015-01-12 16:34:05 +02009358 if (info->attrs[NL80211_ATTR_PID]) {
9359 u32 pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
9360
9361 net = get_net_ns_by_pid(pid);
9362 } else if (info->attrs[NL80211_ATTR_NETNS_FD]) {
9363 u32 fd = nla_get_u32(info->attrs[NL80211_ATTR_NETNS_FD]);
9364
9365 net = get_net_ns_by_fd(fd);
9366 } else {
Johannes Berg463d0182009-07-14 00:33:35 +02009367 return -EINVAL;
Vadim Kochan4b681c82015-01-12 16:34:05 +02009368 }
Johannes Berg463d0182009-07-14 00:33:35 +02009369
Johannes Berg4c476992010-10-04 21:36:35 +02009370 if (IS_ERR(net))
9371 return PTR_ERR(net);
Johannes Berg463d0182009-07-14 00:33:35 +02009372
9373 err = 0;
9374
9375 /* check if anything to do */
Johannes Berg4c476992010-10-04 21:36:35 +02009376 if (!net_eq(wiphy_net(&rdev->wiphy), net))
9377 err = cfg80211_switch_netns(rdev, net);
Johannes Berg463d0182009-07-14 00:33:35 +02009378
Johannes Berg463d0182009-07-14 00:33:35 +02009379 put_net(net);
Johannes Berg463d0182009-07-14 00:33:35 +02009380 return err;
9381}
9382
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009383static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
9384{
Johannes Berg4c476992010-10-04 21:36:35 +02009385 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009386 int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
9387 struct cfg80211_pmksa *pmksa) = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02009388 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009389 struct cfg80211_pmksa pmksa;
9390
9391 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
9392
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009393 if (!info->attrs[NL80211_ATTR_PMKID])
9394 return -EINVAL;
9395
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009396 pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03009397
9398 if (info->attrs[NL80211_ATTR_MAC]) {
9399 pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9400 } else if (info->attrs[NL80211_ATTR_SSID] &&
9401 info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
9402 (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
9403 info->attrs[NL80211_ATTR_PMK])) {
9404 pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9405 pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9406 pmksa.cache_id =
9407 nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
9408 } else {
9409 return -EINVAL;
9410 }
9411 if (info->attrs[NL80211_ATTR_PMK]) {
9412 pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
9413 pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
9414 }
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009415
Johannes Berg074ac8d2010-09-16 14:58:22 +02009416 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009417 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9418 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009419
9420 switch (info->genlhdr->cmd) {
9421 case NL80211_CMD_SET_PMKSA:
9422 rdev_ops = rdev->ops->set_pmksa;
9423 break;
9424 case NL80211_CMD_DEL_PMKSA:
9425 rdev_ops = rdev->ops->del_pmksa;
9426 break;
9427 default:
9428 WARN_ON(1);
9429 break;
9430 }
9431
Johannes Berg4c476992010-10-04 21:36:35 +02009432 if (!rdev_ops)
9433 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009434
Johannes Berg4c476992010-10-04 21:36:35 +02009435 return rdev_ops(&rdev->wiphy, dev, &pmksa);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009436}
9437
9438static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
9439{
Johannes Berg4c476992010-10-04 21:36:35 +02009440 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9441 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009442
Johannes Berg074ac8d2010-09-16 14:58:22 +02009443 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009444 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9445 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009446
Johannes Berg4c476992010-10-04 21:36:35 +02009447 if (!rdev->ops->flush_pmksa)
9448 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009449
Hila Gonene35e4d22012-06-27 17:19:42 +03009450 return rdev_flush_pmksa(rdev, dev);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009451}
9452
Arik Nemtsov109086c2011-09-28 14:12:50 +03009453static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
9454{
9455 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9456 struct net_device *dev = info->user_ptr[1];
9457 u8 action_code, dialog_token;
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309458 u32 peer_capability = 0;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009459 u16 status_code;
9460 u8 *peer;
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009461 bool initiator;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009462
9463 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9464 !rdev->ops->tdls_mgmt)
9465 return -EOPNOTSUPP;
9466
9467 if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
9468 !info->attrs[NL80211_ATTR_STATUS_CODE] ||
9469 !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
9470 !info->attrs[NL80211_ATTR_IE] ||
9471 !info->attrs[NL80211_ATTR_MAC])
9472 return -EINVAL;
9473
9474 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9475 action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
9476 status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
9477 dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009478 initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]);
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309479 if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
9480 peer_capability =
9481 nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009482
Hila Gonene35e4d22012-06-27 17:19:42 +03009483 return rdev_tdls_mgmt(rdev, dev, peer, action_code,
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309484 dialog_token, status_code, peer_capability,
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009485 initiator,
Hila Gonene35e4d22012-06-27 17:19:42 +03009486 nla_data(info->attrs[NL80211_ATTR_IE]),
9487 nla_len(info->attrs[NL80211_ATTR_IE]));
Arik Nemtsov109086c2011-09-28 14:12:50 +03009488}
9489
9490static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
9491{
9492 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9493 struct net_device *dev = info->user_ptr[1];
9494 enum nl80211_tdls_operation operation;
9495 u8 *peer;
9496
9497 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9498 !rdev->ops->tdls_oper)
9499 return -EOPNOTSUPP;
9500
9501 if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
9502 !info->attrs[NL80211_ATTR_MAC])
9503 return -EINVAL;
9504
9505 operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
9506 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9507
Hila Gonene35e4d22012-06-27 17:19:42 +03009508 return rdev_tdls_oper(rdev, dev, peer, operation);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009509}
9510
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009511static int nl80211_remain_on_channel(struct sk_buff *skb,
9512 struct genl_info *info)
9513{
Johannes Berg4c476992010-10-04 21:36:35 +02009514 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009515 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009516 struct cfg80211_chan_def chandef;
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05309517 const struct cfg80211_chan_def *compat_chandef;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009518 struct sk_buff *msg;
9519 void *hdr;
9520 u64 cookie;
Johannes Berg683b6d32012-11-08 21:25:48 +01009521 u32 duration;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009522 int err;
9523
9524 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
9525 !info->attrs[NL80211_ATTR_DURATION])
9526 return -EINVAL;
9527
9528 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
9529
Johannes Berg7c4ef712011-11-18 15:33:48 +01009530 if (!rdev->ops->remain_on_channel ||
9531 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
Johannes Berg4c476992010-10-04 21:36:35 +02009532 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009533
Johannes Bergebf348f2012-06-01 12:50:54 +02009534 /*
9535 * We should be on that channel for at least a minimum amount of
9536 * time (10ms) but no longer than the driver supports.
9537 */
9538 if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9539 duration > rdev->wiphy.max_remain_on_channel_duration)
9540 return -EINVAL;
9541
Johannes Berg683b6d32012-11-08 21:25:48 +01009542 err = nl80211_parse_chandef(rdev, info, &chandef);
9543 if (err)
9544 return err;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009545
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05309546 wdev_lock(wdev);
9547 if (!cfg80211_off_channel_oper_allowed(wdev) &&
9548 !cfg80211_chandef_identical(&wdev->chandef, &chandef)) {
9549 compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
9550 &chandef);
9551 if (compat_chandef != &chandef) {
9552 wdev_unlock(wdev);
9553 return -EBUSY;
9554 }
9555 }
9556 wdev_unlock(wdev);
9557
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009558 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009559 if (!msg)
9560 return -ENOMEM;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009561
Eric W. Biederman15e47302012-09-07 20:12:54 +00009562 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009563 NL80211_CMD_REMAIN_ON_CHANNEL);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009564 if (!hdr) {
9565 err = -ENOBUFS;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009566 goto free_msg;
9567 }
9568
Johannes Berg683b6d32012-11-08 21:25:48 +01009569 err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
9570 duration, &cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009571
9572 if (err)
9573 goto free_msg;
9574
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009575 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9576 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009577 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009578
9579 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009580
9581 return genlmsg_reply(msg, info);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009582
9583 nla_put_failure:
9584 err = -ENOBUFS;
9585 free_msg:
9586 nlmsg_free(msg);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009587 return err;
9588}
9589
9590static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
9591 struct genl_info *info)
9592{
Johannes Berg4c476992010-10-04 21:36:35 +02009593 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009594 struct wireless_dev *wdev = info->user_ptr[1];
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009595 u64 cookie;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009596
9597 if (!info->attrs[NL80211_ATTR_COOKIE])
9598 return -EINVAL;
9599
Johannes Berg4c476992010-10-04 21:36:35 +02009600 if (!rdev->ops->cancel_remain_on_channel)
9601 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009602
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009603 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9604
Hila Gonene35e4d22012-06-27 17:19:42 +03009605 return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009606}
9607
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009608static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
9609 struct genl_info *info)
9610{
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009611 struct cfg80211_bitrate_mask mask;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309612 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009613 struct net_device *dev = info->user_ptr[1];
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309614 int err;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009615
Johannes Berg4c476992010-10-04 21:36:35 +02009616 if (!rdev->ops->set_bitrate_mask)
9617 return -EOPNOTSUPP;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009618
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309619 err = nl80211_parse_tx_bitrate_mask(info, &mask);
9620 if (err)
9621 return err;
Janusz Dziedzic78693032013-12-03 09:50:44 +01009622
Hila Gonene35e4d22012-06-27 17:19:42 +03009623 return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009624}
9625
Johannes Berg2e161f72010-08-12 15:38:38 +02009626static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009627{
Johannes Berg4c476992010-10-04 21:36:35 +02009628 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009629 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2e161f72010-08-12 15:38:38 +02009630 u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
Jouni Malinen026331c2010-02-15 12:53:10 +02009631
9632 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
9633 return -EINVAL;
9634
Johannes Berg2e161f72010-08-12 15:38:38 +02009635 if (info->attrs[NL80211_ATTR_FRAME_TYPE])
9636 frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
Jouni Malinen026331c2010-02-15 12:53:10 +02009637
Johannes Berg71bbc992012-06-15 15:30:18 +02009638 switch (wdev->iftype) {
9639 case NL80211_IFTYPE_STATION:
9640 case NL80211_IFTYPE_ADHOC:
9641 case NL80211_IFTYPE_P2P_CLIENT:
9642 case NL80211_IFTYPE_AP:
9643 case NL80211_IFTYPE_AP_VLAN:
9644 case NL80211_IFTYPE_MESH_POINT:
9645 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009646 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009647 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009648 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009649 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009650 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009651 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009652
9653 /* not much point in registering if we can't reply */
Johannes Berg4c476992010-10-04 21:36:35 +02009654 if (!rdev->ops->mgmt_tx)
9655 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009656
Eric W. Biederman15e47302012-09-07 20:12:54 +00009657 return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
Jouni Malinen026331c2010-02-15 12:53:10 +02009658 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
9659 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
Jouni Malinen026331c2010-02-15 12:53:10 +02009660}
9661
Johannes Berg2e161f72010-08-12 15:38:38 +02009662static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009663{
Johannes Berg4c476992010-10-04 21:36:35 +02009664 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009665 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009666 struct cfg80211_chan_def chandef;
Jouni Malinen026331c2010-02-15 12:53:10 +02009667 int err;
Johannes Bergd64d3732011-11-10 09:44:46 +01009668 void *hdr = NULL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009669 u64 cookie;
Johannes Berge247bd902011-11-04 11:18:21 +01009670 struct sk_buff *msg = NULL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009671 struct cfg80211_mgmt_tx_params params = {
9672 .dont_wait_for_ack =
9673 info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
9674 };
Jouni Malinen026331c2010-02-15 12:53:10 +02009675
Johannes Berg683b6d32012-11-08 21:25:48 +01009676 if (!info->attrs[NL80211_ATTR_FRAME])
Jouni Malinen026331c2010-02-15 12:53:10 +02009677 return -EINVAL;
9678
Johannes Berg4c476992010-10-04 21:36:35 +02009679 if (!rdev->ops->mgmt_tx)
9680 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009681
Johannes Berg71bbc992012-06-15 15:30:18 +02009682 switch (wdev->iftype) {
Antonio Quartulliea141b752013-06-11 14:20:03 +02009683 case NL80211_IFTYPE_P2P_DEVICE:
9684 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
9685 return -EINVAL;
Johannes Berg71bbc992012-06-15 15:30:18 +02009686 case NL80211_IFTYPE_STATION:
9687 case NL80211_IFTYPE_ADHOC:
9688 case NL80211_IFTYPE_P2P_CLIENT:
9689 case NL80211_IFTYPE_AP:
9690 case NL80211_IFTYPE_AP_VLAN:
9691 case NL80211_IFTYPE_MESH_POINT:
9692 case NL80211_IFTYPE_P2P_GO:
9693 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009694 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009695 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009696 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009697 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009698
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009699 if (info->attrs[NL80211_ATTR_DURATION]) {
Johannes Berg7c4ef712011-11-18 15:33:48 +01009700 if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009701 return -EINVAL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009702 params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
Johannes Bergebf348f2012-06-01 12:50:54 +02009703
9704 /*
9705 * We should wait on the channel for at least a minimum amount
9706 * of time (10ms) but no longer than the driver supports.
9707 */
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009708 if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9709 params.wait > rdev->wiphy.max_remain_on_channel_duration)
Johannes Bergebf348f2012-06-01 12:50:54 +02009710 return -EINVAL;
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009711 }
9712
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009713 params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009714
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009715 if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Berg7c4ef712011-11-18 15:33:48 +01009716 return -EINVAL;
9717
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009718 params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05309719
Antonio Quartulliea141b752013-06-11 14:20:03 +02009720 /* get the channel if any has been specified, otherwise pass NULL to
9721 * the driver. The latter will use the current one
9722 */
9723 chandef.chan = NULL;
9724 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
9725 err = nl80211_parse_chandef(rdev, info, &chandef);
9726 if (err)
9727 return err;
9728 }
9729
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009730 if (!chandef.chan && params.offchan)
Antonio Quartulliea141b752013-06-11 14:20:03 +02009731 return -EINVAL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009732
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05309733 wdev_lock(wdev);
9734 if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) {
9735 wdev_unlock(wdev);
9736 return -EBUSY;
9737 }
9738 wdev_unlock(wdev);
9739
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +03009740 params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
9741 params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
9742
9743 if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
9744 int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9745 int i;
9746
9747 if (len % sizeof(u16))
9748 return -EINVAL;
9749
9750 params.n_csa_offsets = len / sizeof(u16);
9751 params.csa_offsets =
9752 nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9753
9754 /* check that all the offsets fit the frame */
9755 for (i = 0; i < params.n_csa_offsets; i++) {
9756 if (params.csa_offsets[i] >= params.len)
9757 return -EINVAL;
9758 }
9759 }
9760
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009761 if (!params.dont_wait_for_ack) {
Johannes Berge247bd902011-11-04 11:18:21 +01009762 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9763 if (!msg)
9764 return -ENOMEM;
Jouni Malinen026331c2010-02-15 12:53:10 +02009765
Eric W. Biederman15e47302012-09-07 20:12:54 +00009766 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berge247bd902011-11-04 11:18:21 +01009767 NL80211_CMD_FRAME);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009768 if (!hdr) {
9769 err = -ENOBUFS;
Johannes Berge247bd902011-11-04 11:18:21 +01009770 goto free_msg;
9771 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009772 }
Johannes Berge247bd902011-11-04 11:18:21 +01009773
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009774 params.chan = chandef.chan;
9775 err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
Jouni Malinen026331c2010-02-15 12:53:10 +02009776 if (err)
9777 goto free_msg;
9778
Johannes Berge247bd902011-11-04 11:18:21 +01009779 if (msg) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009780 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9781 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009782 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +02009783
Johannes Berge247bd902011-11-04 11:18:21 +01009784 genlmsg_end(msg, hdr);
9785 return genlmsg_reply(msg, info);
9786 }
9787
9788 return 0;
Jouni Malinen026331c2010-02-15 12:53:10 +02009789
9790 nla_put_failure:
9791 err = -ENOBUFS;
9792 free_msg:
9793 nlmsg_free(msg);
Jouni Malinen026331c2010-02-15 12:53:10 +02009794 return err;
9795}
9796
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009797static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
9798{
9799 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009800 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009801 u64 cookie;
9802
9803 if (!info->attrs[NL80211_ATTR_COOKIE])
9804 return -EINVAL;
9805
9806 if (!rdev->ops->mgmt_tx_cancel_wait)
9807 return -EOPNOTSUPP;
9808
Johannes Berg71bbc992012-06-15 15:30:18 +02009809 switch (wdev->iftype) {
9810 case NL80211_IFTYPE_STATION:
9811 case NL80211_IFTYPE_ADHOC:
9812 case NL80211_IFTYPE_P2P_CLIENT:
9813 case NL80211_IFTYPE_AP:
9814 case NL80211_IFTYPE_AP_VLAN:
9815 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009816 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009817 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009818 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009819 default:
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009820 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009821 }
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009822
9823 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9824
Hila Gonene35e4d22012-06-27 17:19:42 +03009825 return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009826}
9827
Kalle Valoffb9eb32010-02-17 17:58:10 +02009828static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
9829{
Johannes Berg4c476992010-10-04 21:36:35 +02009830 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009831 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009832 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009833 u8 ps_state;
9834 bool state;
9835 int err;
9836
Johannes Berg4c476992010-10-04 21:36:35 +02009837 if (!info->attrs[NL80211_ATTR_PS_STATE])
9838 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009839
9840 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
9841
Johannes Berg4c476992010-10-04 21:36:35 +02009842 if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
9843 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009844
9845 wdev = dev->ieee80211_ptr;
9846
Johannes Berg4c476992010-10-04 21:36:35 +02009847 if (!rdev->ops->set_power_mgmt)
9848 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009849
9850 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
9851
9852 if (state == wdev->ps)
Johannes Berg4c476992010-10-04 21:36:35 +02009853 return 0;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009854
Hila Gonene35e4d22012-06-27 17:19:42 +03009855 err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
Johannes Berg4c476992010-10-04 21:36:35 +02009856 if (!err)
9857 wdev->ps = state;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009858 return err;
9859}
9860
9861static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
9862{
Johannes Berg4c476992010-10-04 21:36:35 +02009863 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009864 enum nl80211_ps_state ps_state;
9865 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009866 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009867 struct sk_buff *msg;
9868 void *hdr;
9869 int err;
9870
Kalle Valoffb9eb32010-02-17 17:58:10 +02009871 wdev = dev->ieee80211_ptr;
9872
Johannes Berg4c476992010-10-04 21:36:35 +02009873 if (!rdev->ops->set_power_mgmt)
9874 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009875
9876 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009877 if (!msg)
9878 return -ENOMEM;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009879
Eric W. Biederman15e47302012-09-07 20:12:54 +00009880 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Kalle Valoffb9eb32010-02-17 17:58:10 +02009881 NL80211_CMD_GET_POWER_SAVE);
9882 if (!hdr) {
Johannes Berg4c476992010-10-04 21:36:35 +02009883 err = -ENOBUFS;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009884 goto free_msg;
9885 }
9886
9887 if (wdev->ps)
9888 ps_state = NL80211_PS_ENABLED;
9889 else
9890 ps_state = NL80211_PS_DISABLED;
9891
David S. Miller9360ffd2012-03-29 04:41:26 -04009892 if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
9893 goto nla_put_failure;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009894
9895 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009896 return genlmsg_reply(msg, info);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009897
Johannes Berg4c476992010-10-04 21:36:35 +02009898 nla_put_failure:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009899 err = -ENOBUFS;
Johannes Berg4c476992010-10-04 21:36:35 +02009900 free_msg:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009901 nlmsg_free(msg);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009902 return err;
9903}
9904
Johannes Berg94e860f2014-01-20 23:58:15 +01009905static const struct nla_policy
9906nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009907 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009908 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
9909 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
Thomas Pedersen84f10702012-07-12 16:17:33 -07009910 [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
9911 [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
9912 [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +01009913 [NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009914};
9915
Thomas Pedersen84f10702012-07-12 16:17:33 -07009916static int nl80211_set_cqm_txe(struct genl_info *info,
Johannes Bergd9d8b012012-11-26 12:51:52 +01009917 u32 rate, u32 pkts, u32 intvl)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009918{
9919 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Thomas Pedersen84f10702012-07-12 16:17:33 -07009920 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009921 struct wireless_dev *wdev = dev->ieee80211_ptr;
Thomas Pedersen84f10702012-07-12 16:17:33 -07009922
Johannes Bergd9d8b012012-11-26 12:51:52 +01009923 if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009924 return -EINVAL;
9925
Thomas Pedersen84f10702012-07-12 16:17:33 -07009926 if (!rdev->ops->set_cqm_txe_config)
9927 return -EOPNOTSUPP;
9928
9929 if (wdev->iftype != NL80211_IFTYPE_STATION &&
9930 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9931 return -EOPNOTSUPP;
9932
Hila Gonene35e4d22012-06-27 17:19:42 +03009933 return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
Thomas Pedersen84f10702012-07-12 16:17:33 -07009934}
9935
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009936static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
9937 struct net_device *dev)
9938{
9939 struct wireless_dev *wdev = dev->ieee80211_ptr;
9940 s32 last, low, high;
9941 u32 hyst;
9942 int i, n;
9943 int err;
9944
9945 /* RSSI reporting disabled? */
9946 if (!wdev->cqm_config)
9947 return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
9948
9949 /*
9950 * Obtain current RSSI value if possible, if not and no RSSI threshold
9951 * event has been received yet, we should receive an event after a
9952 * connection is established and enough beacons received to calculate
9953 * the average.
9954 */
9955 if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
9956 rdev->ops->get_station) {
Johannes Berg5762d7d2018-01-16 23:20:22 +01009957 struct station_info sinfo = {};
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009958 u8 *mac_addr;
9959
9960 mac_addr = wdev->current_bss->pub.bssid;
9961
9962 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
9963 if (err)
9964 return err;
9965
9966 if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
9967 wdev->cqm_config->last_rssi_event_value =
9968 (s8) sinfo.rx_beacon_signal_avg;
9969 }
9970
9971 last = wdev->cqm_config->last_rssi_event_value;
9972 hyst = wdev->cqm_config->rssi_hyst;
9973 n = wdev->cqm_config->n_rssi_thresholds;
9974
9975 for (i = 0; i < n; i++)
9976 if (last < wdev->cqm_config->rssi_thresholds[i])
9977 break;
9978
9979 low = i > 0 ?
9980 (wdev->cqm_config->rssi_thresholds[i - 1] - hyst) : S32_MIN;
9981 high = i < n ?
9982 (wdev->cqm_config->rssi_thresholds[i] + hyst - 1) : S32_MAX;
9983
9984 return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
9985}
9986
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009987static int nl80211_set_cqm_rssi(struct genl_info *info,
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009988 const s32 *thresholds, int n_thresholds,
9989 u32 hysteresis)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009990{
Johannes Berg4c476992010-10-04 21:36:35 +02009991 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009992 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009993 struct wireless_dev *wdev = dev->ieee80211_ptr;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009994 int i, err;
9995 s32 prev = S32_MIN;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009996
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009997 /* Check all values negative and sorted */
9998 for (i = 0; i < n_thresholds; i++) {
9999 if (thresholds[i] > 0 || thresholds[i] <= prev)
10000 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020010001
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010010002 prev = thresholds[i];
10003 }
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020010004
Johannes Berg074ac8d2010-09-16 14:58:22 +020010005 if (wdev->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +020010006 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
10007 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020010008
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010010009 wdev_lock(wdev);
10010 cfg80211_cqm_config_free(wdev);
10011 wdev_unlock(wdev);
10012
10013 if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
10014 if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
10015 return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
10016
10017 return rdev_set_cqm_rssi_config(rdev, dev,
10018 thresholds[0], hysteresis);
10019 }
10020
10021 if (!wiphy_ext_feature_isset(&rdev->wiphy,
10022 NL80211_EXT_FEATURE_CQM_RSSI_LIST))
10023 return -EOPNOTSUPP;
10024
10025 if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */
10026 n_thresholds = 0;
10027
10028 wdev_lock(wdev);
10029 if (n_thresholds) {
10030 struct cfg80211_cqm_config *cqm_config;
10031
10032 cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
10033 n_thresholds * sizeof(s32), GFP_KERNEL);
10034 if (!cqm_config) {
10035 err = -ENOMEM;
10036 goto unlock;
10037 }
10038
10039 cqm_config->rssi_hyst = hysteresis;
10040 cqm_config->n_rssi_thresholds = n_thresholds;
10041 memcpy(cqm_config->rssi_thresholds, thresholds,
10042 n_thresholds * sizeof(s32));
10043
10044 wdev->cqm_config = cqm_config;
10045 }
10046
10047 err = cfg80211_cqm_rssi_update(rdev, dev);
10048
10049unlock:
10050 wdev_unlock(wdev);
10051
10052 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020010053}
10054
10055static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
10056{
10057 struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
10058 struct nlattr *cqm;
10059 int err;
10060
10061 cqm = info->attrs[NL80211_ATTR_CQM];
Johannes Berg1da5fcc2013-08-06 14:10:48 +020010062 if (!cqm)
10063 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020010064
10065 err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
Johannes Bergfe521452017-04-12 14:34:08 +020010066 nl80211_attr_cqm_policy, info->extack);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020010067 if (err)
Johannes Berg1da5fcc2013-08-06 14:10:48 +020010068 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020010069
10070 if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
10071 attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010010072 const s32 *thresholds =
10073 nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
10074 int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
Johannes Berg1da5fcc2013-08-06 14:10:48 +020010075 u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020010076
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010010077 if (len % 4)
10078 return -EINVAL;
10079
10080 return nl80211_set_cqm_rssi(info, thresholds, len / 4,
10081 hysteresis);
Johannes Berg1da5fcc2013-08-06 14:10:48 +020010082 }
10083
10084 if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
10085 attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
10086 attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
10087 u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
10088 u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
10089 u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
10090
10091 return nl80211_set_cqm_txe(info, rate, pkts, intvl);
10092 }
10093
10094 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020010095}
10096
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010010097static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
10098{
10099 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10100 struct net_device *dev = info->user_ptr[1];
10101 struct ocb_setup setup = {};
10102 int err;
10103
10104 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
10105 if (err)
10106 return err;
10107
10108 return cfg80211_join_ocb(rdev, dev, &setup);
10109}
10110
10111static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
10112{
10113 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10114 struct net_device *dev = info->user_ptr[1];
10115
10116 return cfg80211_leave_ocb(rdev, dev);
10117}
10118
Johannes Berg29cbe682010-12-03 09:20:44 +010010119static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
10120{
10121 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10122 struct net_device *dev = info->user_ptr[1];
10123 struct mesh_config cfg;
Javier Cardonac80d5452010-12-16 17:37:49 -080010124 struct mesh_setup setup;
Johannes Berg29cbe682010-12-03 09:20:44 +010010125 int err;
10126
10127 /* start with default */
10128 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
Javier Cardonac80d5452010-12-16 17:37:49 -080010129 memcpy(&setup, &default_mesh_setup, sizeof(setup));
Johannes Berg29cbe682010-12-03 09:20:44 +010010130
Javier Cardona24bdd9f2010-12-16 17:37:48 -080010131 if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
Johannes Berg29cbe682010-12-03 09:20:44 +010010132 /* and parse parameters if given */
Javier Cardona24bdd9f2010-12-16 17:37:48 -080010133 err = nl80211_parse_mesh_config(info, &cfg, NULL);
Johannes Berg29cbe682010-12-03 09:20:44 +010010134 if (err)
10135 return err;
10136 }
10137
10138 if (!info->attrs[NL80211_ATTR_MESH_ID] ||
10139 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
10140 return -EINVAL;
10141
Javier Cardonac80d5452010-12-16 17:37:49 -080010142 setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
10143 setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
10144
Chun-Yeow Yeoh4bb62342011-11-24 17:15:20 -080010145 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
10146 !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
10147 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
10148 return -EINVAL;
10149
Marco Porsch9bdbf042013-01-07 16:04:51 +010010150 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
10151 setup.beacon_interval =
10152 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053010153
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +053010154 err = cfg80211_validate_beacon_int(rdev,
10155 NL80211_IFTYPE_MESH_POINT,
10156 setup.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053010157 if (err)
10158 return err;
Marco Porsch9bdbf042013-01-07 16:04:51 +010010159 }
10160
10161 if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
10162 setup.dtim_period =
10163 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
10164 if (setup.dtim_period < 1 || setup.dtim_period > 100)
10165 return -EINVAL;
10166 }
10167
Javier Cardonac80d5452010-12-16 17:37:49 -080010168 if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
10169 /* parse additional setup parameters if given */
10170 err = nl80211_parse_mesh_setup(info, &setup);
10171 if (err)
10172 return err;
10173 }
10174
Thomas Pedersend37bb182013-03-04 13:06:13 -080010175 if (setup.user_mpm)
10176 cfg.auto_open_plinks = false;
10177
Johannes Bergcc1d2802012-05-16 23:50:20 +020010178 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +010010179 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
10180 if (err)
10181 return err;
Johannes Bergcc1d2802012-05-16 23:50:20 +020010182 } else {
Denis Kenzior188c1b32018-03-26 12:52:46 -050010183 /* __cfg80211_join_mesh() will sort it out */
Johannes Berg683b6d32012-11-08 21:25:48 +010010184 setup.chandef.chan = NULL;
Johannes Bergcc1d2802012-05-16 23:50:20 +020010185 }
10186
Ashok Nagarajanffb3cf32013-06-03 10:33:36 -070010187 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
10188 u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
10189 int n_rates =
10190 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
10191 struct ieee80211_supported_band *sband;
10192
10193 if (!setup.chandef.chan)
10194 return -EINVAL;
10195
10196 sband = rdev->wiphy.bands[setup.chandef.chan->band];
10197
10198 err = ieee80211_get_ratemask(sband, rates, n_rates,
10199 &setup.basic_rates);
10200 if (err)
10201 return err;
10202 }
10203
Johannes Berg8564e382016-09-19 09:44:44 +020010204 if (info->attrs[NL80211_ATTR_TX_RATES]) {
10205 err = nl80211_parse_tx_bitrate_mask(info, &setup.beacon_rate);
10206 if (err)
10207 return err;
10208
Johannes Berg265698d2017-09-18 22:46:36 +020010209 if (!setup.chandef.chan)
10210 return -EINVAL;
10211
Johannes Berg8564e382016-09-19 09:44:44 +020010212 err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band,
10213 &setup.beacon_rate);
10214 if (err)
10215 return err;
10216 }
10217
Benjamin Bergd37d49c2017-05-16 11:23:11 +020010218 setup.userspace_handles_dfs =
10219 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
10220
Denis Kenzior1224f582018-03-26 12:52:49 -050010221 if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
10222 int r = validate_pae_over_nl80211(rdev, info);
10223
10224 if (r < 0)
10225 return r;
10226
10227 setup.control_port_over_nl80211 = true;
10228 }
10229
Denis Kenzior188c1b32018-03-26 12:52:46 -050010230 wdev_lock(dev->ieee80211_ptr);
10231 err = __cfg80211_join_mesh(rdev, dev, &setup, &cfg);
10232 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER])
10233 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
10234 wdev_unlock(dev->ieee80211_ptr);
10235
10236 return err;
Johannes Berg29cbe682010-12-03 09:20:44 +010010237}
10238
10239static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
10240{
10241 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10242 struct net_device *dev = info->user_ptr[1];
10243
10244 return cfg80211_leave_mesh(rdev, dev);
10245}
10246
Johannes Bergdfb89c52012-06-27 09:23:48 +020010247#ifdef CONFIG_PM
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010248static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
10249 struct cfg80211_registered_device *rdev)
10250{
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010251 struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010252 struct nlattr *nl_pats, *nl_pat;
10253 int i, pat_len;
10254
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010255 if (!wowlan->n_patterns)
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010256 return 0;
10257
10258 nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
10259 if (!nl_pats)
10260 return -ENOBUFS;
10261
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010262 for (i = 0; i < wowlan->n_patterns; i++) {
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010263 nl_pat = nla_nest_start(msg, i + 1);
10264 if (!nl_pat)
10265 return -ENOBUFS;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010266 pat_len = wowlan->patterns[i].pattern_len;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010267 if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010268 wowlan->patterns[i].mask) ||
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010269 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
10270 wowlan->patterns[i].pattern) ||
10271 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010272 wowlan->patterns[i].pkt_offset))
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010273 return -ENOBUFS;
10274 nla_nest_end(msg, nl_pat);
10275 }
10276 nla_nest_end(msg, nl_pats);
10277
10278 return 0;
10279}
10280
Johannes Berg2a0e0472013-01-23 22:57:40 +010010281static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
10282 struct cfg80211_wowlan_tcp *tcp)
10283{
10284 struct nlattr *nl_tcp;
10285
10286 if (!tcp)
10287 return 0;
10288
10289 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
10290 if (!nl_tcp)
10291 return -ENOBUFS;
10292
Jiri Benc930345e2015-03-29 16:59:25 +020010293 if (nla_put_in_addr(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
10294 nla_put_in_addr(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
Johannes Berg2a0e0472013-01-23 22:57:40 +010010295 nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
10296 nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
10297 nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
10298 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
10299 tcp->payload_len, tcp->payload) ||
10300 nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
10301 tcp->data_interval) ||
10302 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
10303 tcp->wake_len, tcp->wake_data) ||
10304 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK,
10305 DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask))
10306 return -ENOBUFS;
10307
10308 if (tcp->payload_seq.len &&
10309 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
10310 sizeof(tcp->payload_seq), &tcp->payload_seq))
10311 return -ENOBUFS;
10312
10313 if (tcp->payload_tok.len &&
10314 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
10315 sizeof(tcp->payload_tok) + tcp->tokens_size,
10316 &tcp->payload_tok))
10317 return -ENOBUFS;
10318
Johannes Berge248ad32013-05-16 10:24:28 +020010319 nla_nest_end(msg, nl_tcp);
10320
Johannes Berg2a0e0472013-01-23 22:57:40 +010010321 return 0;
10322}
10323
Luciano Coelho75453cc2015-01-09 14:06:37 +020010324static int nl80211_send_wowlan_nd(struct sk_buff *msg,
10325 struct cfg80211_sched_scan_request *req)
10326{
Avraham Stern3b06d272015-10-12 09:51:34 +030010327 struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
Luciano Coelho75453cc2015-01-09 14:06:37 +020010328 int i;
10329
10330 if (!req)
10331 return 0;
10332
10333 nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
10334 if (!nd)
10335 return -ENOBUFS;
10336
Avraham Stern3b06d272015-10-12 09:51:34 +030010337 if (req->n_scan_plans == 1 &&
10338 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
10339 req->scan_plans[0].interval * 1000))
Luciano Coelho75453cc2015-01-09 14:06:37 +020010340 return -ENOBUFS;
10341
Luciano Coelho21fea562015-03-17 16:36:01 +020010342 if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
10343 return -ENOBUFS;
10344
vamsi krishnabf95ecd2017-01-13 01:12:20 +020010345 if (req->relative_rssi_set) {
10346 struct nl80211_bss_select_rssi_adjust rssi_adjust;
10347
10348 if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
10349 req->relative_rssi))
10350 return -ENOBUFS;
10351
10352 rssi_adjust.band = req->rssi_adjust.band;
10353 rssi_adjust.delta = req->rssi_adjust.delta;
10354 if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
10355 sizeof(rssi_adjust), &rssi_adjust))
10356 return -ENOBUFS;
10357 }
10358
Luciano Coelho75453cc2015-01-09 14:06:37 +020010359 freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
10360 if (!freqs)
10361 return -ENOBUFS;
10362
Johannes Berg53b18982016-09-14 09:59:21 +020010363 for (i = 0; i < req->n_channels; i++) {
10364 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
10365 return -ENOBUFS;
10366 }
Luciano Coelho75453cc2015-01-09 14:06:37 +020010367
10368 nla_nest_end(msg, freqs);
10369
10370 if (req->n_match_sets) {
10371 matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
Johannes Berg76e1fb42016-09-14 09:55:57 +020010372 if (!matches)
10373 return -ENOBUFS;
10374
Luciano Coelho75453cc2015-01-09 14:06:37 +020010375 for (i = 0; i < req->n_match_sets; i++) {
10376 match = nla_nest_start(msg, i);
Johannes Berg76e1fb42016-09-14 09:55:57 +020010377 if (!match)
10378 return -ENOBUFS;
10379
Johannes Berg53b18982016-09-14 09:59:21 +020010380 if (nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
10381 req->match_sets[i].ssid.ssid_len,
10382 req->match_sets[i].ssid.ssid))
10383 return -ENOBUFS;
Luciano Coelho75453cc2015-01-09 14:06:37 +020010384 nla_nest_end(msg, match);
10385 }
10386 nla_nest_end(msg, matches);
10387 }
10388
Avraham Stern3b06d272015-10-12 09:51:34 +030010389 scan_plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
10390 if (!scan_plans)
10391 return -ENOBUFS;
10392
10393 for (i = 0; i < req->n_scan_plans; i++) {
10394 scan_plan = nla_nest_start(msg, i + 1);
Johannes Berg76e1fb42016-09-14 09:55:57 +020010395 if (!scan_plan)
10396 return -ENOBUFS;
10397
Avraham Stern3b06d272015-10-12 09:51:34 +030010398 if (!scan_plan ||
10399 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
10400 req->scan_plans[i].interval) ||
10401 (req->scan_plans[i].iterations &&
10402 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
10403 req->scan_plans[i].iterations)))
10404 return -ENOBUFS;
10405 nla_nest_end(msg, scan_plan);
10406 }
10407 nla_nest_end(msg, scan_plans);
10408
Luciano Coelho75453cc2015-01-09 14:06:37 +020010409 nla_nest_end(msg, nd);
10410
10411 return 0;
10412}
10413
Johannes Bergff1b6e62011-05-04 15:37:28 +020010414static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
10415{
10416 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10417 struct sk_buff *msg;
10418 void *hdr;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010419 u32 size = NLMSG_DEFAULT_SIZE;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010420
Johannes Berg964dc9e2013-06-03 17:25:34 +020010421 if (!rdev->wiphy.wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010422 return -EOPNOTSUPP;
10423
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010424 if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
Johannes Berg2a0e0472013-01-23 22:57:40 +010010425 /* adjust size to have room for all the data */
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010426 size += rdev->wiphy.wowlan_config->tcp->tokens_size +
10427 rdev->wiphy.wowlan_config->tcp->payload_len +
10428 rdev->wiphy.wowlan_config->tcp->wake_len +
10429 rdev->wiphy.wowlan_config->tcp->wake_len / 8;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010430 }
10431
10432 msg = nlmsg_new(size, GFP_KERNEL);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010433 if (!msg)
10434 return -ENOMEM;
10435
Eric W. Biederman15e47302012-09-07 20:12:54 +000010436 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Bergff1b6e62011-05-04 15:37:28 +020010437 NL80211_CMD_GET_WOWLAN);
10438 if (!hdr)
10439 goto nla_put_failure;
10440
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010441 if (rdev->wiphy.wowlan_config) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020010442 struct nlattr *nl_wowlan;
10443
10444 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
10445 if (!nl_wowlan)
10446 goto nla_put_failure;
10447
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010448 if ((rdev->wiphy.wowlan_config->any &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010449 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010450 (rdev->wiphy.wowlan_config->disconnect &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010451 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010452 (rdev->wiphy.wowlan_config->magic_pkt &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010453 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010454 (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010455 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010456 (rdev->wiphy.wowlan_config->eap_identity_req &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010457 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010458 (rdev->wiphy.wowlan_config->four_way_handshake &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010459 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010460 (rdev->wiphy.wowlan_config->rfkill_release &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010461 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
10462 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010463
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010464 if (nl80211_send_wowlan_patterns(msg, rdev))
10465 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010466
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010467 if (nl80211_send_wowlan_tcp(msg,
10468 rdev->wiphy.wowlan_config->tcp))
Johannes Berg2a0e0472013-01-23 22:57:40 +010010469 goto nla_put_failure;
10470
Luciano Coelho75453cc2015-01-09 14:06:37 +020010471 if (nl80211_send_wowlan_nd(
10472 msg,
10473 rdev->wiphy.wowlan_config->nd_config))
10474 goto nla_put_failure;
10475
Johannes Bergff1b6e62011-05-04 15:37:28 +020010476 nla_nest_end(msg, nl_wowlan);
10477 }
10478
10479 genlmsg_end(msg, hdr);
10480 return genlmsg_reply(msg, info);
10481
10482nla_put_failure:
10483 nlmsg_free(msg);
10484 return -ENOBUFS;
10485}
10486
Johannes Berg2a0e0472013-01-23 22:57:40 +010010487static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
10488 struct nlattr *attr,
10489 struct cfg80211_wowlan *trig)
10490{
10491 struct nlattr *tb[NUM_NL80211_WOWLAN_TCP];
10492 struct cfg80211_wowlan_tcp *cfg;
10493 struct nl80211_wowlan_tcp_data_token *tok = NULL;
10494 struct nl80211_wowlan_tcp_data_seq *seq = NULL;
10495 u32 size;
10496 u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
10497 int err, port;
10498
Johannes Berg964dc9e2013-06-03 17:25:34 +020010499 if (!rdev->wiphy.wowlan->tcp)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010500 return -EINVAL;
10501
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010502 err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TCP, attr,
Johannes Bergfceb6432017-04-12 14:34:07 +020010503 nl80211_wowlan_tcp_policy, NULL);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010504 if (err)
10505 return err;
10506
10507 if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] ||
10508 !tb[NL80211_WOWLAN_TCP_DST_IPV4] ||
10509 !tb[NL80211_WOWLAN_TCP_DST_MAC] ||
10510 !tb[NL80211_WOWLAN_TCP_DST_PORT] ||
10511 !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] ||
10512 !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] ||
10513 !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] ||
10514 !tb[NL80211_WOWLAN_TCP_WAKE_MASK])
10515 return -EINVAL;
10516
10517 data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010518 if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010519 return -EINVAL;
10520
10521 if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
Johannes Berg964dc9e2013-06-03 17:25:34 +020010522 rdev->wiphy.wowlan->tcp->data_interval_max ||
Johannes Berg723d5682013-02-26 13:56:40 +010010523 nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010524 return -EINVAL;
10525
10526 wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010527 if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010528 return -EINVAL;
10529
10530 wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
10531 if (wake_mask_size != DIV_ROUND_UP(wake_size, 8))
10532 return -EINVAL;
10533
10534 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) {
10535 u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
10536
10537 tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
10538 tokens_size = tokln - sizeof(*tok);
10539
10540 if (!tok->len || tokens_size % tok->len)
10541 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010542 if (!rdev->wiphy.wowlan->tcp->tok)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010543 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010544 if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010545 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010546 if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010547 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010548 if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010549 return -EINVAL;
10550 if (tok->offset + tok->len > data_size)
10551 return -EINVAL;
10552 }
10553
10554 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
10555 seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010556 if (!rdev->wiphy.wowlan->tcp->seq)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010557 return -EINVAL;
10558 if (seq->len == 0 || seq->len > 4)
10559 return -EINVAL;
10560 if (seq->len + seq->offset > data_size)
10561 return -EINVAL;
10562 }
10563
10564 size = sizeof(*cfg);
10565 size += data_size;
10566 size += wake_size + wake_mask_size;
10567 size += tokens_size;
10568
10569 cfg = kzalloc(size, GFP_KERNEL);
10570 if (!cfg)
10571 return -ENOMEM;
Jiri Benc67b61f62015-03-29 16:59:26 +020010572 cfg->src = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
10573 cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010574 memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
10575 ETH_ALEN);
10576 if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
10577 port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
10578 else
10579 port = 0;
10580#ifdef CONFIG_INET
10581 /* allocate a socket and port for it and use it */
10582 err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
10583 IPPROTO_TCP, &cfg->sock, 1);
10584 if (err) {
10585 kfree(cfg);
10586 return err;
10587 }
10588 if (inet_csk_get_port(cfg->sock->sk, port)) {
10589 sock_release(cfg->sock);
10590 kfree(cfg);
10591 return -EADDRINUSE;
10592 }
10593 cfg->src_port = inet_sk(cfg->sock->sk)->inet_num;
10594#else
10595 if (!port) {
10596 kfree(cfg);
10597 return -EINVAL;
10598 }
10599 cfg->src_port = port;
10600#endif
10601
10602 cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]);
10603 cfg->payload_len = data_size;
10604 cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size;
10605 memcpy((void *)cfg->payload,
10606 nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]),
10607 data_size);
10608 if (seq)
10609 cfg->payload_seq = *seq;
10610 cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]);
10611 cfg->wake_len = wake_size;
10612 cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size;
10613 memcpy((void *)cfg->wake_data,
10614 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]),
10615 wake_size);
10616 cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size +
10617 data_size + wake_size;
10618 memcpy((void *)cfg->wake_mask,
10619 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]),
10620 wake_mask_size);
10621 if (tok) {
10622 cfg->tokens_size = tokens_size;
10623 memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size);
10624 }
10625
10626 trig->tcp = cfg;
10627
10628 return 0;
10629}
10630
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010631static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
10632 const struct wiphy_wowlan_support *wowlan,
10633 struct nlattr *attr,
10634 struct cfg80211_wowlan *trig)
10635{
10636 struct nlattr **tb;
10637 int err;
10638
10639 tb = kzalloc(NUM_NL80211_ATTR * sizeof(*tb), GFP_KERNEL);
10640 if (!tb)
10641 return -ENOMEM;
10642
10643 if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) {
10644 err = -EOPNOTSUPP;
10645 goto out;
10646 }
10647
Johannes Bergfceb6432017-04-12 14:34:07 +020010648 err = nla_parse_nested(tb, NL80211_ATTR_MAX, attr, nl80211_policy,
10649 NULL);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010650 if (err)
10651 goto out;
10652
Arend Van Sprielaad1e812017-01-27 12:27:44 +000010653 trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb,
10654 wowlan->max_nd_match_sets);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010655 err = PTR_ERR_OR_ZERO(trig->nd_config);
10656 if (err)
10657 trig->nd_config = NULL;
10658
10659out:
10660 kfree(tb);
10661 return err;
10662}
10663
Johannes Bergff1b6e62011-05-04 15:37:28 +020010664static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
10665{
10666 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10667 struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010668 struct cfg80211_wowlan new_triggers = {};
Johannes Bergae33bd82012-07-12 16:25:02 +020010669 struct cfg80211_wowlan *ntrig;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010670 const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010671 int err, i;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010672 bool prev_enabled = rdev->wiphy.wowlan_config;
Johannes Berg98fc4382015-03-01 09:10:13 +020010673 bool regular = false;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010674
Johannes Berg964dc9e2013-06-03 17:25:34 +020010675 if (!wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010676 return -EOPNOTSUPP;
10677
Johannes Bergae33bd82012-07-12 16:25:02 +020010678 if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
10679 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010680 rdev->wiphy.wowlan_config = NULL;
Johannes Bergae33bd82012-07-12 16:25:02 +020010681 goto set_wakeup;
10682 }
Johannes Bergff1b6e62011-05-04 15:37:28 +020010683
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010684 err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TRIG,
10685 info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS],
Johannes Bergfe521452017-04-12 14:34:08 +020010686 nl80211_wowlan_policy, info->extack);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010687 if (err)
10688 return err;
10689
10690 if (tb[NL80211_WOWLAN_TRIG_ANY]) {
10691 if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
10692 return -EINVAL;
10693 new_triggers.any = true;
10694 }
10695
10696 if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
10697 if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
10698 return -EINVAL;
10699 new_triggers.disconnect = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010700 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010701 }
10702
10703 if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
10704 if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
10705 return -EINVAL;
10706 new_triggers.magic_pkt = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010707 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010708 }
10709
Johannes Berg77dbbb12011-07-13 10:48:55 +020010710 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
10711 return -EINVAL;
10712
10713 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) {
10714 if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
10715 return -EINVAL;
10716 new_triggers.gtk_rekey_failure = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010717 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010718 }
10719
10720 if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
10721 if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
10722 return -EINVAL;
10723 new_triggers.eap_identity_req = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010724 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010725 }
10726
10727 if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
10728 if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
10729 return -EINVAL;
10730 new_triggers.four_way_handshake = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010731 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010732 }
10733
10734 if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
10735 if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
10736 return -EINVAL;
10737 new_triggers.rfkill_release = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010738 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010739 }
10740
Johannes Bergff1b6e62011-05-04 15:37:28 +020010741 if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
10742 struct nlattr *pat;
10743 int n_patterns = 0;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010744 int rem, pat_len, mask_len, pkt_offset;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010745 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010746
Johannes Berg98fc4382015-03-01 09:10:13 +020010747 regular = true;
10748
Johannes Bergff1b6e62011-05-04 15:37:28 +020010749 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10750 rem)
10751 n_patterns++;
10752 if (n_patterns > wowlan->n_patterns)
10753 return -EINVAL;
10754
10755 new_triggers.patterns = kcalloc(n_patterns,
10756 sizeof(new_triggers.patterns[0]),
10757 GFP_KERNEL);
10758 if (!new_triggers.patterns)
10759 return -ENOMEM;
10760
10761 new_triggers.n_patterns = n_patterns;
10762 i = 0;
10763
10764 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10765 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010766 u8 *mask_pat;
10767
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010768 nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat,
Peng Xuad670232017-10-03 23:21:51 +030010769 nl80211_packet_pattern_policy,
10770 info->extack);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010771 err = -EINVAL;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010772 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10773 !pat_tb[NL80211_PKTPAT_PATTERN])
Johannes Bergff1b6e62011-05-04 15:37:28 +020010774 goto error;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010775 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010776 mask_len = DIV_ROUND_UP(pat_len, 8);
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010777 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010778 goto error;
10779 if (pat_len > wowlan->pattern_max_len ||
10780 pat_len < wowlan->pattern_min_len)
10781 goto error;
10782
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010783 if (!pat_tb[NL80211_PKTPAT_OFFSET])
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010784 pkt_offset = 0;
10785 else
10786 pkt_offset = nla_get_u32(
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010787 pat_tb[NL80211_PKTPAT_OFFSET]);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010788 if (pkt_offset > wowlan->max_pkt_offset)
10789 goto error;
10790 new_triggers.patterns[i].pkt_offset = pkt_offset;
10791
Johannes Berg922bd802014-05-19 17:59:50 +020010792 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10793 if (!mask_pat) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020010794 err = -ENOMEM;
10795 goto error;
10796 }
Johannes Berg922bd802014-05-19 17:59:50 +020010797 new_triggers.patterns[i].mask = mask_pat;
10798 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010799 mask_len);
Johannes Berg922bd802014-05-19 17:59:50 +020010800 mask_pat += mask_len;
10801 new_triggers.patterns[i].pattern = mask_pat;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010802 new_triggers.patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010803 memcpy(mask_pat,
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010804 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010805 pat_len);
10806 i++;
10807 }
10808 }
10809
Johannes Berg2a0e0472013-01-23 22:57:40 +010010810 if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010811 regular = true;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010812 err = nl80211_parse_wowlan_tcp(
10813 rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
10814 &new_triggers);
10815 if (err)
10816 goto error;
10817 }
10818
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010819 if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010820 regular = true;
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010821 err = nl80211_parse_wowlan_nd(
10822 rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
10823 &new_triggers);
10824 if (err)
10825 goto error;
10826 }
10827
Johannes Berg98fc4382015-03-01 09:10:13 +020010828 /* The 'any' trigger means the device continues operating more or less
10829 * as in its normal operation mode and wakes up the host on most of the
10830 * normal interrupts (like packet RX, ...)
10831 * It therefore makes little sense to combine with the more constrained
10832 * wakeup trigger modes.
10833 */
10834 if (new_triggers.any && regular) {
10835 err = -EINVAL;
10836 goto error;
10837 }
10838
Johannes Bergae33bd82012-07-12 16:25:02 +020010839 ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
10840 if (!ntrig) {
10841 err = -ENOMEM;
10842 goto error;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010843 }
Johannes Bergae33bd82012-07-12 16:25:02 +020010844 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010845 rdev->wiphy.wowlan_config = ntrig;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010846
Johannes Bergae33bd82012-07-12 16:25:02 +020010847 set_wakeup:
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010848 if (rdev->ops->set_wakeup &&
10849 prev_enabled != !!rdev->wiphy.wowlan_config)
10850 rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
Johannes Berg6d525632012-04-04 15:05:25 +020010851
Johannes Bergff1b6e62011-05-04 15:37:28 +020010852 return 0;
10853 error:
10854 for (i = 0; i < new_triggers.n_patterns; i++)
10855 kfree(new_triggers.patterns[i].mask);
10856 kfree(new_triggers.patterns);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010857 if (new_triggers.tcp && new_triggers.tcp->sock)
10858 sock_release(new_triggers.tcp->sock);
10859 kfree(new_triggers.tcp);
Ola Olssone5dbe072015-12-12 23:17:17 +010010860 kfree(new_triggers.nd_config);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010861 return err;
10862}
Johannes Bergdfb89c52012-06-27 09:23:48 +020010863#endif
Johannes Bergff1b6e62011-05-04 15:37:28 +020010864
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010865static int nl80211_send_coalesce_rules(struct sk_buff *msg,
10866 struct cfg80211_registered_device *rdev)
10867{
10868 struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
10869 int i, j, pat_len;
10870 struct cfg80211_coalesce_rules *rule;
10871
10872 if (!rdev->coalesce->n_rules)
10873 return 0;
10874
10875 nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
10876 if (!nl_rules)
10877 return -ENOBUFS;
10878
10879 for (i = 0; i < rdev->coalesce->n_rules; i++) {
10880 nl_rule = nla_nest_start(msg, i + 1);
10881 if (!nl_rule)
10882 return -ENOBUFS;
10883
10884 rule = &rdev->coalesce->rules[i];
10885 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
10886 rule->delay))
10887 return -ENOBUFS;
10888
10889 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
10890 rule->condition))
10891 return -ENOBUFS;
10892
10893 nl_pats = nla_nest_start(msg,
10894 NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
10895 if (!nl_pats)
10896 return -ENOBUFS;
10897
10898 for (j = 0; j < rule->n_patterns; j++) {
10899 nl_pat = nla_nest_start(msg, j + 1);
10900 if (!nl_pat)
10901 return -ENOBUFS;
10902 pat_len = rule->patterns[j].pattern_len;
10903 if (nla_put(msg, NL80211_PKTPAT_MASK,
10904 DIV_ROUND_UP(pat_len, 8),
10905 rule->patterns[j].mask) ||
10906 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
10907 rule->patterns[j].pattern) ||
10908 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
10909 rule->patterns[j].pkt_offset))
10910 return -ENOBUFS;
10911 nla_nest_end(msg, nl_pat);
10912 }
10913 nla_nest_end(msg, nl_pats);
10914 nla_nest_end(msg, nl_rule);
10915 }
10916 nla_nest_end(msg, nl_rules);
10917
10918 return 0;
10919}
10920
10921static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
10922{
10923 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10924 struct sk_buff *msg;
10925 void *hdr;
10926
10927 if (!rdev->wiphy.coalesce)
10928 return -EOPNOTSUPP;
10929
10930 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10931 if (!msg)
10932 return -ENOMEM;
10933
10934 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
10935 NL80211_CMD_GET_COALESCE);
10936 if (!hdr)
10937 goto nla_put_failure;
10938
10939 if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
10940 goto nla_put_failure;
10941
10942 genlmsg_end(msg, hdr);
10943 return genlmsg_reply(msg, info);
10944
10945nla_put_failure:
10946 nlmsg_free(msg);
10947 return -ENOBUFS;
10948}
10949
10950void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
10951{
10952 struct cfg80211_coalesce *coalesce = rdev->coalesce;
10953 int i, j;
10954 struct cfg80211_coalesce_rules *rule;
10955
10956 if (!coalesce)
10957 return;
10958
10959 for (i = 0; i < coalesce->n_rules; i++) {
10960 rule = &coalesce->rules[i];
10961 for (j = 0; j < rule->n_patterns; j++)
10962 kfree(rule->patterns[j].mask);
10963 kfree(rule->patterns);
10964 }
10965 kfree(coalesce->rules);
10966 kfree(coalesce);
10967 rdev->coalesce = NULL;
10968}
10969
10970static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
10971 struct nlattr *rule,
10972 struct cfg80211_coalesce_rules *new_rule)
10973{
10974 int err, i;
10975 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10976 struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
10977 int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
10978 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
10979
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010980 err = nla_parse_nested(tb, NL80211_ATTR_COALESCE_RULE_MAX, rule,
Johannes Bergfceb6432017-04-12 14:34:07 +020010981 nl80211_coalesce_policy, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010982 if (err)
10983 return err;
10984
10985 if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
10986 new_rule->delay =
10987 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
10988 if (new_rule->delay > coalesce->max_delay)
10989 return -EINVAL;
10990
10991 if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
10992 new_rule->condition =
10993 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
10994 if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH &&
10995 new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH)
10996 return -EINVAL;
10997
10998 if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
10999 return -EINVAL;
11000
11001 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
11002 rem)
11003 n_patterns++;
11004 if (n_patterns > coalesce->n_patterns)
11005 return -EINVAL;
11006
11007 new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
11008 GFP_KERNEL);
11009 if (!new_rule->patterns)
11010 return -ENOMEM;
11011
11012 new_rule->n_patterns = n_patterns;
11013 i = 0;
11014
11015 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
11016 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020011017 u8 *mask_pat;
11018
Peng Xuad670232017-10-03 23:21:51 +030011019 nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat,
11020 nl80211_packet_pattern_policy, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070011021 if (!pat_tb[NL80211_PKTPAT_MASK] ||
11022 !pat_tb[NL80211_PKTPAT_PATTERN])
11023 return -EINVAL;
11024 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
11025 mask_len = DIV_ROUND_UP(pat_len, 8);
11026 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
11027 return -EINVAL;
11028 if (pat_len > coalesce->pattern_max_len ||
11029 pat_len < coalesce->pattern_min_len)
11030 return -EINVAL;
11031
11032 if (!pat_tb[NL80211_PKTPAT_OFFSET])
11033 pkt_offset = 0;
11034 else
11035 pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
11036 if (pkt_offset > coalesce->max_pkt_offset)
11037 return -EINVAL;
11038 new_rule->patterns[i].pkt_offset = pkt_offset;
11039
Johannes Berg922bd802014-05-19 17:59:50 +020011040 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
11041 if (!mask_pat)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070011042 return -ENOMEM;
Johannes Berg922bd802014-05-19 17:59:50 +020011043
11044 new_rule->patterns[i].mask = mask_pat;
11045 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
11046 mask_len);
11047
11048 mask_pat += mask_len;
11049 new_rule->patterns[i].pattern = mask_pat;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070011050 new_rule->patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020011051 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
11052 pat_len);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070011053 i++;
11054 }
11055
11056 return 0;
11057}
11058
11059static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
11060{
11061 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11062 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
11063 struct cfg80211_coalesce new_coalesce = {};
11064 struct cfg80211_coalesce *n_coalesce;
11065 int err, rem_rule, n_rules = 0, i, j;
11066 struct nlattr *rule;
11067 struct cfg80211_coalesce_rules *tmp_rule;
11068
11069 if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
11070 return -EOPNOTSUPP;
11071
11072 if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
11073 cfg80211_rdev_free_coalesce(rdev);
Ilan Peera1056b1b2015-10-22 22:27:46 +030011074 rdev_set_coalesce(rdev, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070011075 return 0;
11076 }
11077
11078 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
11079 rem_rule)
11080 n_rules++;
11081 if (n_rules > coalesce->n_rules)
11082 return -EINVAL;
11083
11084 new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
11085 GFP_KERNEL);
11086 if (!new_coalesce.rules)
11087 return -ENOMEM;
11088
11089 new_coalesce.n_rules = n_rules;
11090 i = 0;
11091
11092 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
11093 rem_rule) {
11094 err = nl80211_parse_coalesce_rule(rdev, rule,
11095 &new_coalesce.rules[i]);
11096 if (err)
11097 goto error;
11098
11099 i++;
11100 }
11101
Ilan Peera1056b1b2015-10-22 22:27:46 +030011102 err = rdev_set_coalesce(rdev, &new_coalesce);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070011103 if (err)
11104 goto error;
11105
11106 n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
11107 if (!n_coalesce) {
11108 err = -ENOMEM;
11109 goto error;
11110 }
11111 cfg80211_rdev_free_coalesce(rdev);
11112 rdev->coalesce = n_coalesce;
11113
11114 return 0;
11115error:
11116 for (i = 0; i < new_coalesce.n_rules; i++) {
11117 tmp_rule = &new_coalesce.rules[i];
11118 for (j = 0; j < tmp_rule->n_patterns; j++)
11119 kfree(tmp_rule->patterns[j].mask);
11120 kfree(tmp_rule->patterns);
11121 }
11122 kfree(new_coalesce.rules);
11123
11124 return err;
11125}
11126
Johannes Berge5497d72011-07-05 16:35:40 +020011127static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
11128{
11129 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11130 struct net_device *dev = info->user_ptr[1];
11131 struct wireless_dev *wdev = dev->ieee80211_ptr;
11132 struct nlattr *tb[NUM_NL80211_REKEY_DATA];
11133 struct cfg80211_gtk_rekey_data rekey_data;
11134 int err;
11135
11136 if (!info->attrs[NL80211_ATTR_REKEY_DATA])
11137 return -EINVAL;
11138
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020011139 err = nla_parse_nested(tb, MAX_NL80211_REKEY_DATA,
11140 info->attrs[NL80211_ATTR_REKEY_DATA],
Johannes Bergfe521452017-04-12 14:34:08 +020011141 nl80211_rekey_policy, info->extack);
Johannes Berge5497d72011-07-05 16:35:40 +020011142 if (err)
11143 return err;
11144
Vladis Dronove785fa02017-09-13 00:21:21 +020011145 if (!tb[NL80211_REKEY_DATA_REPLAY_CTR] || !tb[NL80211_REKEY_DATA_KEK] ||
11146 !tb[NL80211_REKEY_DATA_KCK])
11147 return -EINVAL;
Johannes Berge5497d72011-07-05 16:35:40 +020011148 if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
11149 return -ERANGE;
11150 if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
11151 return -ERANGE;
11152 if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
11153 return -ERANGE;
11154
Johannes Berg78f686c2014-09-10 22:28:06 +030011155 rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
11156 rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
11157 rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
Johannes Berge5497d72011-07-05 16:35:40 +020011158
11159 wdev_lock(wdev);
11160 if (!wdev->current_bss) {
11161 err = -ENOTCONN;
11162 goto out;
11163 }
11164
11165 if (!rdev->ops->set_rekey_data) {
11166 err = -EOPNOTSUPP;
11167 goto out;
11168 }
11169
Hila Gonene35e4d22012-06-27 17:19:42 +030011170 err = rdev_set_rekey_data(rdev, dev, &rekey_data);
Johannes Berge5497d72011-07-05 16:35:40 +020011171 out:
11172 wdev_unlock(wdev);
11173 return err;
11174}
11175
Johannes Berg28946da2011-11-04 11:18:12 +010011176static int nl80211_register_unexpected_frame(struct sk_buff *skb,
11177 struct genl_info *info)
11178{
11179 struct net_device *dev = info->user_ptr[1];
11180 struct wireless_dev *wdev = dev->ieee80211_ptr;
11181
11182 if (wdev->iftype != NL80211_IFTYPE_AP &&
11183 wdev->iftype != NL80211_IFTYPE_P2P_GO)
11184 return -EINVAL;
11185
Eric W. Biederman15e47302012-09-07 20:12:54 +000011186 if (wdev->ap_unexpected_nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010011187 return -EBUSY;
11188
Eric W. Biederman15e47302012-09-07 20:12:54 +000011189 wdev->ap_unexpected_nlportid = info->snd_portid;
Johannes Berg28946da2011-11-04 11:18:12 +010011190 return 0;
11191}
11192
Johannes Berg7f6cf312011-11-04 11:18:15 +010011193static int nl80211_probe_client(struct sk_buff *skb,
11194 struct genl_info *info)
11195{
11196 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11197 struct net_device *dev = info->user_ptr[1];
11198 struct wireless_dev *wdev = dev->ieee80211_ptr;
11199 struct sk_buff *msg;
11200 void *hdr;
11201 const u8 *addr;
11202 u64 cookie;
11203 int err;
11204
11205 if (wdev->iftype != NL80211_IFTYPE_AP &&
11206 wdev->iftype != NL80211_IFTYPE_P2P_GO)
11207 return -EOPNOTSUPP;
11208
11209 if (!info->attrs[NL80211_ATTR_MAC])
11210 return -EINVAL;
11211
11212 if (!rdev->ops->probe_client)
11213 return -EOPNOTSUPP;
11214
11215 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11216 if (!msg)
11217 return -ENOMEM;
11218
Eric W. Biederman15e47302012-09-07 20:12:54 +000011219 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg7f6cf312011-11-04 11:18:15 +010011220 NL80211_CMD_PROBE_CLIENT);
Dan Carpentercb35fba2013-08-14 14:50:01 +030011221 if (!hdr) {
11222 err = -ENOBUFS;
Johannes Berg7f6cf312011-11-04 11:18:15 +010011223 goto free_msg;
11224 }
11225
11226 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
11227
Hila Gonene35e4d22012-06-27 17:19:42 +030011228 err = rdev_probe_client(rdev, dev, addr, &cookie);
Johannes Berg7f6cf312011-11-04 11:18:15 +010011229 if (err)
11230 goto free_msg;
11231
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020011232 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
11233 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040011234 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010011235
11236 genlmsg_end(msg, hdr);
11237
11238 return genlmsg_reply(msg, info);
11239
11240 nla_put_failure:
11241 err = -ENOBUFS;
11242 free_msg:
11243 nlmsg_free(msg);
11244 return err;
11245}
11246
Johannes Berg5e760232011-11-04 11:18:17 +010011247static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
11248{
11249 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Ben Greear37c73b52012-10-26 14:49:25 -070011250 struct cfg80211_beacon_registration *reg, *nreg;
11251 int rv;
Johannes Berg5e760232011-11-04 11:18:17 +010011252
11253 if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
11254 return -EOPNOTSUPP;
11255
Ben Greear37c73b52012-10-26 14:49:25 -070011256 nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
11257 if (!nreg)
11258 return -ENOMEM;
Johannes Berg5e760232011-11-04 11:18:17 +010011259
Ben Greear37c73b52012-10-26 14:49:25 -070011260 /* First, check if already registered. */
11261 spin_lock_bh(&rdev->beacon_registrations_lock);
11262 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
11263 if (reg->nlportid == info->snd_portid) {
11264 rv = -EALREADY;
11265 goto out_err;
11266 }
11267 }
11268 /* Add it to the list */
11269 nreg->nlportid = info->snd_portid;
11270 list_add(&nreg->list, &rdev->beacon_registrations);
11271
11272 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010011273
11274 return 0;
Ben Greear37c73b52012-10-26 14:49:25 -070011275out_err:
11276 spin_unlock_bh(&rdev->beacon_registrations_lock);
11277 kfree(nreg);
11278 return rv;
Johannes Berg5e760232011-11-04 11:18:17 +010011279}
11280
Johannes Berg98104fde2012-06-16 00:19:54 +020011281static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
11282{
11283 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11284 struct wireless_dev *wdev = info->user_ptr[1];
11285 int err;
11286
11287 if (!rdev->ops->start_p2p_device)
11288 return -EOPNOTSUPP;
11289
11290 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
11291 return -EOPNOTSUPP;
11292
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011293 if (wdev_running(wdev))
Johannes Berg98104fde2012-06-16 00:19:54 +020011294 return 0;
11295
Luciano Coelhob6a55012014-02-27 11:07:21 +020011296 if (rfkill_blocked(rdev->rfkill))
11297 return -ERFKILL;
Johannes Berg98104fde2012-06-16 00:19:54 +020011298
Johannes Bergeeb126e2012-10-23 15:16:50 +020011299 err = rdev_start_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020011300 if (err)
11301 return err;
11302
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011303 wdev->is_running = true;
Johannes Berg98104fde2012-06-16 00:19:54 +020011304 rdev->opencount++;
Johannes Berg98104fde2012-06-16 00:19:54 +020011305
11306 return 0;
11307}
11308
11309static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
11310{
11311 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11312 struct wireless_dev *wdev = info->user_ptr[1];
11313
11314 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
11315 return -EOPNOTSUPP;
11316
11317 if (!rdev->ops->stop_p2p_device)
11318 return -EOPNOTSUPP;
11319
Johannes Bergf9f47522013-03-19 15:04:07 +010011320 cfg80211_stop_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020011321
11322 return 0;
11323}
11324
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011325static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
11326{
11327 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11328 struct wireless_dev *wdev = info->user_ptr[1];
11329 struct cfg80211_nan_conf conf = {};
11330 int err;
11331
11332 if (wdev->iftype != NL80211_IFTYPE_NAN)
11333 return -EOPNOTSUPP;
11334
Johannes Bergeeb04a92016-11-21 13:55:48 +010011335 if (wdev_running(wdev))
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011336 return -EEXIST;
11337
11338 if (rfkill_blocked(rdev->rfkill))
11339 return -ERFKILL;
11340
11341 if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
11342 return -EINVAL;
11343
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011344 conf.master_pref =
11345 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
11346 if (!conf.master_pref)
11347 return -EINVAL;
11348
Luca Coelho85859892017-02-08 15:00:34 +020011349 if (info->attrs[NL80211_ATTR_BANDS]) {
11350 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
11351
11352 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
11353 return -EOPNOTSUPP;
11354
11355 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
11356 return -EINVAL;
11357
11358 conf.bands = bands;
11359 }
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011360
11361 err = rdev_start_nan(rdev, wdev, &conf);
11362 if (err)
11363 return err;
11364
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011365 wdev->is_running = true;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011366 rdev->opencount++;
11367
11368 return 0;
11369}
11370
11371static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
11372{
11373 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11374 struct wireless_dev *wdev = info->user_ptr[1];
11375
11376 if (wdev->iftype != NL80211_IFTYPE_NAN)
11377 return -EOPNOTSUPP;
11378
11379 cfg80211_stop_nan(rdev, wdev);
11380
11381 return 0;
11382}
11383
Ayala Bekera442b762016-09-20 17:31:15 +030011384static int validate_nan_filter(struct nlattr *filter_attr)
11385{
11386 struct nlattr *attr;
11387 int len = 0, n_entries = 0, rem;
11388
11389 nla_for_each_nested(attr, filter_attr, rem) {
11390 len += nla_len(attr);
11391 n_entries++;
11392 }
11393
11394 if (len >= U8_MAX)
11395 return -EINVAL;
11396
11397 return n_entries;
11398}
11399
11400static int handle_nan_filter(struct nlattr *attr_filter,
11401 struct cfg80211_nan_func *func,
11402 bool tx)
11403{
11404 struct nlattr *attr;
11405 int n_entries, rem, i;
11406 struct cfg80211_nan_func_filter *filter;
11407
11408 n_entries = validate_nan_filter(attr_filter);
11409 if (n_entries < 0)
11410 return n_entries;
11411
11412 BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters));
11413
11414 filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL);
11415 if (!filter)
11416 return -ENOMEM;
11417
11418 i = 0;
11419 nla_for_each_nested(attr, attr_filter, rem) {
Thomas Grafb15ca182016-10-26 10:53:16 +020011420 filter[i].filter = nla_memdup(attr, GFP_KERNEL);
Ayala Bekera442b762016-09-20 17:31:15 +030011421 filter[i].len = nla_len(attr);
11422 i++;
11423 }
11424 if (tx) {
11425 func->num_tx_filters = n_entries;
11426 func->tx_filters = filter;
11427 } else {
11428 func->num_rx_filters = n_entries;
11429 func->rx_filters = filter;
11430 }
11431
11432 return 0;
11433}
11434
11435static int nl80211_nan_add_func(struct sk_buff *skb,
11436 struct genl_info *info)
11437{
11438 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11439 struct wireless_dev *wdev = info->user_ptr[1];
11440 struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR], *func_attr;
11441 struct cfg80211_nan_func *func;
11442 struct sk_buff *msg = NULL;
11443 void *hdr = NULL;
11444 int err = 0;
11445
11446 if (wdev->iftype != NL80211_IFTYPE_NAN)
11447 return -EOPNOTSUPP;
11448
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011449 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030011450 return -ENOTCONN;
11451
11452 if (!info->attrs[NL80211_ATTR_NAN_FUNC])
11453 return -EINVAL;
11454
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020011455 err = nla_parse_nested(tb, NL80211_NAN_FUNC_ATTR_MAX,
11456 info->attrs[NL80211_ATTR_NAN_FUNC],
Johannes Bergfe521452017-04-12 14:34:08 +020011457 nl80211_nan_func_policy, info->extack);
Ayala Bekera442b762016-09-20 17:31:15 +030011458 if (err)
11459 return err;
11460
11461 func = kzalloc(sizeof(*func), GFP_KERNEL);
11462 if (!func)
11463 return -ENOMEM;
11464
11465 func->cookie = wdev->wiphy->cookie_counter++;
11466
11467 if (!tb[NL80211_NAN_FUNC_TYPE] ||
11468 nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]) > NL80211_NAN_FUNC_MAX_TYPE) {
11469 err = -EINVAL;
11470 goto out;
11471 }
11472
11473
11474 func->type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]);
11475
11476 if (!tb[NL80211_NAN_FUNC_SERVICE_ID]) {
11477 err = -EINVAL;
11478 goto out;
11479 }
11480
11481 memcpy(func->service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]),
11482 sizeof(func->service_id));
11483
11484 func->close_range =
11485 nla_get_flag(tb[NL80211_NAN_FUNC_CLOSE_RANGE]);
11486
11487 if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) {
11488 func->serv_spec_info_len =
11489 nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
11490 func->serv_spec_info =
11491 kmemdup(nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]),
11492 func->serv_spec_info_len,
11493 GFP_KERNEL);
11494 if (!func->serv_spec_info) {
11495 err = -ENOMEM;
11496 goto out;
11497 }
11498 }
11499
11500 if (tb[NL80211_NAN_FUNC_TTL])
11501 func->ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]);
11502
11503 switch (func->type) {
11504 case NL80211_NAN_FUNC_PUBLISH:
11505 if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE]) {
11506 err = -EINVAL;
11507 goto out;
11508 }
11509
11510 func->publish_type =
11511 nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]);
11512 func->publish_bcast =
11513 nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]);
11514
11515 if ((!(func->publish_type & NL80211_NAN_SOLICITED_PUBLISH)) &&
11516 func->publish_bcast) {
11517 err = -EINVAL;
11518 goto out;
11519 }
11520 break;
11521 case NL80211_NAN_FUNC_SUBSCRIBE:
11522 func->subscribe_active =
11523 nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]);
11524 break;
11525 case NL80211_NAN_FUNC_FOLLOW_UP:
11526 if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] ||
Hao Chen3ea15452018-01-03 11:00:31 +080011527 !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] ||
11528 !tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]) {
Ayala Bekera442b762016-09-20 17:31:15 +030011529 err = -EINVAL;
11530 goto out;
11531 }
11532
11533 func->followup_id =
11534 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]);
11535 func->followup_reqid =
11536 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]);
11537 memcpy(func->followup_dest.addr,
11538 nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]),
11539 sizeof(func->followup_dest.addr));
11540 if (func->ttl) {
11541 err = -EINVAL;
11542 goto out;
11543 }
11544 break;
11545 default:
11546 err = -EINVAL;
11547 goto out;
11548 }
11549
11550 if (tb[NL80211_NAN_FUNC_SRF]) {
11551 struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
11552
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020011553 err = nla_parse_nested(srf_tb, NL80211_NAN_SRF_ATTR_MAX,
11554 tb[NL80211_NAN_FUNC_SRF],
Johannes Bergfe521452017-04-12 14:34:08 +020011555 nl80211_nan_srf_policy, info->extack);
Ayala Bekera442b762016-09-20 17:31:15 +030011556 if (err)
11557 goto out;
11558
11559 func->srf_include =
11560 nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]);
11561
11562 if (srf_tb[NL80211_NAN_SRF_BF]) {
11563 if (srf_tb[NL80211_NAN_SRF_MAC_ADDRS] ||
11564 !srf_tb[NL80211_NAN_SRF_BF_IDX]) {
11565 err = -EINVAL;
11566 goto out;
11567 }
11568
11569 func->srf_bf_len =
11570 nla_len(srf_tb[NL80211_NAN_SRF_BF]);
11571 func->srf_bf =
11572 kmemdup(nla_data(srf_tb[NL80211_NAN_SRF_BF]),
11573 func->srf_bf_len, GFP_KERNEL);
11574 if (!func->srf_bf) {
11575 err = -ENOMEM;
11576 goto out;
11577 }
11578
11579 func->srf_bf_idx =
11580 nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]);
11581 } else {
11582 struct nlattr *attr, *mac_attr =
11583 srf_tb[NL80211_NAN_SRF_MAC_ADDRS];
11584 int n_entries, rem, i = 0;
11585
11586 if (!mac_attr) {
11587 err = -EINVAL;
11588 goto out;
11589 }
11590
11591 n_entries = validate_acl_mac_addrs(mac_attr);
11592 if (n_entries <= 0) {
11593 err = -EINVAL;
11594 goto out;
11595 }
11596
11597 func->srf_num_macs = n_entries;
11598 func->srf_macs =
11599 kzalloc(sizeof(*func->srf_macs) * n_entries,
11600 GFP_KERNEL);
11601 if (!func->srf_macs) {
11602 err = -ENOMEM;
11603 goto out;
11604 }
11605
11606 nla_for_each_nested(attr, mac_attr, rem)
11607 memcpy(func->srf_macs[i++].addr, nla_data(attr),
11608 sizeof(*func->srf_macs));
11609 }
11610 }
11611
11612 if (tb[NL80211_NAN_FUNC_TX_MATCH_FILTER]) {
11613 err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER],
11614 func, true);
11615 if (err)
11616 goto out;
11617 }
11618
11619 if (tb[NL80211_NAN_FUNC_RX_MATCH_FILTER]) {
11620 err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER],
11621 func, false);
11622 if (err)
11623 goto out;
11624 }
11625
11626 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11627 if (!msg) {
11628 err = -ENOMEM;
11629 goto out;
11630 }
11631
11632 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11633 NL80211_CMD_ADD_NAN_FUNCTION);
11634 /* This can't really happen - we just allocated 4KB */
11635 if (WARN_ON(!hdr)) {
11636 err = -ENOMEM;
11637 goto out;
11638 }
11639
11640 err = rdev_add_nan_func(rdev, wdev, func);
11641out:
11642 if (err < 0) {
11643 cfg80211_free_nan_func(func);
11644 nlmsg_free(msg);
11645 return err;
11646 }
11647
11648 /* propagate the instance id and cookie to userspace */
11649 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, func->cookie,
11650 NL80211_ATTR_PAD))
11651 goto nla_put_failure;
11652
11653 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11654 if (!func_attr)
11655 goto nla_put_failure;
11656
11657 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID,
11658 func->instance_id))
11659 goto nla_put_failure;
11660
11661 nla_nest_end(msg, func_attr);
11662
11663 genlmsg_end(msg, hdr);
11664 return genlmsg_reply(msg, info);
11665
11666nla_put_failure:
11667 nlmsg_free(msg);
11668 return -ENOBUFS;
11669}
11670
11671static int nl80211_nan_del_func(struct sk_buff *skb,
11672 struct genl_info *info)
11673{
11674 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11675 struct wireless_dev *wdev = info->user_ptr[1];
11676 u64 cookie;
11677
11678 if (wdev->iftype != NL80211_IFTYPE_NAN)
11679 return -EOPNOTSUPP;
11680
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011681 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030011682 return -ENOTCONN;
11683
11684 if (!info->attrs[NL80211_ATTR_COOKIE])
11685 return -EINVAL;
11686
Ayala Bekera442b762016-09-20 17:31:15 +030011687 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
11688
11689 rdev_del_nan_func(rdev, wdev, cookie);
11690
11691 return 0;
11692}
11693
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011694static int nl80211_nan_change_config(struct sk_buff *skb,
11695 struct genl_info *info)
11696{
11697 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11698 struct wireless_dev *wdev = info->user_ptr[1];
11699 struct cfg80211_nan_conf conf = {};
11700 u32 changed = 0;
11701
11702 if (wdev->iftype != NL80211_IFTYPE_NAN)
11703 return -EOPNOTSUPP;
11704
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011705 if (!wdev_running(wdev))
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011706 return -ENOTCONN;
11707
11708 if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
11709 conf.master_pref =
11710 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
11711 if (conf.master_pref <= 1 || conf.master_pref == 255)
11712 return -EINVAL;
11713
11714 changed |= CFG80211_NAN_CONF_CHANGED_PREF;
11715 }
11716
Luca Coelho85859892017-02-08 15:00:34 +020011717 if (info->attrs[NL80211_ATTR_BANDS]) {
11718 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
11719
11720 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
11721 return -EOPNOTSUPP;
11722
11723 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
11724 return -EINVAL;
11725
11726 conf.bands = bands;
11727 changed |= CFG80211_NAN_CONF_CHANGED_BANDS;
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011728 }
11729
11730 if (!changed)
11731 return -EINVAL;
11732
11733 return rdev_nan_change_conf(rdev, wdev, &conf, changed);
11734}
11735
Ayala Beker50bcd312016-09-20 17:31:17 +030011736void cfg80211_nan_match(struct wireless_dev *wdev,
11737 struct cfg80211_nan_match_params *match, gfp_t gfp)
11738{
11739 struct wiphy *wiphy = wdev->wiphy;
11740 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11741 struct nlattr *match_attr, *local_func_attr, *peer_func_attr;
11742 struct sk_buff *msg;
11743 void *hdr;
11744
11745 if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr))
11746 return;
11747
11748 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11749 if (!msg)
11750 return;
11751
11752 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH);
11753 if (!hdr) {
11754 nlmsg_free(msg);
11755 return;
11756 }
11757
11758 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11759 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11760 wdev->netdev->ifindex)) ||
11761 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11762 NL80211_ATTR_PAD))
11763 goto nla_put_failure;
11764
11765 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie,
11766 NL80211_ATTR_PAD) ||
11767 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr))
11768 goto nla_put_failure;
11769
11770 match_attr = nla_nest_start(msg, NL80211_ATTR_NAN_MATCH);
11771 if (!match_attr)
11772 goto nla_put_failure;
11773
11774 local_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_LOCAL);
11775 if (!local_func_attr)
11776 goto nla_put_failure;
11777
11778 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id))
11779 goto nla_put_failure;
11780
11781 nla_nest_end(msg, local_func_attr);
11782
11783 peer_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_PEER);
11784 if (!peer_func_attr)
11785 goto nla_put_failure;
11786
11787 if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) ||
11788 nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id))
11789 goto nla_put_failure;
11790
11791 if (match->info && match->info_len &&
11792 nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len,
11793 match->info))
11794 goto nla_put_failure;
11795
11796 nla_nest_end(msg, peer_func_attr);
11797 nla_nest_end(msg, match_attr);
11798 genlmsg_end(msg, hdr);
11799
11800 if (!wdev->owner_nlportid)
11801 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11802 msg, 0, NL80211_MCGRP_NAN, gfp);
11803 else
11804 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11805 wdev->owner_nlportid);
11806
11807 return;
11808
11809nla_put_failure:
11810 nlmsg_free(msg);
11811}
11812EXPORT_SYMBOL(cfg80211_nan_match);
11813
Ayala Beker368e5a72016-09-20 17:31:18 +030011814void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
11815 u8 inst_id,
11816 enum nl80211_nan_func_term_reason reason,
11817 u64 cookie, gfp_t gfp)
11818{
11819 struct wiphy *wiphy = wdev->wiphy;
11820 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11821 struct sk_buff *msg;
11822 struct nlattr *func_attr;
11823 void *hdr;
11824
11825 if (WARN_ON(!inst_id))
11826 return;
11827
11828 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11829 if (!msg)
11830 return;
11831
11832 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_NAN_FUNCTION);
11833 if (!hdr) {
11834 nlmsg_free(msg);
11835 return;
11836 }
11837
11838 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11839 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11840 wdev->netdev->ifindex)) ||
11841 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11842 NL80211_ATTR_PAD))
11843 goto nla_put_failure;
11844
11845 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
11846 NL80211_ATTR_PAD))
11847 goto nla_put_failure;
11848
11849 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11850 if (!func_attr)
11851 goto nla_put_failure;
11852
11853 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, inst_id) ||
11854 nla_put_u8(msg, NL80211_NAN_FUNC_TERM_REASON, reason))
11855 goto nla_put_failure;
11856
11857 nla_nest_end(msg, func_attr);
11858 genlmsg_end(msg, hdr);
11859
11860 if (!wdev->owner_nlportid)
11861 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11862 msg, 0, NL80211_MCGRP_NAN, gfp);
11863 else
11864 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11865 wdev->owner_nlportid);
11866
11867 return;
11868
11869nla_put_failure:
11870 nlmsg_free(msg);
11871}
11872EXPORT_SYMBOL(cfg80211_nan_func_terminated);
11873
Johannes Berg3713b4e2013-02-14 16:19:38 +010011874static int nl80211_get_protocol_features(struct sk_buff *skb,
11875 struct genl_info *info)
11876{
11877 void *hdr;
11878 struct sk_buff *msg;
11879
11880 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11881 if (!msg)
11882 return -ENOMEM;
11883
11884 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11885 NL80211_CMD_GET_PROTOCOL_FEATURES);
11886 if (!hdr)
11887 goto nla_put_failure;
11888
11889 if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
11890 NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
11891 goto nla_put_failure;
11892
11893 genlmsg_end(msg, hdr);
11894 return genlmsg_reply(msg, info);
11895
11896 nla_put_failure:
11897 kfree_skb(msg);
11898 return -ENOBUFS;
11899}
11900
Jouni Malinen355199e2013-02-27 17:14:27 +020011901static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
11902{
11903 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11904 struct cfg80211_update_ft_ies_params ft_params;
11905 struct net_device *dev = info->user_ptr[1];
11906
11907 if (!rdev->ops->update_ft_ies)
11908 return -EOPNOTSUPP;
11909
11910 if (!info->attrs[NL80211_ATTR_MDID] ||
11911 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
11912 return -EINVAL;
11913
11914 memset(&ft_params, 0, sizeof(ft_params));
11915 ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
11916 ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
11917 ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
11918
11919 return rdev_update_ft_ies(rdev, dev, &ft_params);
11920}
11921
Arend van Spriel5de17982013-04-18 15:49:00 +020011922static int nl80211_crit_protocol_start(struct sk_buff *skb,
11923 struct genl_info *info)
11924{
11925 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11926 struct wireless_dev *wdev = info->user_ptr[1];
11927 enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
11928 u16 duration;
11929 int ret;
11930
11931 if (!rdev->ops->crit_proto_start)
11932 return -EOPNOTSUPP;
11933
11934 if (WARN_ON(!rdev->ops->crit_proto_stop))
11935 return -EINVAL;
11936
11937 if (rdev->crit_proto_nlportid)
11938 return -EBUSY;
11939
11940 /* determine protocol if provided */
11941 if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
11942 proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
11943
11944 if (proto >= NUM_NL80211_CRIT_PROTO)
11945 return -EINVAL;
11946
11947 /* timeout must be provided */
11948 if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
11949 return -EINVAL;
11950
11951 duration =
11952 nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
11953
11954 if (duration > NL80211_CRIT_PROTO_MAX_DURATION)
11955 return -ERANGE;
11956
11957 ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
11958 if (!ret)
11959 rdev->crit_proto_nlportid = info->snd_portid;
11960
11961 return ret;
11962}
11963
11964static int nl80211_crit_protocol_stop(struct sk_buff *skb,
11965 struct genl_info *info)
11966{
11967 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11968 struct wireless_dev *wdev = info->user_ptr[1];
11969
11970 if (!rdev->ops->crit_proto_stop)
11971 return -EOPNOTSUPP;
11972
11973 if (rdev->crit_proto_nlportid) {
11974 rdev->crit_proto_nlportid = 0;
11975 rdev_crit_proto_stop(rdev, wdev);
11976 }
11977 return 0;
11978}
11979
Johannes Bergad7e7182013-11-13 13:37:47 +010011980static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
11981{
11982 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11983 struct wireless_dev *wdev =
11984 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
11985 int i, err;
11986 u32 vid, subcmd;
11987
11988 if (!rdev->wiphy.vendor_commands)
11989 return -EOPNOTSUPP;
11990
11991 if (IS_ERR(wdev)) {
11992 err = PTR_ERR(wdev);
11993 if (err != -EINVAL)
11994 return err;
11995 wdev = NULL;
11996 } else if (wdev->wiphy != &rdev->wiphy) {
11997 return -EINVAL;
11998 }
11999
12000 if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
12001 !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
12002 return -EINVAL;
12003
12004 vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
12005 subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
12006 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
12007 const struct wiphy_vendor_command *vcmd;
12008 void *data = NULL;
12009 int len = 0;
12010
12011 vcmd = &rdev->wiphy.vendor_commands[i];
12012
12013 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
12014 continue;
12015
12016 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
12017 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
12018 if (!wdev)
12019 return -EINVAL;
12020 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
12021 !wdev->netdev)
12022 return -EINVAL;
12023
12024 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012025 if (!wdev_running(wdev))
Johannes Bergad7e7182013-11-13 13:37:47 +010012026 return -ENETDOWN;
12027 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030012028
12029 if (!vcmd->doit)
12030 return -EOPNOTSUPP;
Johannes Bergad7e7182013-11-13 13:37:47 +010012031 } else {
12032 wdev = NULL;
12033 }
12034
12035 if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
12036 data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
12037 len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
12038 }
12039
12040 rdev->cur_cmd_info = info;
12041 err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
12042 data, len);
12043 rdev->cur_cmd_info = NULL;
12044 return err;
12045 }
12046
12047 return -EOPNOTSUPP;
12048}
12049
Johannes Berg7bdbe402015-08-15 22:39:49 +030012050static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
12051 struct netlink_callback *cb,
12052 struct cfg80211_registered_device **rdev,
12053 struct wireless_dev **wdev)
12054{
Johannes Bergc90c39d2016-10-24 14:40:01 +020012055 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
Johannes Berg7bdbe402015-08-15 22:39:49 +030012056 u32 vid, subcmd;
12057 unsigned int i;
12058 int vcmd_idx = -1;
12059 int err;
12060 void *data = NULL;
12061 unsigned int data_len = 0;
12062
Johannes Berg7bdbe402015-08-15 22:39:49 +030012063 if (cb->args[0]) {
12064 /* subtract the 1 again here */
12065 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
12066 struct wireless_dev *tmp;
12067
Johannes Bergea90e0d2017-03-15 14:26:04 +010012068 if (!wiphy)
12069 return -ENODEV;
Johannes Berg7bdbe402015-08-15 22:39:49 +030012070 *rdev = wiphy_to_rdev(wiphy);
12071 *wdev = NULL;
12072
12073 if (cb->args[1]) {
Johannes Berg53873f12016-05-03 16:52:04 +030012074 list_for_each_entry(tmp, &wiphy->wdev_list, list) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030012075 if (tmp->identifier == cb->args[1] - 1) {
12076 *wdev = tmp;
12077 break;
12078 }
12079 }
12080 }
12081
12082 /* keep rtnl locked in successful case */
12083 return 0;
12084 }
12085
Johannes Bergfceb6432017-04-12 14:34:07 +020012086 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, attrbuf,
12087 nl80211_fam.maxattr, nl80211_policy, NULL);
Johannes Berg7bdbe402015-08-15 22:39:49 +030012088 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +010012089 return err;
Johannes Berg7bdbe402015-08-15 22:39:49 +030012090
Johannes Bergc90c39d2016-10-24 14:40:01 +020012091 if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
Johannes Bergea90e0d2017-03-15 14:26:04 +010012092 !attrbuf[NL80211_ATTR_VENDOR_SUBCMD])
12093 return -EINVAL;
Johannes Berg7bdbe402015-08-15 22:39:49 +030012094
Johannes Bergc90c39d2016-10-24 14:40:01 +020012095 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg7bdbe402015-08-15 22:39:49 +030012096 if (IS_ERR(*wdev))
12097 *wdev = NULL;
12098
Johannes Bergc90c39d2016-10-24 14:40:01 +020012099 *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Bergea90e0d2017-03-15 14:26:04 +010012100 if (IS_ERR(*rdev))
12101 return PTR_ERR(*rdev);
Johannes Berg7bdbe402015-08-15 22:39:49 +030012102
Johannes Bergc90c39d2016-10-24 14:40:01 +020012103 vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
12104 subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030012105
12106 for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
12107 const struct wiphy_vendor_command *vcmd;
12108
12109 vcmd = &(*rdev)->wiphy.vendor_commands[i];
12110
12111 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
12112 continue;
12113
Johannes Bergea90e0d2017-03-15 14:26:04 +010012114 if (!vcmd->dumpit)
12115 return -EOPNOTSUPP;
Johannes Berg7bdbe402015-08-15 22:39:49 +030012116
12117 vcmd_idx = i;
12118 break;
12119 }
12120
Johannes Bergea90e0d2017-03-15 14:26:04 +010012121 if (vcmd_idx < 0)
12122 return -EOPNOTSUPP;
Johannes Berg7bdbe402015-08-15 22:39:49 +030012123
Johannes Bergc90c39d2016-10-24 14:40:01 +020012124 if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
12125 data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
12126 data_len = nla_len(attrbuf[NL80211_ATTR_VENDOR_DATA]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030012127 }
12128
12129 /* 0 is the first index - add 1 to parse only once */
12130 cb->args[0] = (*rdev)->wiphy_idx + 1;
12131 /* add 1 to know if it was NULL */
12132 cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
12133 cb->args[2] = vcmd_idx;
12134 cb->args[3] = (unsigned long)data;
12135 cb->args[4] = data_len;
12136
12137 /* keep rtnl locked in successful case */
12138 return 0;
Johannes Berg7bdbe402015-08-15 22:39:49 +030012139}
12140
12141static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
12142 struct netlink_callback *cb)
12143{
12144 struct cfg80211_registered_device *rdev;
12145 struct wireless_dev *wdev;
12146 unsigned int vcmd_idx;
12147 const struct wiphy_vendor_command *vcmd;
12148 void *data;
12149 int data_len;
12150 int err;
12151 struct nlattr *vendor_data;
12152
Johannes Bergea90e0d2017-03-15 14:26:04 +010012153 rtnl_lock();
Johannes Berg7bdbe402015-08-15 22:39:49 +030012154 err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
12155 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +010012156 goto out;
Johannes Berg7bdbe402015-08-15 22:39:49 +030012157
12158 vcmd_idx = cb->args[2];
12159 data = (void *)cb->args[3];
12160 data_len = cb->args[4];
12161 vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
12162
12163 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
12164 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
Johannes Bergea90e0d2017-03-15 14:26:04 +010012165 if (!wdev) {
12166 err = -EINVAL;
12167 goto out;
12168 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030012169 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
Johannes Bergea90e0d2017-03-15 14:26:04 +010012170 !wdev->netdev) {
12171 err = -EINVAL;
12172 goto out;
12173 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030012174
12175 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Johannes Bergea90e0d2017-03-15 14:26:04 +010012176 if (!wdev_running(wdev)) {
12177 err = -ENETDOWN;
12178 goto out;
12179 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030012180 }
12181 }
12182
12183 while (1) {
12184 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
12185 cb->nlh->nlmsg_seq, NLM_F_MULTI,
12186 NL80211_CMD_VENDOR);
12187 if (!hdr)
12188 break;
12189
12190 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020012191 (wdev && nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
12192 wdev_id(wdev),
12193 NL80211_ATTR_PAD))) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030012194 genlmsg_cancel(skb, hdr);
12195 break;
12196 }
12197
12198 vendor_data = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
12199 if (!vendor_data) {
12200 genlmsg_cancel(skb, hdr);
12201 break;
12202 }
12203
12204 err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
12205 (unsigned long *)&cb->args[5]);
12206 nla_nest_end(skb, vendor_data);
12207
12208 if (err == -ENOBUFS || err == -ENOENT) {
12209 genlmsg_cancel(skb, hdr);
12210 break;
12211 } else if (err) {
12212 genlmsg_cancel(skb, hdr);
12213 goto out;
12214 }
12215
12216 genlmsg_end(skb, hdr);
12217 }
12218
12219 err = skb->len;
12220 out:
12221 rtnl_unlock();
12222 return err;
12223}
12224
Johannes Bergad7e7182013-11-13 13:37:47 +010012225struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
12226 enum nl80211_commands cmd,
12227 enum nl80211_attrs attr,
12228 int approxlen)
12229{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080012230 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Bergad7e7182013-11-13 13:37:47 +010012231
12232 if (WARN_ON(!rdev->cur_cmd_info))
12233 return NULL;
12234
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020012235 return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
Johannes Bergad7e7182013-11-13 13:37:47 +010012236 rdev->cur_cmd_info->snd_portid,
12237 rdev->cur_cmd_info->snd_seq,
Johannes Berg567ffc32013-12-18 14:43:31 +010012238 cmd, attr, NULL, GFP_KERNEL);
Johannes Bergad7e7182013-11-13 13:37:47 +010012239}
12240EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
12241
12242int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
12243{
12244 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
12245 void *hdr = ((void **)skb->cb)[1];
12246 struct nlattr *data = ((void **)skb->cb)[2];
12247
Johannes Bergbd8c78e2014-07-30 14:55:26 +020012248 /* clear CB data for netlink core to own from now on */
12249 memset(skb->cb, 0, sizeof(skb->cb));
12250
Johannes Bergad7e7182013-11-13 13:37:47 +010012251 if (WARN_ON(!rdev->cur_cmd_info)) {
12252 kfree_skb(skb);
12253 return -EINVAL;
12254 }
12255
12256 nla_nest_end(skb, data);
12257 genlmsg_end(skb, hdr);
12258 return genlmsg_reply(skb, rdev->cur_cmd_info);
12259}
12260EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
12261
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080012262static int nl80211_set_qos_map(struct sk_buff *skb,
12263 struct genl_info *info)
12264{
12265 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12266 struct cfg80211_qos_map *qos_map = NULL;
12267 struct net_device *dev = info->user_ptr[1];
12268 u8 *pos, len, num_des, des_len, des;
12269 int ret;
12270
12271 if (!rdev->ops->set_qos_map)
12272 return -EOPNOTSUPP;
12273
12274 if (info->attrs[NL80211_ATTR_QOS_MAP]) {
12275 pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
12276 len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
12277
12278 if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
12279 len > IEEE80211_QOS_MAP_LEN_MAX)
12280 return -EINVAL;
12281
12282 qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
12283 if (!qos_map)
12284 return -ENOMEM;
12285
12286 num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
12287 if (num_des) {
12288 des_len = num_des *
12289 sizeof(struct cfg80211_dscp_exception);
12290 memcpy(qos_map->dscp_exception, pos, des_len);
12291 qos_map->num_des = num_des;
12292 for (des = 0; des < num_des; des++) {
12293 if (qos_map->dscp_exception[des].up > 7) {
12294 kfree(qos_map);
12295 return -EINVAL;
12296 }
12297 }
12298 pos += des_len;
12299 }
12300 memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
12301 }
12302
12303 wdev_lock(dev->ieee80211_ptr);
12304 ret = nl80211_key_allowed(dev->ieee80211_ptr);
12305 if (!ret)
12306 ret = rdev_set_qos_map(rdev, dev, qos_map);
12307 wdev_unlock(dev->ieee80211_ptr);
12308
12309 kfree(qos_map);
12310 return ret;
12311}
12312
Johannes Berg960d01a2014-09-09 22:55:35 +030012313static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
12314{
12315 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12316 struct net_device *dev = info->user_ptr[1];
12317 struct wireless_dev *wdev = dev->ieee80211_ptr;
12318 const u8 *peer;
12319 u8 tsid, up;
12320 u16 admitted_time = 0;
12321 int err;
12322
Johannes Berg723e73a2014-10-22 09:25:06 +020012323 if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
Johannes Berg960d01a2014-09-09 22:55:35 +030012324 return -EOPNOTSUPP;
12325
12326 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
12327 !info->attrs[NL80211_ATTR_USER_PRIO])
12328 return -EINVAL;
12329
12330 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
12331 if (tsid >= IEEE80211_NUM_TIDS)
12332 return -EINVAL;
12333
12334 up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
12335 if (up >= IEEE80211_NUM_UPS)
12336 return -EINVAL;
12337
12338 /* WMM uses TIDs 0-7 even for TSPEC */
Johannes Berg723e73a2014-10-22 09:25:06 +020012339 if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
Johannes Berg960d01a2014-09-09 22:55:35 +030012340 /* TODO: handle 802.11 TSPEC/admission control
Johannes Berg723e73a2014-10-22 09:25:06 +020012341 * need more attributes for that (e.g. BA session requirement);
12342 * change the WMM adminssion test above to allow both then
Johannes Berg960d01a2014-09-09 22:55:35 +030012343 */
12344 return -EINVAL;
12345 }
12346
12347 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
12348
12349 if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
12350 admitted_time =
12351 nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
12352 if (!admitted_time)
12353 return -EINVAL;
12354 }
12355
12356 wdev_lock(wdev);
12357 switch (wdev->iftype) {
12358 case NL80211_IFTYPE_STATION:
12359 case NL80211_IFTYPE_P2P_CLIENT:
12360 if (wdev->current_bss)
12361 break;
12362 err = -ENOTCONN;
12363 goto out;
12364 default:
12365 err = -EOPNOTSUPP;
12366 goto out;
12367 }
12368
12369 err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
12370
12371 out:
12372 wdev_unlock(wdev);
12373 return err;
12374}
12375
12376static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
12377{
12378 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12379 struct net_device *dev = info->user_ptr[1];
12380 struct wireless_dev *wdev = dev->ieee80211_ptr;
12381 const u8 *peer;
12382 u8 tsid;
12383 int err;
12384
12385 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
12386 return -EINVAL;
12387
12388 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
12389 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
12390
12391 wdev_lock(wdev);
12392 err = rdev_del_tx_ts(rdev, dev, tsid, peer);
12393 wdev_unlock(wdev);
12394
12395 return err;
12396}
12397
Arik Nemtsov1057d352014-11-19 12:54:26 +020012398static int nl80211_tdls_channel_switch(struct sk_buff *skb,
12399 struct genl_info *info)
12400{
12401 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12402 struct net_device *dev = info->user_ptr[1];
12403 struct wireless_dev *wdev = dev->ieee80211_ptr;
12404 struct cfg80211_chan_def chandef = {};
12405 const u8 *addr;
12406 u8 oper_class;
12407 int err;
12408
12409 if (!rdev->ops->tdls_channel_switch ||
12410 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
12411 return -EOPNOTSUPP;
12412
12413 switch (dev->ieee80211_ptr->iftype) {
12414 case NL80211_IFTYPE_STATION:
12415 case NL80211_IFTYPE_P2P_CLIENT:
12416 break;
12417 default:
12418 return -EOPNOTSUPP;
12419 }
12420
12421 if (!info->attrs[NL80211_ATTR_MAC] ||
12422 !info->attrs[NL80211_ATTR_OPER_CLASS])
12423 return -EINVAL;
12424
12425 err = nl80211_parse_chandef(rdev, info, &chandef);
12426 if (err)
12427 return err;
12428
12429 /*
12430 * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012
12431 * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the
12432 * specification is not defined for them.
12433 */
Johannes Berg57fbcce2016-04-12 15:56:15 +020012434 if (chandef.chan->band == NL80211_BAND_2GHZ &&
Arik Nemtsov1057d352014-11-19 12:54:26 +020012435 chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
12436 chandef.width != NL80211_CHAN_WIDTH_20)
12437 return -EINVAL;
12438
12439 /* we will be active on the TDLS link */
Arik Nemtsov923b3522015-07-08 15:41:44 +030012440 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
12441 wdev->iftype))
Arik Nemtsov1057d352014-11-19 12:54:26 +020012442 return -EINVAL;
12443
12444 /* don't allow switching to DFS channels */
12445 if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype))
12446 return -EINVAL;
12447
12448 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
12449 oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]);
12450
12451 wdev_lock(wdev);
12452 err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef);
12453 wdev_unlock(wdev);
12454
12455 return err;
12456}
12457
12458static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
12459 struct genl_info *info)
12460{
12461 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12462 struct net_device *dev = info->user_ptr[1];
12463 struct wireless_dev *wdev = dev->ieee80211_ptr;
12464 const u8 *addr;
12465
12466 if (!rdev->ops->tdls_channel_switch ||
12467 !rdev->ops->tdls_cancel_channel_switch ||
12468 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
12469 return -EOPNOTSUPP;
12470
12471 switch (dev->ieee80211_ptr->iftype) {
12472 case NL80211_IFTYPE_STATION:
12473 case NL80211_IFTYPE_P2P_CLIENT:
12474 break;
12475 default:
12476 return -EOPNOTSUPP;
12477 }
12478
12479 if (!info->attrs[NL80211_ATTR_MAC])
12480 return -EINVAL;
12481
12482 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
12483
12484 wdev_lock(wdev);
12485 rdev_tdls_cancel_channel_switch(rdev, dev, addr);
12486 wdev_unlock(wdev);
12487
12488 return 0;
12489}
12490
Michael Braunce0ce132016-10-10 19:12:22 +020012491static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
12492 struct genl_info *info)
12493{
12494 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12495 struct net_device *dev = info->user_ptr[1];
12496 struct wireless_dev *wdev = dev->ieee80211_ptr;
12497 const struct nlattr *nla;
12498 bool enabled;
12499
Michael Braunce0ce132016-10-10 19:12:22 +020012500 if (!rdev->ops->set_multicast_to_unicast)
12501 return -EOPNOTSUPP;
12502
12503 if (wdev->iftype != NL80211_IFTYPE_AP &&
12504 wdev->iftype != NL80211_IFTYPE_P2P_GO)
12505 return -EOPNOTSUPP;
12506
12507 nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
12508 enabled = nla_get_flag(nla);
12509
12510 return rdev_set_multicast_to_unicast(rdev, dev, enabled);
12511}
12512
Avraham Stern3a00df52017-06-09 13:08:43 +010012513static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
12514{
12515 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12516 struct net_device *dev = info->user_ptr[1];
12517 struct wireless_dev *wdev = dev->ieee80211_ptr;
12518 struct cfg80211_pmk_conf pmk_conf = {};
12519 int ret;
12520
12521 if (wdev->iftype != NL80211_IFTYPE_STATION &&
12522 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
12523 return -EOPNOTSUPP;
12524
12525 if (!wiphy_ext_feature_isset(&rdev->wiphy,
12526 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
12527 return -EOPNOTSUPP;
12528
12529 if (!info->attrs[NL80211_ATTR_MAC] || !info->attrs[NL80211_ATTR_PMK])
12530 return -EINVAL;
12531
12532 wdev_lock(wdev);
12533 if (!wdev->current_bss) {
12534 ret = -ENOTCONN;
12535 goto out;
12536 }
12537
12538 pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
12539 if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) {
12540 ret = -EINVAL;
12541 goto out;
12542 }
12543
12544 pmk_conf.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
12545 pmk_conf.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
12546 if (pmk_conf.pmk_len != WLAN_PMK_LEN &&
12547 pmk_conf.pmk_len != WLAN_PMK_LEN_SUITE_B_192) {
12548 ret = -EINVAL;
12549 goto out;
12550 }
12551
12552 if (info->attrs[NL80211_ATTR_PMKR0_NAME]) {
12553 int r0_name_len = nla_len(info->attrs[NL80211_ATTR_PMKR0_NAME]);
12554
12555 if (r0_name_len != WLAN_PMK_NAME_LEN) {
12556 ret = -EINVAL;
12557 goto out;
12558 }
12559
12560 pmk_conf.pmk_r0_name =
12561 nla_data(info->attrs[NL80211_ATTR_PMKR0_NAME]);
12562 }
12563
12564 ret = rdev_set_pmk(rdev, dev, &pmk_conf);
12565out:
12566 wdev_unlock(wdev);
12567 return ret;
12568}
12569
12570static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
12571{
12572 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12573 struct net_device *dev = info->user_ptr[1];
12574 struct wireless_dev *wdev = dev->ieee80211_ptr;
12575 const u8 *aa;
12576 int ret;
12577
12578 if (wdev->iftype != NL80211_IFTYPE_STATION &&
12579 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
12580 return -EOPNOTSUPP;
12581
12582 if (!wiphy_ext_feature_isset(&rdev->wiphy,
12583 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
12584 return -EOPNOTSUPP;
12585
12586 if (!info->attrs[NL80211_ATTR_MAC])
12587 return -EINVAL;
12588
12589 wdev_lock(wdev);
12590 aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
12591 ret = rdev_del_pmk(rdev, dev, aa);
12592 wdev_unlock(wdev);
12593
12594 return ret;
12595}
12596
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020012597static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info)
12598{
12599 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12600 struct net_device *dev = info->user_ptr[1];
12601 struct cfg80211_external_auth_params params;
12602
Srinivas Dasaridb8d93a2018-02-02 11:15:27 +020012603 if (!rdev->ops->external_auth)
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020012604 return -EOPNOTSUPP;
12605
12606 if (!info->attrs[NL80211_ATTR_SSID])
12607 return -EINVAL;
12608
12609 if (!info->attrs[NL80211_ATTR_BSSID])
12610 return -EINVAL;
12611
12612 if (!info->attrs[NL80211_ATTR_STATUS_CODE])
12613 return -EINVAL;
12614
12615 memset(&params, 0, sizeof(params));
12616
12617 params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
12618 if (params.ssid.ssid_len == 0 ||
12619 params.ssid.ssid_len > IEEE80211_MAX_SSID_LEN)
12620 return -EINVAL;
12621 memcpy(params.ssid.ssid, nla_data(info->attrs[NL80211_ATTR_SSID]),
12622 params.ssid.ssid_len);
12623
12624 memcpy(params.bssid, nla_data(info->attrs[NL80211_ATTR_BSSID]),
12625 ETH_ALEN);
12626
12627 params.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
12628
12629 return rdev_external_auth(rdev, dev, &params);
12630}
12631
Denis Kenzior2576a9a2018-03-26 12:52:42 -050012632static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
12633{
12634 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12635 struct net_device *dev = info->user_ptr[1];
12636 struct wireless_dev *wdev = dev->ieee80211_ptr;
12637 const u8 *buf;
12638 size_t len;
12639 u8 *dest;
12640 u16 proto;
12641 bool noencrypt;
12642 int err;
12643
12644 if (!wiphy_ext_feature_isset(&rdev->wiphy,
12645 NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
12646 return -EOPNOTSUPP;
12647
12648 if (!rdev->ops->tx_control_port)
12649 return -EOPNOTSUPP;
12650
12651 if (!info->attrs[NL80211_ATTR_FRAME] ||
12652 !info->attrs[NL80211_ATTR_MAC] ||
12653 !info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
12654 GENL_SET_ERR_MSG(info, "Frame, MAC or ethertype missing");
12655 return -EINVAL;
12656 }
12657
12658 wdev_lock(wdev);
12659
12660 switch (wdev->iftype) {
12661 case NL80211_IFTYPE_AP:
12662 case NL80211_IFTYPE_P2P_GO:
12663 case NL80211_IFTYPE_MESH_POINT:
12664 break;
12665 case NL80211_IFTYPE_ADHOC:
12666 case NL80211_IFTYPE_STATION:
12667 case NL80211_IFTYPE_P2P_CLIENT:
12668 if (wdev->current_bss)
12669 break;
12670 err = -ENOTCONN;
12671 goto out;
12672 default:
12673 err = -EOPNOTSUPP;
12674 goto out;
12675 }
12676
12677 wdev_unlock(wdev);
12678
12679 buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
12680 len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
12681 dest = nla_data(info->attrs[NL80211_ATTR_MAC]);
12682 proto = nla_get_u16(info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
12683 noencrypt =
12684 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);
12685
12686 return rdev_tx_control_port(rdev, dev, buf, len,
12687 dest, cpu_to_be16(proto), noencrypt);
12688
12689 out:
12690 wdev_unlock(wdev);
12691 return err;
12692}
12693
Johannes Berg4c476992010-10-04 21:36:35 +020012694#define NL80211_FLAG_NEED_WIPHY 0x01
12695#define NL80211_FLAG_NEED_NETDEV 0x02
12696#define NL80211_FLAG_NEED_RTNL 0x04
Johannes Berg41265712010-10-04 21:14:05 +020012697#define NL80211_FLAG_CHECK_NETDEV_UP 0x08
12698#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
12699 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg1bf614e2012-06-15 15:23:36 +020012700#define NL80211_FLAG_NEED_WDEV 0x10
Johannes Berg98104fde2012-06-16 00:19:54 +020012701/* If a netdev is associated, it must be UP, P2P must be started */
Johannes Berg1bf614e2012-06-15 15:23:36 +020012702#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
12703 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg5393b912014-09-10 15:00:16 +030012704#define NL80211_FLAG_CLEAR_SKB 0x20
Johannes Berg4c476992010-10-04 21:36:35 +020012705
Johannes Bergf84f7712013-11-14 17:14:45 +010012706static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020012707 struct genl_info *info)
12708{
12709 struct cfg80211_registered_device *rdev;
Johannes Berg89a54e42012-06-15 14:33:17 +020012710 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020012711 struct net_device *dev;
Johannes Berg4c476992010-10-04 21:36:35 +020012712 bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
12713
12714 if (rtnl)
12715 rtnl_lock();
12716
12717 if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
Johannes Berg4f7eff12012-06-15 14:14:22 +020012718 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
Johannes Berg4c476992010-10-04 21:36:35 +020012719 if (IS_ERR(rdev)) {
12720 if (rtnl)
12721 rtnl_unlock();
12722 return PTR_ERR(rdev);
12723 }
12724 info->user_ptr[0] = rdev;
Johannes Berg1bf614e2012-06-15 15:23:36 +020012725 } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
12726 ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
Johannes Berg5fe231e2013-05-08 21:45:15 +020012727 ASSERT_RTNL();
12728
Johannes Berg89a54e42012-06-15 14:33:17 +020012729 wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
12730 info->attrs);
12731 if (IS_ERR(wdev)) {
Johannes Berg4c476992010-10-04 21:36:35 +020012732 if (rtnl)
12733 rtnl_unlock();
Johannes Berg89a54e42012-06-15 14:33:17 +020012734 return PTR_ERR(wdev);
Johannes Berg4c476992010-10-04 21:36:35 +020012735 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012736
Johannes Berg89a54e42012-06-15 14:33:17 +020012737 dev = wdev->netdev;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080012738 rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg89a54e42012-06-15 14:33:17 +020012739
Johannes Berg1bf614e2012-06-15 15:23:36 +020012740 if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
12741 if (!dev) {
Johannes Berg1bf614e2012-06-15 15:23:36 +020012742 if (rtnl)
12743 rtnl_unlock();
12744 return -EINVAL;
12745 }
12746
12747 info->user_ptr[1] = dev;
12748 } else {
12749 info->user_ptr[1] = wdev;
Johannes Berg41265712010-10-04 21:14:05 +020012750 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012751
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012752 if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
12753 !wdev_running(wdev)) {
12754 if (rtnl)
12755 rtnl_unlock();
12756 return -ENETDOWN;
Johannes Berg1bf614e2012-06-15 15:23:36 +020012757 }
12758
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012759 if (dev)
12760 dev_hold(dev);
12761
Johannes Berg4c476992010-10-04 21:36:35 +020012762 info->user_ptr[0] = rdev;
Johannes Berg4c476992010-10-04 21:36:35 +020012763 }
12764
12765 return 0;
12766}
12767
Johannes Bergf84f7712013-11-14 17:14:45 +010012768static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020012769 struct genl_info *info)
12770{
Johannes Berg1bf614e2012-06-15 15:23:36 +020012771 if (info->user_ptr[1]) {
12772 if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
12773 struct wireless_dev *wdev = info->user_ptr[1];
12774
12775 if (wdev->netdev)
12776 dev_put(wdev->netdev);
12777 } else {
12778 dev_put(info->user_ptr[1]);
12779 }
12780 }
Johannes Berg5393b912014-09-10 15:00:16 +030012781
Johannes Berg4c476992010-10-04 21:36:35 +020012782 if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
12783 rtnl_unlock();
Johannes Berg5393b912014-09-10 15:00:16 +030012784
12785 /* If needed, clear the netlink message payload from the SKB
12786 * as it might contain key data that shouldn't stick around on
12787 * the heap after the SKB is freed. The netlink message header
12788 * is still needed for further processing, so leave it intact.
12789 */
12790 if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) {
12791 struct nlmsghdr *nlh = nlmsg_hdr(skb);
12792
12793 memset(nlmsg_data(nlh), 0, nlmsg_len(nlh));
12794 }
Johannes Berg4c476992010-10-04 21:36:35 +020012795}
12796
Johannes Berg4534de82013-11-14 17:14:46 +010012797static const struct genl_ops nl80211_ops[] = {
Johannes Berg55682962007-09-20 13:09:35 -040012798 {
12799 .cmd = NL80211_CMD_GET_WIPHY,
12800 .doit = nl80211_get_wiphy,
12801 .dumpit = nl80211_dump_wiphy,
Johannes Berg86e8cf92013-06-19 10:57:22 +020012802 .done = nl80211_dump_wiphy_done,
Johannes Berg55682962007-09-20 13:09:35 -040012803 .policy = nl80211_policy,
12804 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012805 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12806 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012807 },
12808 {
12809 .cmd = NL80211_CMD_SET_WIPHY,
12810 .doit = nl80211_set_wiphy,
12811 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012812 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012813 .internal_flags = NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012814 },
12815 {
12816 .cmd = NL80211_CMD_GET_INTERFACE,
12817 .doit = nl80211_get_interface,
12818 .dumpit = nl80211_dump_interface,
12819 .policy = nl80211_policy,
12820 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012821 .internal_flags = NL80211_FLAG_NEED_WDEV |
12822 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012823 },
12824 {
12825 .cmd = NL80211_CMD_SET_INTERFACE,
12826 .doit = nl80211_set_interface,
12827 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012828 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012829 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12830 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012831 },
12832 {
12833 .cmd = NL80211_CMD_NEW_INTERFACE,
12834 .doit = nl80211_new_interface,
12835 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012836 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012837 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12838 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012839 },
12840 {
12841 .cmd = NL80211_CMD_DEL_INTERFACE,
12842 .doit = nl80211_del_interface,
12843 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012844 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg84efbb82012-06-16 00:00:26 +020012845 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012846 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012847 },
Johannes Berg41ade002007-12-19 02:03:29 +010012848 {
12849 .cmd = NL80211_CMD_GET_KEY,
12850 .doit = nl80211_get_key,
12851 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012852 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012853 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012854 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012855 },
12856 {
12857 .cmd = NL80211_CMD_SET_KEY,
12858 .doit = nl80211_set_key,
12859 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012860 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012861 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012862 NL80211_FLAG_NEED_RTNL |
12863 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012864 },
12865 {
12866 .cmd = NL80211_CMD_NEW_KEY,
12867 .doit = nl80211_new_key,
12868 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012869 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012870 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012871 NL80211_FLAG_NEED_RTNL |
12872 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012873 },
12874 {
12875 .cmd = NL80211_CMD_DEL_KEY,
12876 .doit = nl80211_del_key,
12877 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012878 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012879 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012880 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012881 },
Johannes Berged1b6cc2007-12-19 02:03:32 +010012882 {
12883 .cmd = NL80211_CMD_SET_BEACON,
12884 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012885 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012886 .doit = nl80211_set_beacon,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012887 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012888 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012889 },
12890 {
Johannes Berg88600202012-02-13 15:17:18 +010012891 .cmd = NL80211_CMD_START_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012892 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012893 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012894 .doit = nl80211_start_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012895 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012896 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012897 },
12898 {
Johannes Berg88600202012-02-13 15:17:18 +010012899 .cmd = NL80211_CMD_STOP_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012900 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012901 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012902 .doit = nl80211_stop_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012903 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012904 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012905 },
Johannes Berg5727ef12007-12-19 02:03:34 +010012906 {
12907 .cmd = NL80211_CMD_GET_STATION,
12908 .doit = nl80211_get_station,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012909 .dumpit = nl80211_dump_station,
Johannes Berg5727ef12007-12-19 02:03:34 +010012910 .policy = nl80211_policy,
Johannes Berg4c476992010-10-04 21:36:35 +020012911 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12912 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012913 },
12914 {
12915 .cmd = NL80211_CMD_SET_STATION,
12916 .doit = nl80211_set_station,
12917 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012918 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012919 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012920 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012921 },
12922 {
12923 .cmd = NL80211_CMD_NEW_STATION,
12924 .doit = nl80211_new_station,
12925 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012926 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012927 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012928 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012929 },
12930 {
12931 .cmd = NL80211_CMD_DEL_STATION,
12932 .doit = nl80211_del_station,
12933 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012934 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012935 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012936 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012937 },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012938 {
12939 .cmd = NL80211_CMD_GET_MPATH,
12940 .doit = nl80211_get_mpath,
12941 .dumpit = nl80211_dump_mpath,
12942 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012943 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012944 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012945 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012946 },
12947 {
Henning Rogge66be7d22014-09-12 08:58:49 +020012948 .cmd = NL80211_CMD_GET_MPP,
12949 .doit = nl80211_get_mpp,
12950 .dumpit = nl80211_dump_mpp,
12951 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012952 .flags = GENL_UNS_ADMIN_PERM,
Henning Rogge66be7d22014-09-12 08:58:49 +020012953 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12954 NL80211_FLAG_NEED_RTNL,
12955 },
12956 {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012957 .cmd = NL80211_CMD_SET_MPATH,
12958 .doit = nl80211_set_mpath,
12959 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012960 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012961 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012962 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012963 },
12964 {
12965 .cmd = NL80211_CMD_NEW_MPATH,
12966 .doit = nl80211_new_mpath,
12967 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012968 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012969 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012970 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012971 },
12972 {
12973 .cmd = NL80211_CMD_DEL_MPATH,
12974 .doit = nl80211_del_mpath,
12975 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012976 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012977 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012978 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012979 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012980 {
12981 .cmd = NL80211_CMD_SET_BSS,
12982 .doit = nl80211_set_bss,
12983 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012984 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012985 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012986 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012987 },
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012988 {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012989 .cmd = NL80211_CMD_GET_REG,
Arik Nemtsovad30ca22014-12-15 19:25:59 +020012990 .doit = nl80211_get_reg_do,
12991 .dumpit = nl80211_get_reg_dump,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012992 .policy = nl80211_policy,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012993 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012994 /* can be retrieved by unprivileged users */
12995 },
Johannes Bergb6863032015-10-15 09:25:18 +020012996#ifdef CONFIG_CFG80211_CRDA_SUPPORT
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012997 {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012998 .cmd = NL80211_CMD_SET_REG,
12999 .doit = nl80211_set_reg,
13000 .policy = nl80211_policy,
13001 .flags = GENL_ADMIN_PERM,
Johannes Berg5fe231e2013-05-08 21:45:15 +020013002 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070013003 },
Johannes Bergb6863032015-10-15 09:25:18 +020013004#endif
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070013005 {
13006 .cmd = NL80211_CMD_REQ_SET_REG,
13007 .doit = nl80211_req_set_reg,
13008 .policy = nl80211_policy,
13009 .flags = GENL_ADMIN_PERM,
13010 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070013011 {
Johannes Berg1ea4ff32017-09-13 16:07:22 +020013012 .cmd = NL80211_CMD_RELOAD_REGDB,
13013 .doit = nl80211_reload_regdb,
13014 .policy = nl80211_policy,
13015 .flags = GENL_ADMIN_PERM,
13016 },
13017 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080013018 .cmd = NL80211_CMD_GET_MESH_CONFIG,
13019 .doit = nl80211_get_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070013020 .policy = nl80211_policy,
13021 /* can be retrieved by unprivileged users */
Johannes Berg2b5f8b02012-04-02 10:51:55 +020013022 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013023 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070013024 },
13025 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080013026 .cmd = NL80211_CMD_SET_MESH_CONFIG,
13027 .doit = nl80211_update_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070013028 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013029 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010013030 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013031 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070013032 },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +020013033 {
Johannes Berg2a519312009-02-10 21:25:55 +010013034 .cmd = NL80211_CMD_TRIGGER_SCAN,
13035 .doit = nl80211_trigger_scan,
13036 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013037 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergfd014282012-06-18 19:17:03 +020013038 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013039 NL80211_FLAG_NEED_RTNL,
Johannes Berg2a519312009-02-10 21:25:55 +010013040 },
13041 {
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053013042 .cmd = NL80211_CMD_ABORT_SCAN,
13043 .doit = nl80211_abort_scan,
13044 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013045 .flags = GENL_UNS_ADMIN_PERM,
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053013046 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13047 NL80211_FLAG_NEED_RTNL,
13048 },
13049 {
Johannes Berg2a519312009-02-10 21:25:55 +010013050 .cmd = NL80211_CMD_GET_SCAN,
13051 .policy = nl80211_policy,
13052 .dumpit = nl80211_dump_scan,
13053 },
Jouni Malinen636a5d32009-03-19 13:39:22 +020013054 {
Luciano Coelho807f8a82011-05-11 17:09:35 +030013055 .cmd = NL80211_CMD_START_SCHED_SCAN,
13056 .doit = nl80211_start_sched_scan,
13057 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013058 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030013059 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13060 NL80211_FLAG_NEED_RTNL,
13061 },
13062 {
13063 .cmd = NL80211_CMD_STOP_SCHED_SCAN,
13064 .doit = nl80211_stop_sched_scan,
13065 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013066 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030013067 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13068 NL80211_FLAG_NEED_RTNL,
13069 },
13070 {
Jouni Malinen636a5d32009-03-19 13:39:22 +020013071 .cmd = NL80211_CMD_AUTHENTICATE,
13072 .doit = nl80211_authenticate,
13073 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013074 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020013075 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030013076 NL80211_FLAG_NEED_RTNL |
13077 NL80211_FLAG_CLEAR_SKB,
Jouni Malinen636a5d32009-03-19 13:39:22 +020013078 },
13079 {
13080 .cmd = NL80211_CMD_ASSOCIATE,
13081 .doit = nl80211_associate,
13082 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013083 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020013084 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013085 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020013086 },
13087 {
13088 .cmd = NL80211_CMD_DEAUTHENTICATE,
13089 .doit = nl80211_deauthenticate,
13090 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013091 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020013092 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013093 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020013094 },
13095 {
13096 .cmd = NL80211_CMD_DISASSOCIATE,
13097 .doit = nl80211_disassociate,
13098 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013099 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020013100 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013101 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020013102 },
Johannes Berg04a773a2009-04-19 21:24:32 +020013103 {
13104 .cmd = NL80211_CMD_JOIN_IBSS,
13105 .doit = nl80211_join_ibss,
13106 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013107 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020013108 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013109 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020013110 },
13111 {
13112 .cmd = NL80211_CMD_LEAVE_IBSS,
13113 .doit = nl80211_leave_ibss,
13114 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013115 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020013116 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013117 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020013118 },
Johannes Bergaff89a92009-07-01 21:26:51 +020013119#ifdef CONFIG_NL80211_TESTMODE
13120 {
13121 .cmd = NL80211_CMD_TESTMODE,
13122 .doit = nl80211_testmode_do,
Wey-Yi Guy71063f02011-05-20 09:05:54 -070013123 .dumpit = nl80211_testmode_dump,
Johannes Bergaff89a92009-07-01 21:26:51 +020013124 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013125 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020013126 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13127 NL80211_FLAG_NEED_RTNL,
Johannes Bergaff89a92009-07-01 21:26:51 +020013128 },
13129#endif
Samuel Ortizb23aa672009-07-01 21:26:54 +020013130 {
13131 .cmd = NL80211_CMD_CONNECT,
13132 .doit = nl80211_connect,
13133 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013134 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020013135 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013136 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020013137 },
13138 {
vamsi krishna088e8df2016-10-27 16:51:11 +030013139 .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
13140 .doit = nl80211_update_connect_params,
13141 .policy = nl80211_policy,
13142 .flags = GENL_ADMIN_PERM,
13143 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13144 NL80211_FLAG_NEED_RTNL,
13145 },
13146 {
Samuel Ortizb23aa672009-07-01 21:26:54 +020013147 .cmd = NL80211_CMD_DISCONNECT,
13148 .doit = nl80211_disconnect,
13149 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013150 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020013151 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013152 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020013153 },
Johannes Berg463d0182009-07-14 00:33:35 +020013154 {
13155 .cmd = NL80211_CMD_SET_WIPHY_NETNS,
13156 .doit = nl80211_wiphy_netns,
13157 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013158 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020013159 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13160 NL80211_FLAG_NEED_RTNL,
Johannes Berg463d0182009-07-14 00:33:35 +020013161 },
Holger Schurig61fa7132009-11-11 12:25:40 +010013162 {
13163 .cmd = NL80211_CMD_GET_SURVEY,
13164 .policy = nl80211_policy,
13165 .dumpit = nl80211_dump_survey,
13166 },
Samuel Ortiz67fbb162009-11-24 23:59:15 +010013167 {
13168 .cmd = NL80211_CMD_SET_PMKSA,
13169 .doit = nl80211_setdel_pmksa,
13170 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013171 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020013172 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013173 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010013174 },
13175 {
13176 .cmd = NL80211_CMD_DEL_PMKSA,
13177 .doit = nl80211_setdel_pmksa,
13178 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013179 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020013180 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013181 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010013182 },
13183 {
13184 .cmd = NL80211_CMD_FLUSH_PMKSA,
13185 .doit = nl80211_flush_pmksa,
13186 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013187 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020013188 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013189 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010013190 },
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013191 {
13192 .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
13193 .doit = nl80211_remain_on_channel,
13194 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013195 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020013196 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013197 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013198 },
13199 {
13200 .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
13201 .doit = nl80211_cancel_remain_on_channel,
13202 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013203 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020013204 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013205 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013206 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +020013207 {
13208 .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
13209 .doit = nl80211_set_tx_bitrate_mask,
13210 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013211 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020013212 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13213 NL80211_FLAG_NEED_RTNL,
Jouni Malinen13ae75b2009-12-29 12:59:45 +020013214 },
Jouni Malinen026331c2010-02-15 12:53:10 +020013215 {
Johannes Berg2e161f72010-08-12 15:38:38 +020013216 .cmd = NL80211_CMD_REGISTER_FRAME,
13217 .doit = nl80211_register_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020013218 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013219 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020013220 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020013221 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020013222 },
13223 {
Johannes Berg2e161f72010-08-12 15:38:38 +020013224 .cmd = NL80211_CMD_FRAME,
13225 .doit = nl80211_tx_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020013226 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013227 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020013228 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020013229 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020013230 },
Kalle Valoffb9eb32010-02-17 17:58:10 +020013231 {
Johannes Bergf7ca38d2010-11-25 10:02:29 +010013232 .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
13233 .doit = nl80211_tx_mgmt_cancel_wait,
13234 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013235 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020013236 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Bergf7ca38d2010-11-25 10:02:29 +010013237 NL80211_FLAG_NEED_RTNL,
13238 },
13239 {
Kalle Valoffb9eb32010-02-17 17:58:10 +020013240 .cmd = NL80211_CMD_SET_POWER_SAVE,
13241 .doit = nl80211_set_power_save,
13242 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013243 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020013244 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13245 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020013246 },
13247 {
13248 .cmd = NL80211_CMD_GET_POWER_SAVE,
13249 .doit = nl80211_get_power_save,
13250 .policy = nl80211_policy,
13251 /* can be retrieved by unprivileged users */
Johannes Berg4c476992010-10-04 21:36:35 +020013252 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13253 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020013254 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013255 {
13256 .cmd = NL80211_CMD_SET_CQM,
13257 .doit = nl80211_set_cqm,
13258 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013259 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020013260 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13261 NL80211_FLAG_NEED_RTNL,
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013262 },
Johannes Bergf444de02010-05-05 15:25:02 +020013263 {
13264 .cmd = NL80211_CMD_SET_CHANNEL,
13265 .doit = nl80211_set_channel,
13266 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013267 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020013268 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13269 NL80211_FLAG_NEED_RTNL,
Johannes Bergf444de02010-05-05 15:25:02 +020013270 },
Bill Jordane8347eb2010-10-01 13:54:28 -040013271 {
13272 .cmd = NL80211_CMD_SET_WDS_PEER,
13273 .doit = nl80211_set_wds_peer,
13274 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013275 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg43b19952010-10-07 13:10:30 +020013276 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13277 NL80211_FLAG_NEED_RTNL,
Bill Jordane8347eb2010-10-01 13:54:28 -040013278 },
Johannes Berg29cbe682010-12-03 09:20:44 +010013279 {
13280 .cmd = NL80211_CMD_JOIN_MESH,
13281 .doit = nl80211_join_mesh,
13282 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013283 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010013284 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13285 NL80211_FLAG_NEED_RTNL,
13286 },
13287 {
13288 .cmd = NL80211_CMD_LEAVE_MESH,
13289 .doit = nl80211_leave_mesh,
13290 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013291 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010013292 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13293 NL80211_FLAG_NEED_RTNL,
13294 },
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010013295 {
13296 .cmd = NL80211_CMD_JOIN_OCB,
13297 .doit = nl80211_join_ocb,
13298 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013299 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010013300 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13301 NL80211_FLAG_NEED_RTNL,
13302 },
13303 {
13304 .cmd = NL80211_CMD_LEAVE_OCB,
13305 .doit = nl80211_leave_ocb,
13306 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013307 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010013308 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13309 NL80211_FLAG_NEED_RTNL,
13310 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020013311#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +020013312 {
13313 .cmd = NL80211_CMD_GET_WOWLAN,
13314 .doit = nl80211_get_wowlan,
13315 .policy = nl80211_policy,
13316 /* can be retrieved by unprivileged users */
13317 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13318 NL80211_FLAG_NEED_RTNL,
13319 },
13320 {
13321 .cmd = NL80211_CMD_SET_WOWLAN,
13322 .doit = nl80211_set_wowlan,
13323 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013324 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergff1b6e62011-05-04 15:37:28 +020013325 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13326 NL80211_FLAG_NEED_RTNL,
13327 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020013328#endif
Johannes Berge5497d72011-07-05 16:35:40 +020013329 {
13330 .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
13331 .doit = nl80211_set_rekey_data,
13332 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013333 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berge5497d72011-07-05 16:35:40 +020013334 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030013335 NL80211_FLAG_NEED_RTNL |
13336 NL80211_FLAG_CLEAR_SKB,
Johannes Berge5497d72011-07-05 16:35:40 +020013337 },
Arik Nemtsov109086c2011-09-28 14:12:50 +030013338 {
13339 .cmd = NL80211_CMD_TDLS_MGMT,
13340 .doit = nl80211_tdls_mgmt,
13341 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013342 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030013343 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13344 NL80211_FLAG_NEED_RTNL,
13345 },
13346 {
13347 .cmd = NL80211_CMD_TDLS_OPER,
13348 .doit = nl80211_tdls_oper,
13349 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013350 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030013351 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13352 NL80211_FLAG_NEED_RTNL,
13353 },
Johannes Berg28946da2011-11-04 11:18:12 +010013354 {
13355 .cmd = NL80211_CMD_UNEXPECTED_FRAME,
13356 .doit = nl80211_register_unexpected_frame,
13357 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013358 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg28946da2011-11-04 11:18:12 +010013359 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13360 NL80211_FLAG_NEED_RTNL,
13361 },
Johannes Berg7f6cf312011-11-04 11:18:15 +010013362 {
13363 .cmd = NL80211_CMD_PROBE_CLIENT,
13364 .doit = nl80211_probe_client,
13365 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013366 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020013367 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg7f6cf312011-11-04 11:18:15 +010013368 NL80211_FLAG_NEED_RTNL,
13369 },
Johannes Berg5e760232011-11-04 11:18:17 +010013370 {
13371 .cmd = NL80211_CMD_REGISTER_BEACONS,
13372 .doit = nl80211_register_beacons,
13373 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013374 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg5e760232011-11-04 11:18:17 +010013375 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13376 NL80211_FLAG_NEED_RTNL,
13377 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010013378 {
13379 .cmd = NL80211_CMD_SET_NOACK_MAP,
13380 .doit = nl80211_set_noack_map,
13381 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013382 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010013383 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13384 NL80211_FLAG_NEED_RTNL,
13385 },
Johannes Berg98104fde2012-06-16 00:19:54 +020013386 {
13387 .cmd = NL80211_CMD_START_P2P_DEVICE,
13388 .doit = nl80211_start_p2p_device,
13389 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013390 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020013391 .internal_flags = NL80211_FLAG_NEED_WDEV |
13392 NL80211_FLAG_NEED_RTNL,
13393 },
13394 {
13395 .cmd = NL80211_CMD_STOP_P2P_DEVICE,
13396 .doit = nl80211_stop_p2p_device,
13397 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013398 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020013399 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13400 NL80211_FLAG_NEED_RTNL,
13401 },
Antonio Quartullif4e583c2012-11-02 13:27:48 +010013402 {
Ayala Bekercb3b7d82016-09-20 17:31:13 +030013403 .cmd = NL80211_CMD_START_NAN,
13404 .doit = nl80211_start_nan,
13405 .policy = nl80211_policy,
13406 .flags = GENL_ADMIN_PERM,
13407 .internal_flags = NL80211_FLAG_NEED_WDEV |
13408 NL80211_FLAG_NEED_RTNL,
13409 },
13410 {
13411 .cmd = NL80211_CMD_STOP_NAN,
13412 .doit = nl80211_stop_nan,
13413 .policy = nl80211_policy,
13414 .flags = GENL_ADMIN_PERM,
13415 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13416 NL80211_FLAG_NEED_RTNL,
13417 },
13418 {
Ayala Bekera442b762016-09-20 17:31:15 +030013419 .cmd = NL80211_CMD_ADD_NAN_FUNCTION,
13420 .doit = nl80211_nan_add_func,
13421 .policy = nl80211_policy,
13422 .flags = GENL_ADMIN_PERM,
13423 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13424 NL80211_FLAG_NEED_RTNL,
13425 },
13426 {
13427 .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
13428 .doit = nl80211_nan_del_func,
13429 .policy = nl80211_policy,
13430 .flags = GENL_ADMIN_PERM,
13431 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13432 NL80211_FLAG_NEED_RTNL,
13433 },
13434 {
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030013435 .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
13436 .doit = nl80211_nan_change_config,
13437 .policy = nl80211_policy,
13438 .flags = GENL_ADMIN_PERM,
13439 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13440 NL80211_FLAG_NEED_RTNL,
13441 },
13442 {
Antonio Quartullif4e583c2012-11-02 13:27:48 +010013443 .cmd = NL80211_CMD_SET_MCAST_RATE,
13444 .doit = nl80211_set_mcast_rate,
13445 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013446 .flags = GENL_UNS_ADMIN_PERM,
Antonio Quartullif4e583c2012-11-02 13:27:48 +010013447 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13448 NL80211_FLAG_NEED_RTNL,
13449 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053013450 {
13451 .cmd = NL80211_CMD_SET_MAC_ACL,
13452 .doit = nl80211_set_mac_acl,
13453 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013454 .flags = GENL_UNS_ADMIN_PERM,
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053013455 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13456 NL80211_FLAG_NEED_RTNL,
13457 },
Simon Wunderlich04f39042013-02-08 18:16:19 +010013458 {
13459 .cmd = NL80211_CMD_RADAR_DETECT,
13460 .doit = nl80211_start_radar_detection,
13461 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013462 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich04f39042013-02-08 18:16:19 +010013463 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13464 NL80211_FLAG_NEED_RTNL,
13465 },
Johannes Berg3713b4e2013-02-14 16:19:38 +010013466 {
13467 .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
13468 .doit = nl80211_get_protocol_features,
13469 .policy = nl80211_policy,
13470 },
Jouni Malinen355199e2013-02-27 17:14:27 +020013471 {
13472 .cmd = NL80211_CMD_UPDATE_FT_IES,
13473 .doit = nl80211_update_ft_ies,
13474 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013475 .flags = GENL_UNS_ADMIN_PERM,
Jouni Malinen355199e2013-02-27 17:14:27 +020013476 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13477 NL80211_FLAG_NEED_RTNL,
13478 },
Arend van Spriel5de17982013-04-18 15:49:00 +020013479 {
13480 .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
13481 .doit = nl80211_crit_protocol_start,
13482 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013483 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020013484 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13485 NL80211_FLAG_NEED_RTNL,
13486 },
13487 {
13488 .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
13489 .doit = nl80211_crit_protocol_stop,
13490 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013491 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020013492 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13493 NL80211_FLAG_NEED_RTNL,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070013494 },
13495 {
13496 .cmd = NL80211_CMD_GET_COALESCE,
13497 .doit = nl80211_get_coalesce,
13498 .policy = nl80211_policy,
13499 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13500 NL80211_FLAG_NEED_RTNL,
13501 },
13502 {
13503 .cmd = NL80211_CMD_SET_COALESCE,
13504 .doit = nl80211_set_coalesce,
13505 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013506 .flags = GENL_UNS_ADMIN_PERM,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070013507 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13508 NL80211_FLAG_NEED_RTNL,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020013509 },
13510 {
13511 .cmd = NL80211_CMD_CHANNEL_SWITCH,
13512 .doit = nl80211_channel_switch,
13513 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013514 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020013515 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13516 NL80211_FLAG_NEED_RTNL,
13517 },
Johannes Bergad7e7182013-11-13 13:37:47 +010013518 {
13519 .cmd = NL80211_CMD_VENDOR,
13520 .doit = nl80211_vendor_cmd,
Johannes Berg7bdbe402015-08-15 22:39:49 +030013521 .dumpit = nl80211_vendor_cmd_dump,
Johannes Bergad7e7182013-11-13 13:37:47 +010013522 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013523 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergad7e7182013-11-13 13:37:47 +010013524 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13525 NL80211_FLAG_NEED_RTNL,
13526 },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080013527 {
13528 .cmd = NL80211_CMD_SET_QOS_MAP,
13529 .doit = nl80211_set_qos_map,
13530 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013531 .flags = GENL_UNS_ADMIN_PERM,
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080013532 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13533 NL80211_FLAG_NEED_RTNL,
13534 },
Johannes Berg960d01a2014-09-09 22:55:35 +030013535 {
13536 .cmd = NL80211_CMD_ADD_TX_TS,
13537 .doit = nl80211_add_tx_ts,
13538 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013539 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030013540 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13541 NL80211_FLAG_NEED_RTNL,
13542 },
13543 {
13544 .cmd = NL80211_CMD_DEL_TX_TS,
13545 .doit = nl80211_del_tx_ts,
13546 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013547 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030013548 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13549 NL80211_FLAG_NEED_RTNL,
13550 },
Arik Nemtsov1057d352014-11-19 12:54:26 +020013551 {
13552 .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
13553 .doit = nl80211_tdls_channel_switch,
13554 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013555 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020013556 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13557 NL80211_FLAG_NEED_RTNL,
13558 },
13559 {
13560 .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
13561 .doit = nl80211_tdls_cancel_channel_switch,
13562 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013563 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020013564 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13565 NL80211_FLAG_NEED_RTNL,
13566 },
Michael Braunce0ce132016-10-10 19:12:22 +020013567 {
13568 .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
13569 .doit = nl80211_set_multicast_to_unicast,
13570 .policy = nl80211_policy,
13571 .flags = GENL_UNS_ADMIN_PERM,
13572 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13573 NL80211_FLAG_NEED_RTNL,
13574 },
Avraham Stern3a00df52017-06-09 13:08:43 +010013575 {
13576 .cmd = NL80211_CMD_SET_PMK,
13577 .doit = nl80211_set_pmk,
13578 .policy = nl80211_policy,
13579 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13580 NL80211_FLAG_NEED_RTNL,
13581 },
13582 {
13583 .cmd = NL80211_CMD_DEL_PMK,
13584 .doit = nl80211_del_pmk,
13585 .policy = nl80211_policy,
13586 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13587 NL80211_FLAG_NEED_RTNL,
13588 },
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020013589 {
13590 .cmd = NL80211_CMD_EXTERNAL_AUTH,
13591 .doit = nl80211_external_auth,
13592 .policy = nl80211_policy,
13593 .flags = GENL_ADMIN_PERM,
13594 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13595 NL80211_FLAG_NEED_RTNL,
13596 },
Denis Kenzior2576a9a2018-03-26 12:52:42 -050013597 {
13598 .cmd = NL80211_CMD_CONTROL_PORT_FRAME,
13599 .doit = nl80211_tx_control_port,
13600 .policy = nl80211_policy,
13601 .flags = GENL_UNS_ADMIN_PERM,
13602 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13603 NL80211_FLAG_NEED_RTNL,
13604 },
Johannes Berg55682962007-09-20 13:09:35 -040013605};
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013606
Johannes Berg56989f62016-10-24 14:40:05 +020013607static struct genl_family nl80211_fam __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +020013608 .name = NL80211_GENL_NAME, /* have users key off the name instead */
13609 .hdrsize = 0, /* no private header */
13610 .version = 1, /* no particular meaning now */
13611 .maxattr = NL80211_ATTR_MAX,
13612 .netnsok = true,
13613 .pre_doit = nl80211_pre_doit,
13614 .post_doit = nl80211_post_doit,
13615 .module = THIS_MODULE,
13616 .ops = nl80211_ops,
13617 .n_ops = ARRAY_SIZE(nl80211_ops),
13618 .mcgrps = nl80211_mcgrps,
13619 .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
13620};
13621
Johannes Berg55682962007-09-20 13:09:35 -040013622/* notification functions */
13623
Johannes Berg3bb20552014-05-26 13:52:25 +020013624void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
13625 enum nl80211_commands cmd)
Johannes Berg55682962007-09-20 13:09:35 -040013626{
13627 struct sk_buff *msg;
Johannes Berg86e8cf92013-06-19 10:57:22 +020013628 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -040013629
Johannes Berg3bb20552014-05-26 13:52:25 +020013630 WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
13631 cmd != NL80211_CMD_DEL_WIPHY);
13632
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013633 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040013634 if (!msg)
13635 return;
13636
Johannes Berg3bb20552014-05-26 13:52:25 +020013637 if (nl80211_send_wiphy(rdev, cmd, msg, 0, 0, 0, &state) < 0) {
Johannes Berg55682962007-09-20 13:09:35 -040013638 nlmsg_free(msg);
13639 return;
13640 }
13641
Johannes Berg68eb5502013-11-19 15:19:38 +010013642 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013643 NL80211_MCGRP_CONFIG, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040013644}
13645
Denis Kenzior896ff062016-08-03 16:58:33 -050013646void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
13647 struct wireless_dev *wdev,
13648 enum nl80211_commands cmd)
13649{
13650 struct sk_buff *msg;
13651
13652 WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
13653 cmd != NL80211_CMD_DEL_INTERFACE);
13654
13655 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13656 if (!msg)
13657 return;
13658
13659 if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
13660 cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
13661 nlmsg_free(msg);
13662 return;
13663 }
13664
13665 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
13666 NL80211_MCGRP_CONFIG, GFP_KERNEL);
13667}
13668
Johannes Berg362a4152009-05-24 16:43:15 +020013669static int nl80211_add_scan_req(struct sk_buff *msg,
13670 struct cfg80211_registered_device *rdev)
13671{
13672 struct cfg80211_scan_request *req = rdev->scan_req;
13673 struct nlattr *nest;
13674 int i;
13675
13676 if (WARN_ON(!req))
13677 return 0;
13678
13679 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
13680 if (!nest)
13681 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040013682 for (i = 0; i < req->n_ssids; i++) {
13683 if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
13684 goto nla_put_failure;
13685 }
Johannes Berg362a4152009-05-24 16:43:15 +020013686 nla_nest_end(msg, nest);
13687
13688 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
13689 if (!nest)
13690 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040013691 for (i = 0; i < req->n_channels; i++) {
13692 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
13693 goto nla_put_failure;
13694 }
Johannes Berg362a4152009-05-24 16:43:15 +020013695 nla_nest_end(msg, nest);
13696
David S. Miller9360ffd2012-03-29 04:41:26 -040013697 if (req->ie &&
13698 nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
13699 goto nla_put_failure;
Johannes Berg362a4152009-05-24 16:43:15 +020013700
Johannes Bergae917c92013-10-25 11:05:22 +020013701 if (req->flags &&
13702 nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
13703 goto nla_put_failure;
Sam Lefflered4737712012-10-11 21:03:31 -070013704
Avraham Stern1d762502016-07-05 17:10:13 +030013705 if (req->info.scan_start_tsf &&
13706 (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
13707 req->info.scan_start_tsf, NL80211_BSS_PAD) ||
13708 nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
13709 req->info.tsf_bssid)))
13710 goto nla_put_failure;
13711
Johannes Berg362a4152009-05-24 16:43:15 +020013712 return 0;
13713 nla_put_failure:
13714 return -ENOBUFS;
13715}
13716
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013717static int nl80211_prep_scan_msg(struct sk_buff *msg,
Johannes Berga538e2d2009-06-16 19:56:42 +020013718 struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020013719 struct wireless_dev *wdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000013720 u32 portid, u32 seq, int flags,
Johannes Berga538e2d2009-06-16 19:56:42 +020013721 u32 cmd)
Johannes Berg2a519312009-02-10 21:25:55 +010013722{
13723 void *hdr;
13724
Eric W. Biederman15e47302012-09-07 20:12:54 +000013725 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg2a519312009-02-10 21:25:55 +010013726 if (!hdr)
13727 return -1;
13728
David S. Miller9360ffd2012-03-29 04:41:26 -040013729 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Bergfd014282012-06-18 19:17:03 +020013730 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13731 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013732 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13733 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013734 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +010013735
Johannes Berg362a4152009-05-24 16:43:15 +020013736 /* ignore errors and send incomplete event anyway */
13737 nl80211_add_scan_req(msg, rdev);
Johannes Berg2a519312009-02-10 21:25:55 +010013738
Johannes Berg053c0952015-01-16 22:09:00 +010013739 genlmsg_end(msg, hdr);
13740 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +010013741
13742 nla_put_failure:
13743 genlmsg_cancel(msg, hdr);
13744 return -EMSGSIZE;
13745}
13746
Luciano Coelho807f8a82011-05-11 17:09:35 +030013747static int
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013748nl80211_prep_sched_scan_msg(struct sk_buff *msg,
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013749 struct cfg80211_sched_scan_request *req, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030013750{
13751 void *hdr;
13752
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013753 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013754 if (!hdr)
13755 return -1;
13756
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013757 if (nla_put_u32(msg, NL80211_ATTR_WIPHY,
13758 wiphy_to_rdev(req->wiphy)->wiphy_idx) ||
13759 nla_put_u32(msg, NL80211_ATTR_IFINDEX, req->dev->ifindex) ||
13760 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->reqid,
13761 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013762 goto nla_put_failure;
Luciano Coelho807f8a82011-05-11 17:09:35 +030013763
Johannes Berg053c0952015-01-16 22:09:00 +010013764 genlmsg_end(msg, hdr);
13765 return 0;
Luciano Coelho807f8a82011-05-11 17:09:35 +030013766
13767 nla_put_failure:
13768 genlmsg_cancel(msg, hdr);
13769 return -EMSGSIZE;
13770}
13771
Johannes Berga538e2d2009-06-16 19:56:42 +020013772void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020013773 struct wireless_dev *wdev)
Johannes Berga538e2d2009-06-16 19:56:42 +020013774{
13775 struct sk_buff *msg;
13776
Thomas Graf58050fc2012-06-28 03:57:45 +000013777 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013778 if (!msg)
13779 return;
13780
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013781 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Berga538e2d2009-06-16 19:56:42 +020013782 NL80211_CMD_TRIGGER_SCAN) < 0) {
13783 nlmsg_free(msg);
13784 return;
13785 }
13786
Johannes Berg68eb5502013-11-19 15:19:38 +010013787 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013788 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013789}
13790
Johannes Bergf9d15d12014-01-22 11:14:19 +020013791struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
13792 struct wireless_dev *wdev, bool aborted)
Johannes Berg2a519312009-02-10 21:25:55 +010013793{
13794 struct sk_buff *msg;
13795
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013796 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013797 if (!msg)
Johannes Bergf9d15d12014-01-22 11:14:19 +020013798 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013799
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013800 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Bergf9d15d12014-01-22 11:14:19 +020013801 aborted ? NL80211_CMD_SCAN_ABORTED :
13802 NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +010013803 nlmsg_free(msg);
Johannes Bergf9d15d12014-01-22 11:14:19 +020013804 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013805 }
13806
Johannes Bergf9d15d12014-01-22 11:14:19 +020013807 return msg;
Johannes Berg2a519312009-02-10 21:25:55 +010013808}
13809
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013810/* send message created by nl80211_build_scan_msg() */
13811void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
13812 struct sk_buff *msg)
Johannes Berg2a519312009-02-10 21:25:55 +010013813{
Johannes Berg2a519312009-02-10 21:25:55 +010013814 if (!msg)
13815 return;
13816
Johannes Berg68eb5502013-11-19 15:19:38 +010013817 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013818 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013819}
13820
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013821void nl80211_send_sched_scan(struct cfg80211_sched_scan_request *req, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030013822{
13823 struct sk_buff *msg;
13824
Thomas Graf58050fc2012-06-28 03:57:45 +000013825 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013826 if (!msg)
13827 return;
13828
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013829 if (nl80211_prep_sched_scan_msg(msg, req, cmd) < 0) {
Luciano Coelho807f8a82011-05-11 17:09:35 +030013830 nlmsg_free(msg);
13831 return;
13832 }
13833
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013834 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(req->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013835 NL80211_MCGRP_SCAN, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013836}
13837
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013838static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
13839 struct regulatory_request *request)
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013840{
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013841 /* Userspace can always count this one always being set */
David S. Miller9360ffd2012-03-29 04:41:26 -040013842 if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
13843 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013844
David S. Miller9360ffd2012-03-29 04:41:26 -040013845 if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
13846 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13847 NL80211_REGDOM_TYPE_WORLD))
13848 goto nla_put_failure;
13849 } else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
13850 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13851 NL80211_REGDOM_TYPE_CUSTOM_WORLD))
13852 goto nla_put_failure;
13853 } else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
13854 request->intersect) {
13855 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13856 NL80211_REGDOM_TYPE_INTERSECTION))
13857 goto nla_put_failure;
13858 } else {
13859 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13860 NL80211_REGDOM_TYPE_COUNTRY) ||
13861 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
13862 request->alpha2))
13863 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013864 }
13865
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013866 if (request->wiphy_idx != WIPHY_IDX_INVALID) {
13867 struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
13868
13869 if (wiphy &&
13870 nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
13871 goto nla_put_failure;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +020013872
13873 if (wiphy &&
13874 wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
13875 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
13876 goto nla_put_failure;
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013877 }
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013878
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013879 return true;
13880
13881nla_put_failure:
13882 return false;
13883}
13884
13885/*
13886 * This can happen on global regulatory changes or device specific settings
13887 * based on custom regulatory domains.
13888 */
13889void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
13890 struct regulatory_request *request)
13891{
13892 struct sk_buff *msg;
13893 void *hdr;
13894
13895 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13896 if (!msg)
13897 return;
13898
13899 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
13900 if (!hdr) {
13901 nlmsg_free(msg);
13902 return;
13903 }
13904
13905 if (nl80211_reg_change_event_fill(msg, request) == false)
13906 goto nla_put_failure;
13907
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013908 genlmsg_end(msg, hdr);
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013909
Johannes Bergbc43b282009-07-25 10:54:13 +020013910 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010013911 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013912 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Bergbc43b282009-07-25 10:54:13 +020013913 rcu_read_unlock();
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013914
13915 return;
13916
13917nla_put_failure:
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013918 nlmsg_free(msg);
13919}
13920
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013921static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
13922 struct net_device *netdev,
13923 const u8 *buf, size_t len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013924 enum nl80211_commands cmd, gfp_t gfp,
13925 int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013926{
13927 struct sk_buff *msg;
13928 void *hdr;
13929
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013930 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013931 if (!msg)
13932 return;
13933
13934 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13935 if (!hdr) {
13936 nlmsg_free(msg);
13937 return;
13938 }
13939
David S. Miller9360ffd2012-03-29 04:41:26 -040013940 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13941 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13942 nla_put(msg, NL80211_ATTR_FRAME, len, buf))
13943 goto nla_put_failure;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013944
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013945 if (uapsd_queues >= 0) {
13946 struct nlattr *nla_wmm =
13947 nla_nest_start(msg, NL80211_ATTR_STA_WME);
13948 if (!nla_wmm)
13949 goto nla_put_failure;
13950
13951 if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
13952 uapsd_queues))
13953 goto nla_put_failure;
13954
13955 nla_nest_end(msg, nla_wmm);
13956 }
13957
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013958 genlmsg_end(msg, hdr);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013959
Johannes Berg68eb5502013-11-19 15:19:38 +010013960 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013961 NL80211_MCGRP_MLME, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013962 return;
13963
13964 nla_put_failure:
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013965 nlmsg_free(msg);
13966}
13967
13968void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013969 struct net_device *netdev, const u8 *buf,
13970 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013971{
13972 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013973 NL80211_CMD_AUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013974}
13975
13976void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
13977 struct net_device *netdev, const u8 *buf,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013978 size_t len, gfp_t gfp, int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013979{
Johannes Berge6d6e342009-07-01 21:26:47 +020013980 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013981 NL80211_CMD_ASSOCIATE, gfp, uapsd_queues);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013982}
13983
Jouni Malinen53b46b82009-03-27 20:53:56 +020013984void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013985 struct net_device *netdev, const u8 *buf,
13986 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013987{
13988 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013989 NL80211_CMD_DEAUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013990}
13991
Jouni Malinen53b46b82009-03-27 20:53:56 +020013992void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
13993 struct net_device *netdev, const u8 *buf,
Johannes Berge6d6e342009-07-01 21:26:47 +020013994 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013995{
13996 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013997 NL80211_CMD_DISASSOCIATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013998}
13999
Johannes Berg6ff57cf2013-05-16 00:55:00 +020014000void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
14001 size_t len)
Jouni Malinencf4e5942010-12-16 00:52:40 +020014002{
Johannes Berg947add32013-02-22 22:05:20 +010014003 struct wireless_dev *wdev = dev->ieee80211_ptr;
14004 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014005 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg6ff57cf2013-05-16 00:55:00 +020014006 const struct ieee80211_mgmt *mgmt = (void *)buf;
14007 u32 cmd;
Jouni Malinencf4e5942010-12-16 00:52:40 +020014008
Johannes Berg6ff57cf2013-05-16 00:55:00 +020014009 if (WARN_ON(len < 2))
14010 return;
14011
14012 if (ieee80211_is_deauth(mgmt->frame_control))
14013 cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
14014 else
14015 cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
14016
14017 trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030014018 nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1);
Jouni Malinencf4e5942010-12-16 00:52:40 +020014019}
Johannes Berg6ff57cf2013-05-16 00:55:00 +020014020EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
Jouni Malinencf4e5942010-12-16 00:52:40 +020014021
Luis R. Rodriguez1b06bb42009-05-02 00:34:48 -040014022static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
14023 struct net_device *netdev, int cmd,
Johannes Berge6d6e342009-07-01 21:26:47 +020014024 const u8 *addr, gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030014025{
14026 struct sk_buff *msg;
14027 void *hdr;
14028
Johannes Berge6d6e342009-07-01 21:26:47 +020014029 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030014030 if (!msg)
14031 return;
14032
14033 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
14034 if (!hdr) {
14035 nlmsg_free(msg);
14036 return;
14037 }
14038
David S. Miller9360ffd2012-03-29 04:41:26 -040014039 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14040 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14041 nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
14042 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
14043 goto nla_put_failure;
Jouni Malinen1965c852009-04-22 21:38:25 +030014044
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014045 genlmsg_end(msg, hdr);
Jouni Malinen1965c852009-04-22 21:38:25 +030014046
Johannes Berg68eb5502013-11-19 15:19:38 +010014047 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014048 NL80211_MCGRP_MLME, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030014049 return;
14050
14051 nla_put_failure:
Jouni Malinen1965c852009-04-22 21:38:25 +030014052 nlmsg_free(msg);
14053}
14054
14055void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020014056 struct net_device *netdev, const u8 *addr,
14057 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030014058{
14059 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
Johannes Berge6d6e342009-07-01 21:26:47 +020014060 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030014061}
14062
14063void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020014064 struct net_device *netdev, const u8 *addr,
14065 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030014066{
Johannes Berge6d6e342009-07-01 21:26:47 +020014067 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
14068 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030014069}
14070
Samuel Ortizb23aa672009-07-01 21:26:54 +020014071void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030014072 struct net_device *netdev,
14073 struct cfg80211_connect_resp_params *cr,
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020014074 gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020014075{
14076 struct sk_buff *msg;
14077 void *hdr;
14078
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030014079 msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
14080 cr->fils_kek_len + cr->pmk_len +
14081 (cr->pmkid ? WLAN_PMKID_LEN : 0), gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014082 if (!msg)
14083 return;
14084
14085 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
14086 if (!hdr) {
14087 nlmsg_free(msg);
14088 return;
14089 }
14090
David S. Miller9360ffd2012-03-29 04:41:26 -040014091 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14092 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030014093 (cr->bssid &&
14094 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
Jouni Malinenbf1ecd22016-05-31 00:16:50 +030014095 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030014096 cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
14097 cr->status) ||
14098 (cr->status < 0 &&
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020014099 (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030014100 nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
14101 cr->timeout_reason))) ||
14102 (cr->req_ie &&
14103 nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
14104 (cr->resp_ie &&
14105 nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030014106 cr->resp_ie)) ||
14107 (cr->update_erp_next_seq_num &&
14108 nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
14109 cr->fils_erp_next_seq_num)) ||
14110 (cr->status == WLAN_STATUS_SUCCESS &&
14111 ((cr->fils_kek &&
14112 nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils_kek_len,
14113 cr->fils_kek)) ||
14114 (cr->pmk &&
14115 nla_put(msg, NL80211_ATTR_PMK, cr->pmk_len, cr->pmk)) ||
14116 (cr->pmkid &&
14117 nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->pmkid)))))
David S. Miller9360ffd2012-03-29 04:41:26 -040014118 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020014119
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014120 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014121
Johannes Berg68eb5502013-11-19 15:19:38 +010014122 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014123 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014124 return;
14125
14126 nla_put_failure:
Samuel Ortizb23aa672009-07-01 21:26:54 +020014127 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014128}
14129
14130void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
Avraham Stern29ce6ec2017-04-26 10:58:49 +030014131 struct net_device *netdev,
14132 struct cfg80211_roam_info *info, gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020014133{
14134 struct sk_buff *msg;
14135 void *hdr;
Avraham Stern29ce6ec2017-04-26 10:58:49 +030014136 const u8 *bssid = info->bss ? info->bss->bssid : info->bssid;
Samuel Ortizb23aa672009-07-01 21:26:54 +020014137
Avraham Stern29ce6ec2017-04-26 10:58:49 +030014138 msg = nlmsg_new(100 + info->req_ie_len + info->resp_ie_len, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014139 if (!msg)
14140 return;
14141
14142 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
14143 if (!hdr) {
14144 nlmsg_free(msg);
14145 return;
14146 }
14147
David S. Miller9360ffd2012-03-29 04:41:26 -040014148 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14149 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14150 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
Avraham Stern29ce6ec2017-04-26 10:58:49 +030014151 (info->req_ie &&
14152 nla_put(msg, NL80211_ATTR_REQ_IE, info->req_ie_len,
14153 info->req_ie)) ||
14154 (info->resp_ie &&
14155 nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
Avraham Stern503c1fb2017-09-29 14:21:49 +020014156 info->resp_ie)))
David S. Miller9360ffd2012-03-29 04:41:26 -040014157 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020014158
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014159 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014160
Johannes Berg68eb5502013-11-19 15:19:38 +010014161 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014162 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014163 return;
14164
14165 nla_put_failure:
Samuel Ortizb23aa672009-07-01 21:26:54 +020014166 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014167}
14168
Avraham Stern503c1fb2017-09-29 14:21:49 +020014169void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
14170 struct net_device *netdev, const u8 *bssid)
14171{
14172 struct sk_buff *msg;
14173 void *hdr;
14174
14175 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
14176 if (!msg)
14177 return;
14178
14179 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PORT_AUTHORIZED);
14180 if (!hdr) {
14181 nlmsg_free(msg);
14182 return;
14183 }
14184
14185 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
14186 goto nla_put_failure;
14187
14188 genlmsg_end(msg, hdr);
14189
14190 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
14191 NL80211_MCGRP_MLME, GFP_KERNEL);
14192 return;
14193
14194 nla_put_failure:
Avraham Stern503c1fb2017-09-29 14:21:49 +020014195 nlmsg_free(msg);
14196}
14197
Samuel Ortizb23aa672009-07-01 21:26:54 +020014198void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
14199 struct net_device *netdev, u16 reason,
Johannes Berg667503d2009-07-07 03:56:11 +020014200 const u8 *ie, size_t ie_len, bool from_ap)
Samuel Ortizb23aa672009-07-01 21:26:54 +020014201{
14202 struct sk_buff *msg;
14203 void *hdr;
14204
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014205 msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014206 if (!msg)
14207 return;
14208
14209 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
14210 if (!hdr) {
14211 nlmsg_free(msg);
14212 return;
14213 }
14214
David S. Miller9360ffd2012-03-29 04:41:26 -040014215 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14216 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
David Spinadel86b6c462017-12-18 12:14:05 +020014217 (reason &&
David S. Miller9360ffd2012-03-29 04:41:26 -040014218 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
14219 (from_ap &&
14220 nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
14221 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
14222 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020014223
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014224 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014225
Johannes Berg68eb5502013-11-19 15:19:38 +010014226 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014227 NL80211_MCGRP_MLME, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014228 return;
14229
14230 nla_put_failure:
Samuel Ortizb23aa672009-07-01 21:26:54 +020014231 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020014232}
14233
Johannes Berg04a773a2009-04-19 21:24:32 +020014234void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
14235 struct net_device *netdev, const u8 *bssid,
14236 gfp_t gfp)
14237{
14238 struct sk_buff *msg;
14239 void *hdr;
14240
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070014241 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020014242 if (!msg)
14243 return;
14244
14245 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
14246 if (!hdr) {
14247 nlmsg_free(msg);
14248 return;
14249 }
14250
David S. Miller9360ffd2012-03-29 04:41:26 -040014251 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14252 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14253 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
14254 goto nla_put_failure;
Johannes Berg04a773a2009-04-19 21:24:32 +020014255
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014256 genlmsg_end(msg, hdr);
Johannes Berg04a773a2009-04-19 21:24:32 +020014257
Johannes Berg68eb5502013-11-19 15:19:38 +010014258 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014259 NL80211_MCGRP_MLME, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020014260 return;
14261
14262 nla_put_failure:
Johannes Berg04a773a2009-04-19 21:24:32 +020014263 nlmsg_free(msg);
14264}
14265
Johannes Berg947add32013-02-22 22:05:20 +010014266void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
14267 const u8* ie, u8 ie_len, gfp_t gfp)
Javier Cardonac93b5e72011-04-07 15:08:34 -070014268{
Johannes Berg947add32013-02-22 22:05:20 +010014269 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014270 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Javier Cardonac93b5e72011-04-07 15:08:34 -070014271 struct sk_buff *msg;
14272 void *hdr;
14273
Johannes Berg947add32013-02-22 22:05:20 +010014274 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
14275 return;
14276
14277 trace_cfg80211_notify_new_peer_candidate(dev, addr);
14278
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014279 msg = nlmsg_new(100 + ie_len, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070014280 if (!msg)
14281 return;
14282
14283 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
14284 if (!hdr) {
14285 nlmsg_free(msg);
14286 return;
14287 }
14288
David S. Miller9360ffd2012-03-29 04:41:26 -040014289 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010014290 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14291 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014292 (ie_len && ie &&
14293 nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
14294 goto nla_put_failure;
Javier Cardonac93b5e72011-04-07 15:08:34 -070014295
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014296 genlmsg_end(msg, hdr);
Javier Cardonac93b5e72011-04-07 15:08:34 -070014297
Johannes Berg68eb5502013-11-19 15:19:38 +010014298 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014299 NL80211_MCGRP_MLME, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070014300 return;
14301
14302 nla_put_failure:
Javier Cardonac93b5e72011-04-07 15:08:34 -070014303 nlmsg_free(msg);
14304}
Johannes Berg947add32013-02-22 22:05:20 +010014305EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
Javier Cardonac93b5e72011-04-07 15:08:34 -070014306
Jouni Malinena3b8b052009-03-27 21:59:49 +020014307void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
14308 struct net_device *netdev, const u8 *addr,
14309 enum nl80211_key_type key_type, int key_id,
Johannes Berge6d6e342009-07-01 21:26:47 +020014310 const u8 *tsc, gfp_t gfp)
Jouni Malinena3b8b052009-03-27 21:59:49 +020014311{
14312 struct sk_buff *msg;
14313 void *hdr;
14314
Johannes Berge6d6e342009-07-01 21:26:47 +020014315 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020014316 if (!msg)
14317 return;
14318
14319 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
14320 if (!hdr) {
14321 nlmsg_free(msg);
14322 return;
14323 }
14324
David S. Miller9360ffd2012-03-29 04:41:26 -040014325 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14326 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14327 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
14328 nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
14329 (key_id != -1 &&
14330 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
14331 (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
14332 goto nla_put_failure;
Jouni Malinena3b8b052009-03-27 21:59:49 +020014333
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014334 genlmsg_end(msg, hdr);
Jouni Malinena3b8b052009-03-27 21:59:49 +020014335
Johannes Berg68eb5502013-11-19 15:19:38 +010014336 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014337 NL80211_MCGRP_MLME, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020014338 return;
14339
14340 nla_put_failure:
Jouni Malinena3b8b052009-03-27 21:59:49 +020014341 nlmsg_free(msg);
14342}
14343
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014344void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
14345 struct ieee80211_channel *channel_before,
14346 struct ieee80211_channel *channel_after)
14347{
14348 struct sk_buff *msg;
14349 void *hdr;
14350 struct nlattr *nl_freq;
14351
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070014352 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014353 if (!msg)
14354 return;
14355
14356 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
14357 if (!hdr) {
14358 nlmsg_free(msg);
14359 return;
14360 }
14361
14362 /*
14363 * Since we are applying the beacon hint to a wiphy we know its
14364 * wiphy_idx is valid
14365 */
David S. Miller9360ffd2012-03-29 04:41:26 -040014366 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
14367 goto nla_put_failure;
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014368
14369 /* Before */
14370 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
14371 if (!nl_freq)
14372 goto nla_put_failure;
Haim Dreyfuss50f32712018-04-20 13:49:26 +030014373
14374 if (nl80211_msg_put_channel(msg, wiphy, channel_before, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014375 goto nla_put_failure;
14376 nla_nest_end(msg, nl_freq);
14377
14378 /* After */
14379 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
14380 if (!nl_freq)
14381 goto nla_put_failure;
Haim Dreyfuss50f32712018-04-20 13:49:26 +030014382
14383 if (nl80211_msg_put_channel(msg, wiphy, channel_after, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014384 goto nla_put_failure;
14385 nla_nest_end(msg, nl_freq);
14386
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014387 genlmsg_end(msg, hdr);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014388
Johannes Berg463d0182009-07-14 00:33:35 +020014389 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010014390 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014391 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Berg463d0182009-07-14 00:33:35 +020014392 rcu_read_unlock();
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014393
14394 return;
14395
14396nla_put_failure:
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014397 nlmsg_free(msg);
14398}
14399
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014400static void nl80211_send_remain_on_chan_event(
14401 int cmd, struct cfg80211_registered_device *rdev,
Johannes Berg71bbc992012-06-15 15:30:18 +020014402 struct wireless_dev *wdev, u64 cookie,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014403 struct ieee80211_channel *chan,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014404 unsigned int duration, gfp_t gfp)
14405{
14406 struct sk_buff *msg;
14407 void *hdr;
14408
14409 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14410 if (!msg)
14411 return;
14412
14413 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
14414 if (!hdr) {
14415 nlmsg_free(msg);
14416 return;
14417 }
14418
David S. Miller9360ffd2012-03-29 04:41:26 -040014419 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020014420 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14421 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014422 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14423 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014424 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
Johannes Berg42d97a52012-11-08 18:31:02 +010014425 nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
14426 NL80211_CHAN_NO_HT) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014427 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14428 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040014429 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014430
David S. Miller9360ffd2012-03-29 04:41:26 -040014431 if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
14432 nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
14433 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014434
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014435 genlmsg_end(msg, hdr);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014436
Johannes Berg68eb5502013-11-19 15:19:38 +010014437 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014438 NL80211_MCGRP_MLME, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014439 return;
14440
14441 nla_put_failure:
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014442 nlmsg_free(msg);
14443}
14444
Johannes Berg947add32013-02-22 22:05:20 +010014445void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
14446 struct ieee80211_channel *chan,
14447 unsigned int duration, gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014448{
Johannes Berg947add32013-02-22 22:05:20 +010014449 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014450 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014451
14452 trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014453 nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
Johannes Berg71bbc992012-06-15 15:30:18 +020014454 rdev, wdev, cookie, chan,
Johannes Berg42d97a52012-11-08 18:31:02 +010014455 duration, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014456}
Johannes Berg947add32013-02-22 22:05:20 +010014457EXPORT_SYMBOL(cfg80211_ready_on_channel);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014458
Johannes Berg947add32013-02-22 22:05:20 +010014459void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
14460 struct ieee80211_channel *chan,
14461 gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014462{
Johannes Berg947add32013-02-22 22:05:20 +010014463 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014464 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014465
14466 trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014467 nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
Johannes Berg42d97a52012-11-08 18:31:02 +010014468 rdev, wdev, cookie, chan, 0, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014469}
Johannes Berg947add32013-02-22 22:05:20 +010014470EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014471
Johannes Berg947add32013-02-22 22:05:20 +010014472void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
14473 struct station_info *sinfo, gfp_t gfp)
Johannes Berg98b62182009-12-23 13:15:44 +010014474{
Johannes Berg947add32013-02-22 22:05:20 +010014475 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014476 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg98b62182009-12-23 13:15:44 +010014477 struct sk_buff *msg;
14478
Johannes Berg947add32013-02-22 22:05:20 +010014479 trace_cfg80211_new_sta(dev, mac_addr, sinfo);
14480
Thomas Graf58050fc2012-06-28 03:57:45 +000014481 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010014482 if (!msg)
14483 return;
14484
Johannes Bergcf5ead82014-11-14 17:14:00 +010014485 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
John W. Linville66266b32012-03-15 13:25:41 -040014486 rdev, dev, mac_addr, sinfo) < 0) {
Johannes Berg98b62182009-12-23 13:15:44 +010014487 nlmsg_free(msg);
14488 return;
14489 }
14490
Johannes Berg68eb5502013-11-19 15:19:38 +010014491 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014492 NL80211_MCGRP_MLME, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010014493}
Johannes Berg947add32013-02-22 22:05:20 +010014494EXPORT_SYMBOL(cfg80211_new_sta);
Johannes Berg98b62182009-12-23 13:15:44 +010014495
Johannes Bergcf5ead82014-11-14 17:14:00 +010014496void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
14497 struct station_info *sinfo, gfp_t gfp)
Jouni Malinenec15e682011-03-23 15:29:52 +020014498{
Johannes Berg947add32013-02-22 22:05:20 +010014499 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014500 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinenec15e682011-03-23 15:29:52 +020014501 struct sk_buff *msg;
Johannes Bergcf5ead82014-11-14 17:14:00 +010014502 struct station_info empty_sinfo = {};
14503
14504 if (!sinfo)
14505 sinfo = &empty_sinfo;
Jouni Malinenec15e682011-03-23 15:29:52 +020014506
Johannes Berg947add32013-02-22 22:05:20 +010014507 trace_cfg80211_del_sta(dev, mac_addr);
14508
Thomas Graf58050fc2012-06-28 03:57:45 +000014509 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020014510 if (!msg)
14511 return;
14512
Johannes Bergcf5ead82014-11-14 17:14:00 +010014513 if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
Johannes Berg57007122015-01-16 21:05:02 +010014514 rdev, dev, mac_addr, sinfo) < 0) {
Jouni Malinenec15e682011-03-23 15:29:52 +020014515 nlmsg_free(msg);
14516 return;
14517 }
14518
Johannes Berg68eb5502013-11-19 15:19:38 +010014519 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014520 NL80211_MCGRP_MLME, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020014521}
Johannes Bergcf5ead82014-11-14 17:14:00 +010014522EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
Jouni Malinenec15e682011-03-23 15:29:52 +020014523
Johannes Berg947add32013-02-22 22:05:20 +010014524void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
14525 enum nl80211_connect_failed_reason reason,
14526 gfp_t gfp)
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053014527{
Johannes Berg947add32013-02-22 22:05:20 +010014528 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014529 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053014530 struct sk_buff *msg;
14531 void *hdr;
14532
14533 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
14534 if (!msg)
14535 return;
14536
14537 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED);
14538 if (!hdr) {
14539 nlmsg_free(msg);
14540 return;
14541 }
14542
14543 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14544 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
14545 nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason))
14546 goto nla_put_failure;
14547
14548 genlmsg_end(msg, hdr);
14549
Johannes Berg68eb5502013-11-19 15:19:38 +010014550 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014551 NL80211_MCGRP_MLME, gfp);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053014552 return;
14553
14554 nla_put_failure:
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053014555 nlmsg_free(msg);
14556}
Johannes Berg947add32013-02-22 22:05:20 +010014557EXPORT_SYMBOL(cfg80211_conn_failed);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053014558
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014559static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
14560 const u8 *addr, gfp_t gfp)
Johannes Berg28946da2011-11-04 11:18:12 +010014561{
14562 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014563 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg28946da2011-11-04 11:18:12 +010014564 struct sk_buff *msg;
14565 void *hdr;
Mark Rutland6aa7de02017-10-23 14:07:29 -070014566 u32 nlportid = READ_ONCE(wdev->ap_unexpected_nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010014567
Eric W. Biederman15e47302012-09-07 20:12:54 +000014568 if (!nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010014569 return false;
14570
14571 msg = nlmsg_new(100, gfp);
14572 if (!msg)
14573 return true;
14574
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014575 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Johannes Berg28946da2011-11-04 11:18:12 +010014576 if (!hdr) {
14577 nlmsg_free(msg);
14578 return true;
14579 }
14580
David S. Miller9360ffd2012-03-29 04:41:26 -040014581 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14582 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14583 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
14584 goto nla_put_failure;
Johannes Berg28946da2011-11-04 11:18:12 +010014585
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014586 genlmsg_end(msg, hdr);
Eric W. Biederman15e47302012-09-07 20:12:54 +000014587 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010014588 return true;
14589
14590 nla_put_failure:
Johannes Berg28946da2011-11-04 11:18:12 +010014591 nlmsg_free(msg);
14592 return true;
14593}
14594
Johannes Berg947add32013-02-22 22:05:20 +010014595bool cfg80211_rx_spurious_frame(struct net_device *dev,
14596 const u8 *addr, gfp_t gfp)
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014597{
Johannes Berg947add32013-02-22 22:05:20 +010014598 struct wireless_dev *wdev = dev->ieee80211_ptr;
14599 bool ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014600
Johannes Berg947add32013-02-22 22:05:20 +010014601 trace_cfg80211_rx_spurious_frame(dev, addr);
14602
14603 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
14604 wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
14605 trace_cfg80211_return_bool(false);
14606 return false;
14607 }
14608 ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
14609 addr, gfp);
14610 trace_cfg80211_return_bool(ret);
14611 return ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014612}
Johannes Berg947add32013-02-22 22:05:20 +010014613EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
14614
14615bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
14616 const u8 *addr, gfp_t gfp)
14617{
14618 struct wireless_dev *wdev = dev->ieee80211_ptr;
14619 bool ret;
14620
14621 trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
14622
14623 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
14624 wdev->iftype != NL80211_IFTYPE_P2P_GO &&
14625 wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
14626 trace_cfg80211_return_bool(false);
14627 return false;
14628 }
14629 ret = __nl80211_unexpected_frame(dev,
14630 NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
14631 addr, gfp);
14632 trace_cfg80211_return_bool(ret);
14633 return ret;
14634}
14635EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014636
Johannes Berg2e161f72010-08-12 15:38:38 +020014637int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000014638 struct wireless_dev *wdev, u32 nlportid,
Johannes Berg804483e2012-03-05 22:18:41 +010014639 int freq, int sig_dbm,
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030014640 const u8 *buf, size_t len, u32 flags, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020014641{
Johannes Berg71bbc992012-06-15 15:30:18 +020014642 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020014643 struct sk_buff *msg;
14644 void *hdr;
Jouni Malinen026331c2010-02-15 12:53:10 +020014645
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014646 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014647 if (!msg)
14648 return -ENOMEM;
14649
Johannes Berg2e161f72010-08-12 15:38:38 +020014650 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
Jouni Malinen026331c2010-02-15 12:53:10 +020014651 if (!hdr) {
14652 nlmsg_free(msg);
14653 return -ENOMEM;
14654 }
14655
David S. Miller9360ffd2012-03-29 04:41:26 -040014656 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020014657 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14658 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014659 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14660 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014661 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
14662 (sig_dbm &&
14663 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030014664 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
14665 (flags &&
14666 nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
David S. Miller9360ffd2012-03-29 04:41:26 -040014667 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020014668
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014669 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020014670
Eric W. Biederman15e47302012-09-07 20:12:54 +000014671 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Jouni Malinen026331c2010-02-15 12:53:10 +020014672
14673 nla_put_failure:
Jouni Malinen026331c2010-02-15 12:53:10 +020014674 nlmsg_free(msg);
14675 return -ENOBUFS;
14676}
14677
Johannes Berg947add32013-02-22 22:05:20 +010014678void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
14679 const u8 *buf, size_t len, bool ack, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020014680{
Johannes Berg947add32013-02-22 22:05:20 +010014681 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014682 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg71bbc992012-06-15 15:30:18 +020014683 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020014684 struct sk_buff *msg;
14685 void *hdr;
14686
Johannes Berg947add32013-02-22 22:05:20 +010014687 trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
14688
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014689 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014690 if (!msg)
14691 return;
14692
Johannes Berg2e161f72010-08-12 15:38:38 +020014693 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
Jouni Malinen026331c2010-02-15 12:53:10 +020014694 if (!hdr) {
14695 nlmsg_free(msg);
14696 return;
14697 }
14698
David S. Miller9360ffd2012-03-29 04:41:26 -040014699 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020014700 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14701 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014702 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14703 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014704 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014705 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14706 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014707 (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
14708 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020014709
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014710 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020014711
Johannes Berg68eb5502013-11-19 15:19:38 +010014712 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014713 NL80211_MCGRP_MLME, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014714 return;
14715
14716 nla_put_failure:
Jouni Malinen026331c2010-02-15 12:53:10 +020014717 nlmsg_free(msg);
14718}
Johannes Berg947add32013-02-22 22:05:20 +010014719EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
Jouni Malinen026331c2010-02-15 12:53:10 +020014720
Denis Kenzior6a671a52018-03-26 12:52:41 -050014721static int __nl80211_rx_control_port(struct net_device *dev,
14722 const u8 *buf, size_t len,
14723 const u8 *addr, u16 proto,
14724 bool unencrypted, gfp_t gfp)
14725{
14726 struct wireless_dev *wdev = dev->ieee80211_ptr;
14727 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
14728 struct sk_buff *msg;
14729 void *hdr;
14730 u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid);
14731
14732 if (!nlportid)
14733 return -ENOENT;
14734
14735 msg = nlmsg_new(100 + len, gfp);
14736 if (!msg)
14737 return -ENOMEM;
14738
14739 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME);
14740 if (!hdr) {
14741 nlmsg_free(msg);
14742 return -ENOBUFS;
14743 }
14744
14745 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14746 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14747 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14748 NL80211_ATTR_PAD) ||
14749 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
14750 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
14751 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
14752 (unencrypted && nla_put_flag(msg,
14753 NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
14754 goto nla_put_failure;
14755
14756 genlmsg_end(msg, hdr);
14757
14758 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
14759
14760 nla_put_failure:
14761 nlmsg_free(msg);
14762 return -ENOBUFS;
14763}
14764
14765bool cfg80211_rx_control_port(struct net_device *dev,
14766 const u8 *buf, size_t len,
14767 const u8 *addr, u16 proto, bool unencrypted)
14768{
14769 int ret;
14770
14771 trace_cfg80211_rx_control_port(dev, buf, len, addr, proto, unencrypted);
14772 ret = __nl80211_rx_control_port(dev, buf, len, addr, proto,
14773 unencrypted, GFP_ATOMIC);
14774 trace_cfg80211_return_bool(ret == 0);
14775 return ret == 0;
14776}
14777EXPORT_SYMBOL(cfg80211_rx_control_port);
14778
Johannes Berg5b97f492014-11-26 12:37:43 +010014779static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
14780 const char *mac, gfp_t gfp)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014781{
Johannes Berg947add32013-02-22 22:05:20 +010014782 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg5b97f492014-11-26 12:37:43 +010014783 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
14784 struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14785 void **cb;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014786
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014787 if (!msg)
Johannes Berg5b97f492014-11-26 12:37:43 +010014788 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014789
Johannes Berg5b97f492014-11-26 12:37:43 +010014790 cb = (void **)msg->cb;
14791
14792 cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
14793 if (!cb[0]) {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014794 nlmsg_free(msg);
Johannes Berg5b97f492014-11-26 12:37:43 +010014795 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014796 }
14797
David S. Miller9360ffd2012-03-29 04:41:26 -040014798 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010014799 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
David S. Miller9360ffd2012-03-29 04:41:26 -040014800 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014801
Johannes Berg5b97f492014-11-26 12:37:43 +010014802 if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014803 goto nla_put_failure;
14804
Johannes Berg5b97f492014-11-26 12:37:43 +010014805 cb[1] = nla_nest_start(msg, NL80211_ATTR_CQM);
14806 if (!cb[1])
14807 goto nla_put_failure;
14808
14809 cb[2] = rdev;
14810
14811 return msg;
14812 nla_put_failure:
14813 nlmsg_free(msg);
14814 return NULL;
14815}
14816
14817static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
14818{
14819 void **cb = (void **)msg->cb;
14820 struct cfg80211_registered_device *rdev = cb[2];
14821
14822 nla_nest_end(msg, cb[1]);
14823 genlmsg_end(msg, cb[0]);
14824
14825 memset(msg->cb, 0, sizeof(msg->cb));
14826
14827 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
14828 NL80211_MCGRP_MLME, gfp);
14829}
14830
14831void cfg80211_cqm_rssi_notify(struct net_device *dev,
14832 enum nl80211_cqm_rssi_threshold_event rssi_event,
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010014833 s32 rssi_level, gfp_t gfp)
Johannes Berg5b97f492014-11-26 12:37:43 +010014834{
14835 struct sk_buff *msg;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010014836 struct wireless_dev *wdev = dev->ieee80211_ptr;
14837 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg5b97f492014-11-26 12:37:43 +010014838
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010014839 trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
Johannes Berg5b97f492014-11-26 12:37:43 +010014840
Johannes Berg98f03342014-11-26 12:42:02 +010014841 if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
14842 rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
14843 return;
14844
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010014845 if (wdev->cqm_config) {
14846 wdev->cqm_config->last_rssi_event_value = rssi_level;
14847
14848 cfg80211_cqm_rssi_update(rdev, dev);
14849
14850 if (rssi_level == 0)
14851 rssi_level = wdev->cqm_config->last_rssi_event_value;
14852 }
14853
Johannes Berg5b97f492014-11-26 12:37:43 +010014854 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
14855 if (!msg)
14856 return;
14857
David S. Miller9360ffd2012-03-29 04:41:26 -040014858 if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
14859 rssi_event))
14860 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014861
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010014862 if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
14863 rssi_level))
14864 goto nla_put_failure;
14865
Johannes Berg5b97f492014-11-26 12:37:43 +010014866 cfg80211_send_cqm(msg, gfp);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014867
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014868 return;
14869
14870 nla_put_failure:
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014871 nlmsg_free(msg);
14872}
Johannes Berg947add32013-02-22 22:05:20 +010014873EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014874
Johannes Berg5b97f492014-11-26 12:37:43 +010014875void cfg80211_cqm_txe_notify(struct net_device *dev,
14876 const u8 *peer, u32 num_packets,
14877 u32 rate, u32 intvl, gfp_t gfp)
14878{
14879 struct sk_buff *msg;
14880
14881 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14882 if (!msg)
14883 return;
14884
14885 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
14886 goto nla_put_failure;
14887
14888 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
14889 goto nla_put_failure;
14890
14891 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
14892 goto nla_put_failure;
14893
14894 cfg80211_send_cqm(msg, gfp);
14895 return;
14896
14897 nla_put_failure:
14898 nlmsg_free(msg);
14899}
14900EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
14901
14902void cfg80211_cqm_pktloss_notify(struct net_device *dev,
14903 const u8 *peer, u32 num_packets, gfp_t gfp)
14904{
14905 struct sk_buff *msg;
14906
14907 trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
14908
14909 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14910 if (!msg)
14911 return;
14912
14913 if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
14914 goto nla_put_failure;
14915
14916 cfg80211_send_cqm(msg, gfp);
14917 return;
14918
14919 nla_put_failure:
14920 nlmsg_free(msg);
14921}
14922EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
14923
Johannes Berg98f03342014-11-26 12:42:02 +010014924void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
14925{
14926 struct sk_buff *msg;
14927
14928 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
14929 if (!msg)
14930 return;
14931
14932 if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
14933 goto nla_put_failure;
14934
14935 cfg80211_send_cqm(msg, gfp);
14936 return;
14937
14938 nla_put_failure:
14939 nlmsg_free(msg);
14940}
14941EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
14942
Johannes Berg947add32013-02-22 22:05:20 +010014943static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
14944 struct net_device *netdev, const u8 *bssid,
14945 const u8 *replay_ctr, gfp_t gfp)
Johannes Berge5497d72011-07-05 16:35:40 +020014946{
14947 struct sk_buff *msg;
14948 struct nlattr *rekey_attr;
14949 void *hdr;
14950
Thomas Graf58050fc2012-06-28 03:57:45 +000014951 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014952 if (!msg)
14953 return;
14954
14955 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
14956 if (!hdr) {
14957 nlmsg_free(msg);
14958 return;
14959 }
14960
David S. Miller9360ffd2012-03-29 04:41:26 -040014961 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14962 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14963 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
14964 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014965
14966 rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
14967 if (!rekey_attr)
14968 goto nla_put_failure;
14969
David S. Miller9360ffd2012-03-29 04:41:26 -040014970 if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
14971 NL80211_REPLAY_CTR_LEN, replay_ctr))
14972 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014973
14974 nla_nest_end(msg, rekey_attr);
14975
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014976 genlmsg_end(msg, hdr);
Johannes Berge5497d72011-07-05 16:35:40 +020014977
Johannes Berg68eb5502013-11-19 15:19:38 +010014978 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014979 NL80211_MCGRP_MLME, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014980 return;
14981
14982 nla_put_failure:
Johannes Berge5497d72011-07-05 16:35:40 +020014983 nlmsg_free(msg);
14984}
14985
Johannes Berg947add32013-02-22 22:05:20 +010014986void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
14987 const u8 *replay_ctr, gfp_t gfp)
14988{
14989 struct wireless_dev *wdev = dev->ieee80211_ptr;
14990 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014991 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014992
14993 trace_cfg80211_gtk_rekey_notify(dev, bssid);
14994 nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
14995}
14996EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
14997
14998static void
14999nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
15000 struct net_device *netdev, int index,
15001 const u8 *bssid, bool preauth, gfp_t gfp)
Jouni Malinenc9df56b2011-09-16 18:56:23 +030015002{
15003 struct sk_buff *msg;
15004 struct nlattr *attr;
15005 void *hdr;
15006
Thomas Graf58050fc2012-06-28 03:57:45 +000015007 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030015008 if (!msg)
15009 return;
15010
15011 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
15012 if (!hdr) {
15013 nlmsg_free(msg);
15014 return;
15015 }
15016
David S. Miller9360ffd2012-03-29 04:41:26 -040015017 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15018 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
15019 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030015020
15021 attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE);
15022 if (!attr)
15023 goto nla_put_failure;
15024
David S. Miller9360ffd2012-03-29 04:41:26 -040015025 if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
15026 nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
15027 (preauth &&
15028 nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
15029 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030015030
15031 nla_nest_end(msg, attr);
15032
Johannes Berg3b7b72e2011-10-22 19:05:51 +020015033 genlmsg_end(msg, hdr);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030015034
Johannes Berg68eb5502013-11-19 15:19:38 +010015035 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015036 NL80211_MCGRP_MLME, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030015037 return;
15038
15039 nla_put_failure:
Jouni Malinenc9df56b2011-09-16 18:56:23 +030015040 nlmsg_free(msg);
15041}
15042
Johannes Berg947add32013-02-22 22:05:20 +010015043void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
15044 const u8 *bssid, bool preauth, gfp_t gfp)
15045{
15046 struct wireless_dev *wdev = dev->ieee80211_ptr;
15047 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015048 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010015049
15050 trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
15051 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
15052}
15053EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
15054
15055static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
15056 struct net_device *netdev,
15057 struct cfg80211_chan_def *chandef,
Luciano Coelhof8d75522014-11-07 14:31:35 +020015058 gfp_t gfp,
15059 enum nl80211_commands notif,
15060 u8 count)
Thomas Pedersen53145262012-04-06 13:35:47 -070015061{
15062 struct sk_buff *msg;
15063 void *hdr;
15064
Thomas Graf58050fc2012-06-28 03:57:45 +000015065 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070015066 if (!msg)
15067 return;
15068
Luciano Coelhof8d75522014-11-07 14:31:35 +020015069 hdr = nl80211hdr_put(msg, 0, 0, 0, notif);
Thomas Pedersen53145262012-04-06 13:35:47 -070015070 if (!hdr) {
15071 nlmsg_free(msg);
15072 return;
15073 }
15074
Johannes Berg683b6d32012-11-08 21:25:48 +010015075 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
15076 goto nla_put_failure;
15077
15078 if (nl80211_send_chandef(msg, chandef))
John W. Linville7eab0f62012-04-12 14:25:14 -040015079 goto nla_put_failure;
Thomas Pedersen53145262012-04-06 13:35:47 -070015080
Luciano Coelhof8d75522014-11-07 14:31:35 +020015081 if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) &&
15082 (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count)))
15083 goto nla_put_failure;
15084
Thomas Pedersen53145262012-04-06 13:35:47 -070015085 genlmsg_end(msg, hdr);
15086
Johannes Berg68eb5502013-11-19 15:19:38 +010015087 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015088 NL80211_MCGRP_MLME, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070015089 return;
15090
15091 nla_put_failure:
Thomas Pedersen53145262012-04-06 13:35:47 -070015092 nlmsg_free(msg);
15093}
15094
Johannes Berg947add32013-02-22 22:05:20 +010015095void cfg80211_ch_switch_notify(struct net_device *dev,
15096 struct cfg80211_chan_def *chandef)
Thomas Pedersen84f10702012-07-12 16:17:33 -070015097{
Johannes Berg947add32013-02-22 22:05:20 +010015098 struct wireless_dev *wdev = dev->ieee80211_ptr;
15099 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015100 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010015101
Simon Wunderliche487eae2013-11-21 18:19:51 +010015102 ASSERT_WDEV_LOCK(wdev);
Johannes Berg947add32013-02-22 22:05:20 +010015103
Simon Wunderliche487eae2013-11-21 18:19:51 +010015104 trace_cfg80211_ch_switch_notify(dev, chandef);
Johannes Berg947add32013-02-22 22:05:20 +010015105
Michal Kazior9e0e2962014-01-29 14:22:27 +010015106 wdev->chandef = *chandef;
Janusz Dziedzic96f55f12014-01-24 14:29:21 +010015107 wdev->preset_chandef = *chandef;
Luciano Coelhof8d75522014-11-07 14:31:35 +020015108 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
15109 NL80211_CMD_CH_SWITCH_NOTIFY, 0);
Johannes Berg947add32013-02-22 22:05:20 +010015110}
15111EXPORT_SYMBOL(cfg80211_ch_switch_notify);
15112
Luciano Coelhof8d75522014-11-07 14:31:35 +020015113void cfg80211_ch_switch_started_notify(struct net_device *dev,
15114 struct cfg80211_chan_def *chandef,
15115 u8 count)
15116{
15117 struct wireless_dev *wdev = dev->ieee80211_ptr;
15118 struct wiphy *wiphy = wdev->wiphy;
15119 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
15120
15121 trace_cfg80211_ch_switch_started_notify(dev, chandef);
15122
15123 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
15124 NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count);
15125}
15126EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
15127
Thomas Pedersen84f10702012-07-12 16:17:33 -070015128void
Simon Wunderlich04f39042013-02-08 18:16:19 +010015129nl80211_radar_notify(struct cfg80211_registered_device *rdev,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +010015130 const struct cfg80211_chan_def *chandef,
Simon Wunderlich04f39042013-02-08 18:16:19 +010015131 enum nl80211_radar_event event,
15132 struct net_device *netdev, gfp_t gfp)
15133{
15134 struct sk_buff *msg;
15135 void *hdr;
15136
15137 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15138 if (!msg)
15139 return;
15140
15141 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
15142 if (!hdr) {
15143 nlmsg_free(msg);
15144 return;
15145 }
15146
15147 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
15148 goto nla_put_failure;
15149
15150 /* NOP and radar events don't need a netdev parameter */
15151 if (netdev) {
15152 struct wireless_dev *wdev = netdev->ieee80211_ptr;
15153
15154 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015155 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15156 NL80211_ATTR_PAD))
Simon Wunderlich04f39042013-02-08 18:16:19 +010015157 goto nla_put_failure;
15158 }
15159
15160 if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
15161 goto nla_put_failure;
15162
15163 if (nl80211_send_chandef(msg, chandef))
15164 goto nla_put_failure;
15165
Johannes Berg9c90a9f2013-06-04 12:46:03 +020015166 genlmsg_end(msg, hdr);
Simon Wunderlich04f39042013-02-08 18:16:19 +010015167
Johannes Berg68eb5502013-11-19 15:19:38 +010015168 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015169 NL80211_MCGRP_MLME, gfp);
Simon Wunderlich04f39042013-02-08 18:16:19 +010015170 return;
15171
15172 nla_put_failure:
Simon Wunderlich04f39042013-02-08 18:16:19 +010015173 nlmsg_free(msg);
15174}
15175
tamizhr@codeaurora.org466b9932018-01-31 16:24:49 +053015176void cfg80211_sta_opmode_change_notify(struct net_device *dev, const u8 *mac,
15177 struct sta_opmode_info *sta_opmode,
15178 gfp_t gfp)
15179{
15180 struct sk_buff *msg;
15181 struct wireless_dev *wdev = dev->ieee80211_ptr;
15182 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
15183 void *hdr;
15184
15185 if (WARN_ON(!mac))
15186 return;
15187
15188 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15189 if (!msg)
15190 return;
15191
15192 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STA_OPMODE_CHANGED);
15193 if (!hdr) {
15194 nlmsg_free(msg);
15195 return;
15196 }
15197
15198 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
15199 goto nla_put_failure;
15200
15201 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
15202 goto nla_put_failure;
15203
15204 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
15205 goto nla_put_failure;
15206
15207 if ((sta_opmode->changed & STA_OPMODE_SMPS_MODE_CHANGED) &&
15208 nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, sta_opmode->smps_mode))
15209 goto nla_put_failure;
15210
15211 if ((sta_opmode->changed & STA_OPMODE_MAX_BW_CHANGED) &&
15212 nla_put_u8(msg, NL80211_ATTR_CHANNEL_WIDTH, sta_opmode->bw))
15213 goto nla_put_failure;
15214
15215 if ((sta_opmode->changed & STA_OPMODE_N_SS_CHANGED) &&
15216 nla_put_u8(msg, NL80211_ATTR_NSS, sta_opmode->rx_nss))
15217 goto nla_put_failure;
15218
15219 genlmsg_end(msg, hdr);
15220
15221 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
15222 NL80211_MCGRP_MLME, gfp);
15223
15224 return;
15225
15226nla_put_failure:
15227 nlmsg_free(msg);
15228}
15229EXPORT_SYMBOL(cfg80211_sta_opmode_change_notify);
15230
Johannes Berg7f6cf312011-11-04 11:18:15 +010015231void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
Venkateswara Naralasettyc4b50cd2018-02-13 11:03:06 +053015232 u64 cookie, bool acked, s32 ack_signal,
15233 bool is_valid_ack_signal, gfp_t gfp)
Johannes Berg7f6cf312011-11-04 11:18:15 +010015234{
15235 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015236 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg7f6cf312011-11-04 11:18:15 +010015237 struct sk_buff *msg;
15238 void *hdr;
Johannes Berg7f6cf312011-11-04 11:18:15 +010015239
Beni Lev4ee3e062012-08-27 12:49:39 +030015240 trace_cfg80211_probe_status(dev, addr, cookie, acked);
15241
Thomas Graf58050fc2012-06-28 03:57:45 +000015242 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Beni Lev4ee3e062012-08-27 12:49:39 +030015243
Johannes Berg7f6cf312011-11-04 11:18:15 +010015244 if (!msg)
15245 return;
15246
15247 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
15248 if (!hdr) {
15249 nlmsg_free(msg);
15250 return;
15251 }
15252
David S. Miller9360ffd2012-03-29 04:41:26 -040015253 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15254 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
15255 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015256 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
15257 NL80211_ATTR_PAD) ||
Venkateswara Naralasettyc4b50cd2018-02-13 11:03:06 +053015258 (acked && nla_put_flag(msg, NL80211_ATTR_ACK)) ||
15259 (is_valid_ack_signal && nla_put_s32(msg, NL80211_ATTR_ACK_SIGNAL,
15260 ack_signal)))
David S. Miller9360ffd2012-03-29 04:41:26 -040015261 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010015262
Johannes Berg9c90a9f2013-06-04 12:46:03 +020015263 genlmsg_end(msg, hdr);
Johannes Berg7f6cf312011-11-04 11:18:15 +010015264
Johannes Berg68eb5502013-11-19 15:19:38 +010015265 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015266 NL80211_MCGRP_MLME, gfp);
Johannes Berg7f6cf312011-11-04 11:18:15 +010015267 return;
15268
15269 nla_put_failure:
Johannes Berg7f6cf312011-11-04 11:18:15 +010015270 nlmsg_free(msg);
15271}
15272EXPORT_SYMBOL(cfg80211_probe_status);
15273
Johannes Berg5e760232011-11-04 11:18:17 +010015274void cfg80211_report_obss_beacon(struct wiphy *wiphy,
15275 const u8 *frame, size_t len,
Ben Greear37c73b52012-10-26 14:49:25 -070015276 int freq, int sig_dbm)
Johannes Berg5e760232011-11-04 11:18:17 +010015277{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015278 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg5e760232011-11-04 11:18:17 +010015279 struct sk_buff *msg;
15280 void *hdr;
Ben Greear37c73b52012-10-26 14:49:25 -070015281 struct cfg80211_beacon_registration *reg;
Johannes Berg5e760232011-11-04 11:18:17 +010015282
Beni Lev4ee3e062012-08-27 12:49:39 +030015283 trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
15284
Ben Greear37c73b52012-10-26 14:49:25 -070015285 spin_lock_bh(&rdev->beacon_registrations_lock);
15286 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
15287 msg = nlmsg_new(len + 100, GFP_ATOMIC);
15288 if (!msg) {
15289 spin_unlock_bh(&rdev->beacon_registrations_lock);
15290 return;
15291 }
Johannes Berg5e760232011-11-04 11:18:17 +010015292
Ben Greear37c73b52012-10-26 14:49:25 -070015293 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
15294 if (!hdr)
15295 goto nla_put_failure;
Johannes Berg5e760232011-11-04 11:18:17 +010015296
Ben Greear37c73b52012-10-26 14:49:25 -070015297 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15298 (freq &&
15299 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
15300 (sig_dbm &&
15301 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
15302 nla_put(msg, NL80211_ATTR_FRAME, len, frame))
15303 goto nla_put_failure;
15304
15305 genlmsg_end(msg, hdr);
15306
15307 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
Johannes Berg5e760232011-11-04 11:18:17 +010015308 }
Ben Greear37c73b52012-10-26 14:49:25 -070015309 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010015310 return;
15311
15312 nla_put_failure:
Ben Greear37c73b52012-10-26 14:49:25 -070015313 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010015314 nlmsg_free(msg);
15315}
15316EXPORT_SYMBOL(cfg80211_report_obss_beacon);
15317
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015318#ifdef CONFIG_PM
Luciano Coelho8cd4d452014-09-17 11:55:28 +030015319static int cfg80211_net_detect_results(struct sk_buff *msg,
15320 struct cfg80211_wowlan_wakeup *wakeup)
15321{
15322 struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect;
15323 struct nlattr *nl_results, *nl_match, *nl_freqs;
15324 int i, j;
15325
15326 nl_results = nla_nest_start(
15327 msg, NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS);
15328 if (!nl_results)
15329 return -EMSGSIZE;
15330
15331 for (i = 0; i < nd->n_matches; i++) {
15332 struct cfg80211_wowlan_nd_match *match = nd->matches[i];
15333
15334 nl_match = nla_nest_start(msg, i);
15335 if (!nl_match)
15336 break;
15337
15338 /* The SSID attribute is optional in nl80211, but for
15339 * simplicity reasons it's always present in the
15340 * cfg80211 structure. If a driver can't pass the
15341 * SSID, that needs to be changed. A zero length SSID
15342 * is still a valid SSID (wildcard), so it cannot be
15343 * used for this purpose.
15344 */
15345 if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len,
15346 match->ssid.ssid)) {
15347 nla_nest_cancel(msg, nl_match);
15348 goto out;
15349 }
15350
15351 if (match->n_channels) {
15352 nl_freqs = nla_nest_start(
15353 msg, NL80211_ATTR_SCAN_FREQUENCIES);
15354 if (!nl_freqs) {
15355 nla_nest_cancel(msg, nl_match);
15356 goto out;
15357 }
15358
15359 for (j = 0; j < match->n_channels; j++) {
Samuel Tan5528fae82015-02-09 21:29:15 +020015360 if (nla_put_u32(msg, j, match->channels[j])) {
Luciano Coelho8cd4d452014-09-17 11:55:28 +030015361 nla_nest_cancel(msg, nl_freqs);
15362 nla_nest_cancel(msg, nl_match);
15363 goto out;
15364 }
15365 }
15366
15367 nla_nest_end(msg, nl_freqs);
15368 }
15369
15370 nla_nest_end(msg, nl_match);
15371 }
15372
15373out:
15374 nla_nest_end(msg, nl_results);
15375 return 0;
15376}
15377
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015378void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
15379 struct cfg80211_wowlan_wakeup *wakeup,
15380 gfp_t gfp)
15381{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015382 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015383 struct sk_buff *msg;
15384 void *hdr;
Johannes Berg9c90a9f2013-06-04 12:46:03 +020015385 int size = 200;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015386
15387 trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
15388
15389 if (wakeup)
15390 size += wakeup->packet_present_len;
15391
15392 msg = nlmsg_new(size, gfp);
15393 if (!msg)
15394 return;
15395
15396 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN);
15397 if (!hdr)
15398 goto free_msg;
15399
15400 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015401 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15402 NL80211_ATTR_PAD))
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015403 goto free_msg;
15404
15405 if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
15406 wdev->netdev->ifindex))
15407 goto free_msg;
15408
15409 if (wakeup) {
15410 struct nlattr *reasons;
15411
15412 reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
Johannes Berg7fa322c2013-10-25 11:16:58 +020015413 if (!reasons)
15414 goto free_msg;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015415
15416 if (wakeup->disconnect &&
15417 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
15418 goto free_msg;
15419 if (wakeup->magic_pkt &&
15420 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT))
15421 goto free_msg;
15422 if (wakeup->gtk_rekey_failure &&
15423 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE))
15424 goto free_msg;
15425 if (wakeup->eap_identity_req &&
15426 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST))
15427 goto free_msg;
15428 if (wakeup->four_way_handshake &&
15429 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE))
15430 goto free_msg;
15431 if (wakeup->rfkill_release &&
15432 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))
15433 goto free_msg;
15434
15435 if (wakeup->pattern_idx >= 0 &&
15436 nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
15437 wakeup->pattern_idx))
15438 goto free_msg;
15439
Johannes Bergae917c92013-10-25 11:05:22 +020015440 if (wakeup->tcp_match &&
15441 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
15442 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010015443
Johannes Bergae917c92013-10-25 11:05:22 +020015444 if (wakeup->tcp_connlost &&
15445 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
15446 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010015447
Johannes Bergae917c92013-10-25 11:05:22 +020015448 if (wakeup->tcp_nomoretokens &&
15449 nla_put_flag(msg,
15450 NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
15451 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010015452
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015453 if (wakeup->packet) {
15454 u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
15455 u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN;
15456
15457 if (!wakeup->packet_80211) {
15458 pkt_attr =
15459 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023;
15460 len_attr =
15461 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN;
15462 }
15463
15464 if (wakeup->packet_len &&
15465 nla_put_u32(msg, len_attr, wakeup->packet_len))
15466 goto free_msg;
15467
15468 if (nla_put(msg, pkt_attr, wakeup->packet_present_len,
15469 wakeup->packet))
15470 goto free_msg;
15471 }
15472
Luciano Coelho8cd4d452014-09-17 11:55:28 +030015473 if (wakeup->net_detect &&
15474 cfg80211_net_detect_results(msg, wakeup))
15475 goto free_msg;
15476
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015477 nla_nest_end(msg, reasons);
15478 }
15479
Johannes Berg9c90a9f2013-06-04 12:46:03 +020015480 genlmsg_end(msg, hdr);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015481
Johannes Berg68eb5502013-11-19 15:19:38 +010015482 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015483 NL80211_MCGRP_MLME, gfp);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015484 return;
15485
15486 free_msg:
15487 nlmsg_free(msg);
15488}
15489EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup);
15490#endif
15491
Jouni Malinen3475b092012-11-16 22:49:57 +020015492void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
15493 enum nl80211_tdls_operation oper,
15494 u16 reason_code, gfp_t gfp)
15495{
15496 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015497 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Jouni Malinen3475b092012-11-16 22:49:57 +020015498 struct sk_buff *msg;
15499 void *hdr;
Jouni Malinen3475b092012-11-16 22:49:57 +020015500
15501 trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
15502 reason_code);
15503
15504 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15505 if (!msg)
15506 return;
15507
15508 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
15509 if (!hdr) {
15510 nlmsg_free(msg);
15511 return;
15512 }
15513
15514 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15515 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
15516 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
15517 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
15518 (reason_code > 0 &&
15519 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
15520 goto nla_put_failure;
15521
Johannes Berg9c90a9f2013-06-04 12:46:03 +020015522 genlmsg_end(msg, hdr);
Jouni Malinen3475b092012-11-16 22:49:57 +020015523
Johannes Berg68eb5502013-11-19 15:19:38 +010015524 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015525 NL80211_MCGRP_MLME, gfp);
Jouni Malinen3475b092012-11-16 22:49:57 +020015526 return;
15527
15528 nla_put_failure:
Jouni Malinen3475b092012-11-16 22:49:57 +020015529 nlmsg_free(msg);
15530}
15531EXPORT_SYMBOL(cfg80211_tdls_oper_request);
15532
Jouni Malinen026331c2010-02-15 12:53:10 +020015533static int nl80211_netlink_notify(struct notifier_block * nb,
15534 unsigned long state,
15535 void *_notify)
15536{
15537 struct netlink_notify *notify = _notify;
15538 struct cfg80211_registered_device *rdev;
15539 struct wireless_dev *wdev;
Ben Greear37c73b52012-10-26 14:49:25 -070015540 struct cfg80211_beacon_registration *reg, *tmp;
Jouni Malinen026331c2010-02-15 12:53:10 +020015541
Dmitry Ivanov8f815cd2016-04-06 17:23:18 +030015542 if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
Jouni Malinen026331c2010-02-15 12:53:10 +020015543 return NOTIFY_DONE;
15544
15545 rcu_read_lock();
15546
Johannes Berg5e760232011-11-04 11:18:17 +010015547 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
Arend Van Sprielca986ad2017-04-21 13:05:00 +010015548 struct cfg80211_sched_scan_request *sched_scan_req;
Jukka Rissanen93a1e862014-12-15 13:25:39 +020015549
Arend Van Sprielca986ad2017-04-21 13:05:00 +010015550 list_for_each_entry_rcu(sched_scan_req,
15551 &rdev->sched_scan_req_list,
15552 list) {
15553 if (sched_scan_req->owner_nlportid == notify->portid) {
15554 sched_scan_req->nl_owner_dead = true;
Johannes Berg753aacf2017-01-05 10:57:14 +010015555 schedule_work(&rdev->sched_scan_stop_wk);
Arend Van Sprielca986ad2017-04-21 13:05:00 +010015556 }
Johannes Berg753aacf2017-01-05 10:57:14 +010015557 }
Johannes Berg78f22b62014-03-24 17:57:27 +010015558
Johannes Berg53873f12016-05-03 16:52:04 +030015559 list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
Eric W. Biederman15e47302012-09-07 20:12:54 +000015560 cfg80211_mlme_unregister_socket(wdev, notify->portid);
Ben Greear37c73b52012-10-26 14:49:25 -070015561
Johannes Bergab810072017-04-26 07:43:41 +020015562 if (wdev->owner_nlportid == notify->portid) {
15563 wdev->nl_owner_dead = true;
15564 schedule_work(&rdev->destroy_work);
15565 } else if (wdev->conn_owner_nlportid == notify->portid) {
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050015566 schedule_work(&wdev->disconnect_wk);
Johannes Bergab810072017-04-26 07:43:41 +020015567 }
Johannes Berg78f22b62014-03-24 17:57:27 +010015568 }
15569
Ben Greear37c73b52012-10-26 14:49:25 -070015570 spin_lock_bh(&rdev->beacon_registrations_lock);
15571 list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
15572 list) {
15573 if (reg->nlportid == notify->portid) {
15574 list_del(&reg->list);
15575 kfree(reg);
15576 break;
15577 }
15578 }
15579 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010015580 }
Jouni Malinen026331c2010-02-15 12:53:10 +020015581
15582 rcu_read_unlock();
15583
Ilan peer05050752015-03-04 00:32:06 -050015584 /*
15585 * It is possible that the user space process that is controlling the
15586 * indoor setting disappeared, so notify the regulatory core.
15587 */
15588 regulatory_netlink_notify(notify->portid);
Zhao, Gang6784c7d2014-04-21 12:53:04 +080015589 return NOTIFY_OK;
Jouni Malinen026331c2010-02-15 12:53:10 +020015590}
15591
15592static struct notifier_block nl80211_netlink_notifier = {
15593 .notifier_call = nl80211_netlink_notify,
15594};
15595
Jouni Malinen355199e2013-02-27 17:14:27 +020015596void cfg80211_ft_event(struct net_device *netdev,
15597 struct cfg80211_ft_event_params *ft_event)
15598{
15599 struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015600 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinen355199e2013-02-27 17:14:27 +020015601 struct sk_buff *msg;
15602 void *hdr;
Jouni Malinen355199e2013-02-27 17:14:27 +020015603
15604 trace_cfg80211_ft_event(wiphy, netdev, ft_event);
15605
15606 if (!ft_event->target_ap)
15607 return;
15608
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010015609 msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
Jouni Malinen355199e2013-02-27 17:14:27 +020015610 if (!msg)
15611 return;
15612
15613 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
Johannes Bergae917c92013-10-25 11:05:22 +020015614 if (!hdr)
15615 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020015616
Johannes Bergae917c92013-10-25 11:05:22 +020015617 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15618 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15619 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
15620 goto out;
15621
15622 if (ft_event->ies &&
15623 nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
15624 goto out;
15625 if (ft_event->ric_ies &&
15626 nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
15627 ft_event->ric_ies))
15628 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020015629
Johannes Berg9c90a9f2013-06-04 12:46:03 +020015630 genlmsg_end(msg, hdr);
Jouni Malinen355199e2013-02-27 17:14:27 +020015631
Johannes Berg68eb5502013-11-19 15:19:38 +010015632 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015633 NL80211_MCGRP_MLME, GFP_KERNEL);
Johannes Bergae917c92013-10-25 11:05:22 +020015634 return;
15635 out:
15636 nlmsg_free(msg);
Jouni Malinen355199e2013-02-27 17:14:27 +020015637}
15638EXPORT_SYMBOL(cfg80211_ft_event);
15639
Arend van Spriel5de17982013-04-18 15:49:00 +020015640void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
15641{
15642 struct cfg80211_registered_device *rdev;
15643 struct sk_buff *msg;
15644 void *hdr;
15645 u32 nlportid;
15646
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015647 rdev = wiphy_to_rdev(wdev->wiphy);
Arend van Spriel5de17982013-04-18 15:49:00 +020015648 if (!rdev->crit_proto_nlportid)
15649 return;
15650
15651 nlportid = rdev->crit_proto_nlportid;
15652 rdev->crit_proto_nlportid = 0;
15653
15654 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15655 if (!msg)
15656 return;
15657
15658 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
15659 if (!hdr)
15660 goto nla_put_failure;
15661
15662 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015663 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15664 NL80211_ATTR_PAD))
Arend van Spriel5de17982013-04-18 15:49:00 +020015665 goto nla_put_failure;
15666
15667 genlmsg_end(msg, hdr);
15668
15669 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
15670 return;
15671
15672 nla_put_failure:
Arend van Spriel5de17982013-04-18 15:49:00 +020015673 nlmsg_free(msg);
Arend van Spriel5de17982013-04-18 15:49:00 +020015674}
15675EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
15676
Johannes Berg348baf02014-01-24 14:06:29 +010015677void nl80211_send_ap_stopped(struct wireless_dev *wdev)
15678{
15679 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015680 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg348baf02014-01-24 14:06:29 +010015681 struct sk_buff *msg;
15682 void *hdr;
15683
15684 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
15685 if (!msg)
15686 return;
15687
15688 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
15689 if (!hdr)
15690 goto out;
15691
15692 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15693 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015694 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15695 NL80211_ATTR_PAD))
Johannes Berg348baf02014-01-24 14:06:29 +010015696 goto out;
15697
15698 genlmsg_end(msg, hdr);
15699
15700 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
15701 NL80211_MCGRP_MLME, GFP_KERNEL);
15702 return;
15703 out:
15704 nlmsg_free(msg);
15705}
15706
Srinivas Dasari40cbfa92018-01-25 17:13:38 +020015707int cfg80211_external_auth_request(struct net_device *dev,
15708 struct cfg80211_external_auth_params *params,
15709 gfp_t gfp)
15710{
15711 struct wireless_dev *wdev = dev->ieee80211_ptr;
15712 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
15713 struct sk_buff *msg;
15714 void *hdr;
15715
15716 if (!wdev->conn_owner_nlportid)
15717 return -EINVAL;
15718
15719 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15720 if (!msg)
15721 return -ENOMEM;
15722
15723 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_EXTERNAL_AUTH);
15724 if (!hdr)
15725 goto nla_put_failure;
15726
15727 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15728 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
15729 nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) ||
15730 nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION,
15731 params->action) ||
15732 nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) ||
15733 nla_put(msg, NL80211_ATTR_SSID, params->ssid.ssid_len,
15734 params->ssid.ssid))
15735 goto nla_put_failure;
15736
15737 genlmsg_end(msg, hdr);
15738 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
15739 wdev->conn_owner_nlportid);
15740 return 0;
15741
15742 nla_put_failure:
15743 nlmsg_free(msg);
15744 return -ENOBUFS;
15745}
15746EXPORT_SYMBOL(cfg80211_external_auth_request);
15747
Johannes Berg55682962007-09-20 13:09:35 -040015748/* initialisation/exit functions */
15749
Johannes Berg56989f62016-10-24 14:40:05 +020015750int __init nl80211_init(void)
Johannes Berg55682962007-09-20 13:09:35 -040015751{
Michał Mirosław0d63cbb2009-05-21 10:34:06 +000015752 int err;
Johannes Berg55682962007-09-20 13:09:35 -040015753
Johannes Berg489111e2016-10-24 14:40:03 +020015754 err = genl_register_family(&nl80211_fam);
Johannes Berg55682962007-09-20 13:09:35 -040015755 if (err)
15756 return err;
15757
Jouni Malinen026331c2010-02-15 12:53:10 +020015758 err = netlink_register_notifier(&nl80211_netlink_notifier);
15759 if (err)
15760 goto err_out;
15761
Johannes Berg55682962007-09-20 13:09:35 -040015762 return 0;
15763 err_out:
15764 genl_unregister_family(&nl80211_fam);
15765 return err;
15766}
15767
15768void nl80211_exit(void)
15769{
Jouni Malinen026331c2010-02-15 12:53:10 +020015770 netlink_unregister_notifier(&nl80211_netlink_notifier);
Johannes Berg55682962007-09-20 13:09:35 -040015771 genl_unregister_family(&nl80211_fam);
15772}