blob: 2b3dbcd40e46390debf84f4a127b23f185e76b39 [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
Johannes Berg55682962007-09-20 13:09:35 -04007 */
8
9#include <linux/if.h>
10#include <linux/module.h>
11#include <linux/err.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/slab.h>
Johannes Berg55682962007-09-20 13:09:35 -040013#include <linux/list.h>
14#include <linux/if_ether.h>
15#include <linux/ieee80211.h>
16#include <linux/nl80211.h>
17#include <linux/rtnetlink.h>
18#include <linux/netlink.h>
Johannes Berg2a519312009-02-10 21:25:55 +010019#include <linux/etherdevice.h>
Johannes Berg463d0182009-07-14 00:33:35 +020020#include <net/net_namespace.h>
Johannes Berg55682962007-09-20 13:09:35 -040021#include <net/genetlink.h>
22#include <net/cfg80211.h>
Johannes Berg463d0182009-07-14 00:33:35 +020023#include <net/sock.h>
Johannes Berg2a0e0472013-01-23 22:57:40 +010024#include <net/inet_connection_sock.h>
Johannes Berg55682962007-09-20 13:09:35 -040025#include "core.h"
26#include "nl80211.h"
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070027#include "reg.h"
Hila Gonene35e4d22012-06-27 17:19:42 +030028#include "rdev-ops.h"
Johannes Berg55682962007-09-20 13:09:35 -040029
Jouni Malinen5fb628e2011-08-10 23:54:35 +030030static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
31 struct genl_info *info,
32 struct cfg80211_crypto_settings *settings,
33 int cipher_limit);
34
Johannes Berg55682962007-09-20 13:09:35 -040035/* the netlink family */
Johannes Berg489111e2016-10-24 14:40:03 +020036static struct genl_family nl80211_fam;
Johannes Berg55682962007-09-20 13:09:35 -040037
Johannes Berg2a94fe42013-11-19 15:19:39 +010038/* multicast groups */
39enum nl80211_multicast_groups {
40 NL80211_MCGRP_CONFIG,
41 NL80211_MCGRP_SCAN,
42 NL80211_MCGRP_REGULATORY,
43 NL80211_MCGRP_MLME,
Johannes Berg567ffc32013-12-18 14:43:31 +010044 NL80211_MCGRP_VENDOR,
Ayala Beker50bcd312016-09-20 17:31:17 +030045 NL80211_MCGRP_NAN,
Johannes Berg2a94fe42013-11-19 15:19:39 +010046 NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
47};
48
49static const struct genl_multicast_group nl80211_mcgrps[] = {
Johannes Berg71b836e2014-12-23 17:17:38 +010050 [NL80211_MCGRP_CONFIG] = { .name = NL80211_MULTICAST_GROUP_CONFIG },
51 [NL80211_MCGRP_SCAN] = { .name = NL80211_MULTICAST_GROUP_SCAN },
52 [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG },
53 [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME },
54 [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR },
Ayala Beker50bcd312016-09-20 17:31:17 +030055 [NL80211_MCGRP_NAN] = { .name = NL80211_MULTICAST_GROUP_NAN },
Johannes Berg2a94fe42013-11-19 15:19:39 +010056#ifdef CONFIG_NL80211_TESTMODE
Johannes Berg71b836e2014-12-23 17:17:38 +010057 [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }
Johannes Berg2a94fe42013-11-19 15:19:39 +010058#endif
59};
60
Johannes Berg89a54e42012-06-15 14:33:17 +020061/* returns ERR_PTR values */
62static struct wireless_dev *
63__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
Johannes Berg55682962007-09-20 13:09:35 -040064{
Johannes Berg89a54e42012-06-15 14:33:17 +020065 struct cfg80211_registered_device *rdev;
66 struct wireless_dev *result = NULL;
67 bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
68 bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
69 u64 wdev_id;
70 int wiphy_idx = -1;
71 int ifidx = -1;
Johannes Berg55682962007-09-20 13:09:35 -040072
Johannes Berg5fe231e2013-05-08 21:45:15 +020073 ASSERT_RTNL();
Johannes Berg55682962007-09-20 13:09:35 -040074
Johannes Berg89a54e42012-06-15 14:33:17 +020075 if (!have_ifidx && !have_wdev_id)
76 return ERR_PTR(-EINVAL);
Johannes Berg55682962007-09-20 13:09:35 -040077
Johannes Berg89a54e42012-06-15 14:33:17 +020078 if (have_ifidx)
79 ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
80 if (have_wdev_id) {
81 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
82 wiphy_idx = wdev_id >> 32;
Johannes Berg55682962007-09-20 13:09:35 -040083 }
84
Johannes Berg89a54e42012-06-15 14:33:17 +020085 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
86 struct wireless_dev *wdev;
87
88 if (wiphy_net(&rdev->wiphy) != netns)
89 continue;
90
91 if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
92 continue;
93
Johannes Berg53873f12016-05-03 16:52:04 +030094 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Berg89a54e42012-06-15 14:33:17 +020095 if (have_ifidx && wdev->netdev &&
96 wdev->netdev->ifindex == ifidx) {
97 result = wdev;
98 break;
99 }
100 if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
101 result = wdev;
102 break;
103 }
104 }
Johannes Berg89a54e42012-06-15 14:33:17 +0200105
106 if (result)
107 break;
108 }
109
110 if (result)
111 return result;
112 return ERR_PTR(-ENODEV);
Johannes Berg55682962007-09-20 13:09:35 -0400113}
114
Johannes Berga9455402012-06-15 13:32:49 +0200115static struct cfg80211_registered_device *
Johannes Berg878d9ec2012-06-15 14:18:32 +0200116__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
Johannes Berga9455402012-06-15 13:32:49 +0200117{
Johannes Berg7fee4772012-06-15 14:09:58 +0200118 struct cfg80211_registered_device *rdev = NULL, *tmp;
119 struct net_device *netdev;
Johannes Berga9455402012-06-15 13:32:49 +0200120
Johannes Berg5fe231e2013-05-08 21:45:15 +0200121 ASSERT_RTNL();
Johannes Berga9455402012-06-15 13:32:49 +0200122
Johannes Berg878d9ec2012-06-15 14:18:32 +0200123 if (!attrs[NL80211_ATTR_WIPHY] &&
Johannes Berg89a54e42012-06-15 14:33:17 +0200124 !attrs[NL80211_ATTR_IFINDEX] &&
125 !attrs[NL80211_ATTR_WDEV])
Johannes Berg7fee4772012-06-15 14:09:58 +0200126 return ERR_PTR(-EINVAL);
127
Johannes Berg878d9ec2012-06-15 14:18:32 +0200128 if (attrs[NL80211_ATTR_WIPHY])
Johannes Berg7fee4772012-06-15 14:09:58 +0200129 rdev = cfg80211_rdev_by_wiphy_idx(
Johannes Berg878d9ec2012-06-15 14:18:32 +0200130 nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
Johannes Berga9455402012-06-15 13:32:49 +0200131
Johannes Berg89a54e42012-06-15 14:33:17 +0200132 if (attrs[NL80211_ATTR_WDEV]) {
133 u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
134 struct wireless_dev *wdev;
135 bool found = false;
136
137 tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
138 if (tmp) {
139 /* make sure wdev exists */
Johannes Berg53873f12016-05-03 16:52:04 +0300140 list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
Johannes Berg89a54e42012-06-15 14:33:17 +0200141 if (wdev->identifier != (u32)wdev_id)
142 continue;
143 found = true;
144 break;
145 }
Johannes Berg89a54e42012-06-15 14:33:17 +0200146
147 if (!found)
148 tmp = NULL;
149
150 if (rdev && tmp != rdev)
151 return ERR_PTR(-EINVAL);
152 rdev = tmp;
153 }
154 }
155
Johannes Berg878d9ec2012-06-15 14:18:32 +0200156 if (attrs[NL80211_ATTR_IFINDEX]) {
157 int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -0700158
Ying Xue7f2b8562014-01-15 10:23:45 +0800159 netdev = __dev_get_by_index(netns, ifindex);
Johannes Berg7fee4772012-06-15 14:09:58 +0200160 if (netdev) {
161 if (netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800162 tmp = wiphy_to_rdev(
163 netdev->ieee80211_ptr->wiphy);
Johannes Berg7fee4772012-06-15 14:09:58 +0200164 else
165 tmp = NULL;
166
Johannes Berg7fee4772012-06-15 14:09:58 +0200167 /* not wireless device -- return error */
168 if (!tmp)
169 return ERR_PTR(-EINVAL);
170
171 /* mismatch -- return error */
172 if (rdev && tmp != rdev)
173 return ERR_PTR(-EINVAL);
174
175 rdev = tmp;
Johannes Berga9455402012-06-15 13:32:49 +0200176 }
Johannes Berga9455402012-06-15 13:32:49 +0200177 }
178
Johannes Berg4f7eff12012-06-15 14:14:22 +0200179 if (!rdev)
180 return ERR_PTR(-ENODEV);
Johannes Berga9455402012-06-15 13:32:49 +0200181
Johannes Berg4f7eff12012-06-15 14:14:22 +0200182 if (netns != wiphy_net(&rdev->wiphy))
183 return ERR_PTR(-ENODEV);
184
185 return rdev;
Johannes Berga9455402012-06-15 13:32:49 +0200186}
187
188/*
189 * This function returns a pointer to the driver
190 * that the genl_info item that is passed refers to.
Johannes Berga9455402012-06-15 13:32:49 +0200191 *
192 * The result of this can be a PTR_ERR and hence must
193 * be checked with IS_ERR() for errors.
194 */
195static struct cfg80211_registered_device *
Johannes Berg4f7eff12012-06-15 14:14:22 +0200196cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
Johannes Berga9455402012-06-15 13:32:49 +0200197{
Johannes Berg5fe231e2013-05-08 21:45:15 +0200198 return __cfg80211_rdev_from_attrs(netns, info->attrs);
Johannes Berga9455402012-06-15 13:32:49 +0200199}
200
Johannes Berg55682962007-09-20 13:09:35 -0400201/* policy for the attributes */
Luciano Coelho8cd4d452014-09-17 11:55:28 +0300202static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
Johannes Berg55682962007-09-20 13:09:35 -0400203 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
204 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
David S. Miller079e24e2009-05-26 21:15:00 -0700205 .len = 20-1 },
Jouni Malinen31888482008-10-30 16:59:24 +0200206 [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100207
Jouni Malinen72bdcf32008-11-26 16:15:24 +0200208 [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
Sujith094d05d2008-12-12 11:57:43 +0530209 [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100210 [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
211 [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
212 [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
213
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +0200214 [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 },
215 [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
216 [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
217 [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
Lukáš Turek81077e82009-12-21 22:50:47 +0100218 [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +0200219 [NL80211_ATTR_WIPHY_DYN_ACK] = { .type = NLA_FLAG },
Johannes Berg55682962007-09-20 13:09:35 -0400220
221 [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
222 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
223 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
Johannes Berg41ade002007-12-19 02:03:29 +0100224
Eliad Pellere007b852011-11-24 18:13:56 +0200225 [NL80211_ATTR_MAC] = { .len = ETH_ALEN },
226 [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN },
Johannes Berg41ade002007-12-19 02:03:29 +0100227
Johannes Bergb9454e82009-07-08 13:29:08 +0200228 [NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
Johannes Berg41ade002007-12-19 02:03:29 +0100229 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
230 .len = WLAN_MAX_KEY_LEN },
231 [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
232 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
233 [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
Jouni Malinen81962262011-11-02 23:36:31 +0200234 [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Berge31b8212010-10-05 19:39:30 +0200235 [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
Johannes Berged1b6cc2007-12-19 02:03:32 +0100236
237 [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
238 [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
239 [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
240 .len = IEEE80211_MAX_DATA_LEN },
241 [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
242 .len = IEEE80211_MAX_DATA_LEN },
Johannes Berg5727ef12007-12-19 02:03:34 +0100243 [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
244 [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
245 [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
246 [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
247 .len = NL80211_MAX_SUPP_RATES },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100248 [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 },
Johannes Berg5727ef12007-12-19 02:03:34 +0100249 [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
Johannes Berg0a9542e2008-10-15 11:54:04 +0200250 [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100251 [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +0800252 .len = IEEE80211_MAX_MESH_ID_LEN },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100253 [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +0300254
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700255 [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
256 [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
257
Jouni Malinen9f1ba902008-08-07 20:07:01 +0300258 [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
259 [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
260 [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
Jouni Malinen90c97a02008-10-30 16:59:22 +0200261 [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY,
262 .len = NL80211_MAX_SUPP_RATES },
Helmut Schaa50b12f52010-11-19 12:40:25 +0100263 [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 },
Jouni Malinen36aedc92008-08-25 11:58:58 +0300264
Javier Cardona24bdd9f2010-12-16 17:37:48 -0800265 [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
Javier Cardona15d5dda2011-04-07 15:08:28 -0700266 [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -0700267
Johannes Berg6c739412011-11-03 09:27:01 +0100268 [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +0200269
270 [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
271 [NL80211_ATTR_IE] = { .type = NLA_BINARY,
272 .len = IEEE80211_MAX_DATA_LEN },
Johannes Berg2a519312009-02-10 21:25:55 +0100273 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
274 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
Jouni Malinen636a5d32009-03-19 13:39:22 +0200275
276 [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
277 .len = IEEE80211_MAX_SSID_LEN },
278 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
279 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
Johannes Berg04a773a2009-04-19 21:24:32 +0200280 [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
Jouni Malinen1965c852009-04-22 21:38:25 +0300281 [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
Jouni Malinendc6382ce2009-05-06 22:09:37 +0300282 [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 },
Johannes Bergeccb8e82009-05-11 21:57:56 +0300283 [NL80211_ATTR_STA_FLAGS2] = {
284 .len = sizeof(struct nl80211_sta_flag_update),
285 },
Jouni Malinen3f77316c2009-05-11 21:57:57 +0300286 [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
Johannes Bergc0692b82010-08-27 14:26:53 +0300287 [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
288 [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
Samuel Ortizb23aa672009-07-01 21:26:54 +0200289 [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
290 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
291 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
Johannes Berg463d0182009-07-14 00:33:35 +0200292 [NL80211_ATTR_PID] = { .type = NLA_U32 },
Felix Fietkau8b787642009-11-10 18:53:10 +0100293 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
Srinivas Dasari9361df12017-07-07 01:43:39 +0300294 [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN },
Jouni Malinen9588bbd2009-12-23 13:15:41 +0100295 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
296 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +0200297 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
Jouni Malinen026331c2010-02-15 12:53:10 +0200298 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
299 .len = IEEE80211_MAX_DATA_LEN },
300 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
Kalle Valoffb9eb32010-02-17 17:58:10 +0200301 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +0200302 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
Jouni Malinend5cdfac2010-04-04 09:37:19 +0300303 [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +0200304 [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +0300305 [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
306 [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
Johannes Berg2e161f72010-08-12 15:38:38 +0200307 [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
Bruno Randolfafe0cbf2010-11-10 12:50:50 +0900308 [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 },
309 [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
Felix Fietkau885a46d2010-11-11 15:07:22 +0100310 [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
Johannes Bergf7ca38d2010-11-25 10:02:29 +0100311 [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100312 [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200313 [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
Javier Cardona9c3990a2011-05-03 16:57:11 -0700314 [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
Luciano Coelhobbe6ad62011-05-11 17:09:37 +0300315 [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
Johannes Berge5497d72011-07-05 16:35:40 +0200316 [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
Johannes Berg34850ab2011-07-18 18:08:35 +0200317 [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
Jouni Malinen32e9de82011-08-10 23:53:31 +0300318 [NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
Jouni Malinen9946ecf2011-08-10 23:55:56 +0300319 [NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
320 .len = IEEE80211_MAX_DATA_LEN },
321 [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
322 .len = IEEE80211_MAX_DATA_LEN },
Vivek Natarajanf4b34b52011-08-29 14:23:03 +0530323 [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300324 [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +0530325 [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
Arik Nemtsov109086c2011-09-28 14:12:50 +0300326 [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
327 [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
328 [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
329 [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
330 [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
Arik Nemtsov31fa97c2014-06-11 17:18:21 +0300331 [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG },
Johannes Berge247bd902011-11-04 11:18:21 +0100332 [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
Arik Nemtsov00f740e2011-11-10 11:28:56 +0200333 [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
334 .len = IEEE80211_MAX_DATA_LEN },
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -0700335 [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
Ben Greear7e7c8922011-11-18 11:31:59 -0800336 [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
337 [NL80211_ATTR_HT_CAPABILITY_MASK] = {
338 .len = NL80211_HT_CAPABILITY_LEN
339 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +0100340 [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +0530341 [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
Bala Shanmugam4486ea92012-03-07 17:27:12 +0530342 [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
Johannes Berg89a54e42012-06-15 14:33:17 +0200343 [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -0700344 [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
Jouni Malinen11b6b5a2016-10-27 00:41:58 +0300345 [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +0000346 [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
Sam Lefflered4737712012-10-11 21:03:31 -0700347 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
Johannes Berg53cabad2012-11-14 15:17:28 +0100348 [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
349 [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
Srinivas Dasari8feb69c2017-07-07 01:43:41 +0300350 [NL80211_ATTR_LOCAL_MESH_POWER_MODE] = {. type = NLA_U32 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +0530351 [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
352 [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
Jouni Malinen9d62a982013-02-14 21:10:13 +0200353 [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
354 [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
Johannes Berg3713b4e2013-02-14 16:19:38 +0100355 [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
Johannes Bergee2aca32013-02-21 17:36:01 +0100356 [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG },
357 [NL80211_ATTR_VHT_CAPABILITY_MASK] = {
358 .len = NL80211_VHT_CAPABILITY_LEN,
359 },
Jouni Malinen355199e2013-02-27 17:14:27 +0200360 [NL80211_ATTR_MDID] = { .type = NLA_U16 },
361 [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
362 .len = IEEE80211_MAX_DATA_LEN },
Jouni Malinen5e4b6f52013-05-16 20:11:08 +0300363 [NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +0200364 [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
365 [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
366 [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +0300367 [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_BINARY },
368 [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_BINARY },
Sunil Duttc01fc9a2013-10-09 20:45:21 +0530369 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
370 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
Simon Wunderlich5336fa82013-10-07 18:41:05 +0200371 [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +0100372 [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
Johannes Bergad7e7182013-11-13 13:37:47 +0100373 [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
374 [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
375 [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -0800376 [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
377 .len = IEEE80211_QOS_MAP_LEN_MAX },
Jouni Malinen1df4a512014-01-15 00:00:47 +0200378 [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
379 [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +0530380 [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
Jukka Rissanen18e5ca62014-11-13 17:25:14 +0200381 [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +0300382 [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
Assaf Kraussbab5ab72014-09-03 15:25:01 +0300383 [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
Johannes Berg960d01a2014-09-09 22:55:35 +0300384 [NL80211_ATTR_TSID] = { .type = NLA_U8 },
385 [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },
386 [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
Eliad Peller18998c32014-09-10 14:07:34 +0300387 [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
Johannes Bergad2b26a2014-06-12 21:39:05 +0200388 [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN },
Arik Nemtsov1bdd7162014-12-15 19:26:01 +0200389 [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
Vadim Kochan4b681c82015-01-12 16:34:05 +0200390 [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
Luciano Coelho9c748932015-01-16 16:04:09 +0200391 [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
Ilan peer05050752015-03-04 00:32:06 -0500392 [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
Lior David34d50512016-01-28 10:58:25 +0200393 [NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
Arend van Spriel38de03d2016-03-02 20:37:18 +0100394 [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
Ayala Beker17b94242016-03-17 15:41:38 +0200395 [NL80211_ATTR_STA_SUPPORT_P2P_PS] = { .type = NLA_U8 },
Aviya Erenfeldc6e6a0c2016-07-05 15:23:08 +0300396 [NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
397 .len = VHT_MUMIMO_GROUPS_DATA_LEN
398 },
399 [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN },
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300400 [NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
Luca Coelho85859892017-02-08 15:00:34 +0200401 [NL80211_ATTR_BANDS] = { .type = NLA_U32 },
Ayala Bekera442b762016-09-20 17:31:15 +0300402 [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
Jouni Malinen348bd452016-10-27 00:42:03 +0300403 [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
404 .len = FILS_MAX_KEK_LEN },
405 [NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
Michael Braunce0ce132016-10-10 19:12:22 +0200406 [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
Vamsi Krishna2fa436b2016-12-02 23:59:08 +0200407 [NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
vamsi krishnabf95ecd2017-01-13 01:12:20 +0200408 [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
409 [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
410 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
411 },
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +0200412 [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +0300413 [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
414 .len = FILS_ERP_MAX_USERNAME_LEN },
415 [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
416 .len = FILS_ERP_MAX_REALM_LEN },
417 [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
418 [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
419 .len = FILS_ERP_MAX_RRK_LEN },
420 [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
421 [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
Arend Van Sprielca986ad2017-04-21 13:05:00 +0100422 [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
Johannes Berg55682962007-09-20 13:09:35 -0400423};
424
Johannes Berge31b8212010-10-05 19:39:30 +0200425/* policy for the key attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000426static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
Johannes Bergfffd0932009-07-08 14:22:54 +0200427 [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
Johannes Bergb9454e82009-07-08 13:29:08 +0200428 [NL80211_KEY_IDX] = { .type = NLA_U8 },
429 [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
Jouni Malinen81962262011-11-02 23:36:31 +0200430 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Bergb9454e82009-07-08 13:29:08 +0200431 [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
432 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
Johannes Berge31b8212010-10-05 19:39:30 +0200433 [NL80211_KEY_TYPE] = { .type = NLA_U32 },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100434 [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
435};
436
437/* policy for the key default flags */
438static const struct nla_policy
439nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
440 [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
441 [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
Johannes Bergb9454e82009-07-08 13:29:08 +0200442};
443
Johannes Bergf83ace32016-10-17 08:04:07 +0200444#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +0200445/* policy for WoWLAN attributes */
446static const struct nla_policy
447nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
448 [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
449 [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
450 [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
451 [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
Johannes Berg77dbbb12011-07-13 10:48:55 +0200452 [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG },
453 [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG },
454 [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG },
455 [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100456 [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED },
Luciano Coelho8cd4d452014-09-17 11:55:28 +0300457 [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100458};
459
460static const struct nla_policy
461nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
462 [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
463 [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
464 [NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN },
465 [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
466 [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
467 [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 },
468 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
469 .len = sizeof(struct nl80211_wowlan_tcp_data_seq)
470 },
471 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = {
472 .len = sizeof(struct nl80211_wowlan_tcp_data_token)
473 },
474 [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
475 [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 },
476 [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200477};
Johannes Bergf83ace32016-10-17 08:04:07 +0200478#endif /* CONFIG_PM */
Johannes Bergff1b6e62011-05-04 15:37:28 +0200479
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -0700480/* policy for coalesce rule attributes */
481static const struct nla_policy
482nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
483 [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
484 [NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 },
485 [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
486};
487
Johannes Berge5497d72011-07-05 16:35:40 +0200488/* policy for GTK rekey offload attributes */
489static const struct nla_policy
490nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
491 [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN },
492 [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN },
493 [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
494};
495
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300496static const struct nla_policy
497nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
Johannes Berg4a4ab0d2012-06-13 11:17:11 +0200498 [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300499 .len = IEEE80211_MAX_SSID_LEN },
Arend Van Spriel3007e352017-04-21 13:05:01 +0100500 [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = { .len = ETH_ALEN },
Thomas Pedersen88e920b2012-06-21 11:09:54 -0700501 [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300502};
503
Avraham Stern3b06d272015-10-12 09:51:34 +0300504static const struct nla_policy
505nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
506 [NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
507 [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
508};
509
Arend van Spriel38de03d2016-03-02 20:37:18 +0100510static const struct nla_policy
511nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
512 [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
513 [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
514 [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
515 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
516 },
517};
518
Ayala Bekera442b762016-09-20 17:31:15 +0300519/* policy for NAN function attributes */
520static const struct nla_policy
521nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
522 [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
Srinivas Dasari0a278442017-07-07 01:43:40 +0300523 [NL80211_NAN_FUNC_SERVICE_ID] = {
Ayala Bekera442b762016-09-20 17:31:15 +0300524 .len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
525 [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
526 [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
527 [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
528 [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
529 [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
530 [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { .len = ETH_ALEN },
531 [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
532 [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
533 [NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
534 .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN },
535 [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
536 [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
537 [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
538 [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8 },
539 [NL80211_NAN_FUNC_TERM_REASON] = { .type = NLA_U8 },
540};
541
542/* policy for Service Response Filter attributes */
543static const struct nla_policy
544nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
545 [NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG },
546 [NL80211_NAN_SRF_BF] = { .type = NLA_BINARY,
547 .len = NL80211_NAN_FUNC_SRF_MAX_LEN },
548 [NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 },
549 [NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED },
550};
551
Peng Xuad670232017-10-03 23:21:51 +0300552/* policy for packet pattern attributes */
553static const struct nla_policy
554nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
555 [NL80211_PKTPAT_MASK] = { .type = NLA_BINARY, },
556 [NL80211_PKTPAT_PATTERN] = { .type = NLA_BINARY, },
557 [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 },
558};
559
Johannes Berg97990a02013-04-19 01:02:55 +0200560static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
561 struct netlink_callback *cb,
562 struct cfg80211_registered_device **rdev,
563 struct wireless_dev **wdev)
Holger Schuriga0438972009-11-11 11:30:02 +0100564{
Johannes Berg67748892010-10-04 21:14:06 +0200565 int err;
566
Johannes Berg97990a02013-04-19 01:02:55 +0200567 if (!cb->args[0]) {
568 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergc90c39d2016-10-24 14:40:01 +0200569 genl_family_attrbuf(&nl80211_fam),
Johannes Bergfceb6432017-04-12 14:34:07 +0200570 nl80211_fam.maxattr, nl80211_policy, NULL);
Johannes Berg97990a02013-04-19 01:02:55 +0200571 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +0100572 return err;
Johannes Berg97990a02013-04-19 01:02:55 +0200573
Johannes Bergc90c39d2016-10-24 14:40:01 +0200574 *wdev = __cfg80211_wdev_from_attrs(
575 sock_net(skb->sk),
576 genl_family_attrbuf(&nl80211_fam));
Johannes Bergea90e0d2017-03-15 14:26:04 +0100577 if (IS_ERR(*wdev))
578 return PTR_ERR(*wdev);
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800579 *rdev = wiphy_to_rdev((*wdev)->wiphy);
Johannes Bergc319d502013-07-30 22:34:28 +0200580 /* 0 is the first index - add 1 to parse only once */
581 cb->args[0] = (*rdev)->wiphy_idx + 1;
Johannes Berg97990a02013-04-19 01:02:55 +0200582 cb->args[1] = (*wdev)->identifier;
583 } else {
Johannes Bergc319d502013-07-30 22:34:28 +0200584 /* subtract the 1 again here */
585 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
Johannes Berg97990a02013-04-19 01:02:55 +0200586 struct wireless_dev *tmp;
587
Johannes Bergea90e0d2017-03-15 14:26:04 +0100588 if (!wiphy)
589 return -ENODEV;
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800590 *rdev = wiphy_to_rdev(wiphy);
Johannes Berg97990a02013-04-19 01:02:55 +0200591 *wdev = NULL;
592
Johannes Berg53873f12016-05-03 16:52:04 +0300593 list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
Johannes Berg97990a02013-04-19 01:02:55 +0200594 if (tmp->identifier == cb->args[1]) {
595 *wdev = tmp;
596 break;
597 }
598 }
Johannes Berg97990a02013-04-19 01:02:55 +0200599
Johannes Bergea90e0d2017-03-15 14:26:04 +0100600 if (!*wdev)
601 return -ENODEV;
Johannes Berg67748892010-10-04 21:14:06 +0200602 }
603
Johannes Berg67748892010-10-04 21:14:06 +0200604 return 0;
Johannes Berg67748892010-10-04 21:14:06 +0200605}
606
Johannes Bergf4a11bb2009-03-27 12:40:28 +0100607/* IE validation */
608static bool is_valid_ie_attr(const struct nlattr *attr)
609{
610 const u8 *pos;
611 int len;
612
613 if (!attr)
614 return true;
615
616 pos = nla_data(attr);
617 len = nla_len(attr);
618
619 while (len) {
620 u8 elemlen;
621
622 if (len < 2)
623 return false;
624 len -= 2;
625
626 elemlen = pos[1];
627 if (elemlen > len)
628 return false;
629
630 len -= elemlen;
631 pos += 2 + elemlen;
632 }
633
634 return true;
635}
636
Johannes Berg55682962007-09-20 13:09:35 -0400637/* message building helper */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000638static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
Johannes Berg55682962007-09-20 13:09:35 -0400639 int flags, u8 cmd)
640{
641 /* since there is no private header just add the generic one */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000642 return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -0400643}
644
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400645static int nl80211_msg_put_channel(struct sk_buff *msg,
Johannes Bergcdc89b92013-02-18 23:54:36 +0100646 struct ieee80211_channel *chan,
647 bool large)
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400648{
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200649 /* Some channels must be completely excluded from the
650 * list to protect old user-space tools from breaking
651 */
652 if (!large && chan->flags &
653 (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
654 return 0;
655
David S. Miller9360ffd2012-03-29 04:41:26 -0400656 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
657 chan->center_freq))
658 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400659
David S. Miller9360ffd2012-03-29 04:41:26 -0400660 if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
661 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
662 goto nla_put_failure;
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200663 if (chan->flags & IEEE80211_CHAN_NO_IR) {
664 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
665 goto nla_put_failure;
666 if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
667 goto nla_put_failure;
668 }
Johannes Bergcdc89b92013-02-18 23:54:36 +0100669 if (chan->flags & IEEE80211_CHAN_RADAR) {
670 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
671 goto nla_put_failure;
672 if (large) {
673 u32 time;
674
675 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
676
677 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
678 chan->dfs_state))
679 goto nla_put_failure;
680 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
681 time))
682 goto nla_put_failure;
Janusz Dziedzic089027e2014-02-21 19:46:12 +0100683 if (nla_put_u32(msg,
684 NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
685 chan->dfs_cac_ms))
686 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +0100687 }
688 }
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400689
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100690 if (large) {
691 if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
692 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
693 goto nla_put_failure;
694 if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
695 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
696 goto nla_put_failure;
697 if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
698 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
699 goto nla_put_failure;
700 if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
701 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
702 goto nla_put_failure;
David Spinadel570dbde2014-02-23 09:12:59 +0200703 if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
704 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
705 goto nla_put_failure;
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300706 if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
707 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
David Spinadel570dbde2014-02-23 09:12:59 +0200708 goto nla_put_failure;
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200709 if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
710 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
711 goto nla_put_failure;
712 if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
713 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
714 goto nla_put_failure;
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100715 }
716
David S. Miller9360ffd2012-03-29 04:41:26 -0400717 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
718 DBM_TO_MBM(chan->max_power)))
719 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400720
721 return 0;
722
723 nla_put_failure:
724 return -ENOBUFS;
725}
726
Johannes Berg55682962007-09-20 13:09:35 -0400727/* netlink command implementations */
728
Johannes Bergb9454e82009-07-08 13:29:08 +0200729struct key_parse {
730 struct key_params p;
731 int idx;
Johannes Berge31b8212010-10-05 19:39:30 +0200732 int type;
Johannes Bergb9454e82009-07-08 13:29:08 +0200733 bool def, defmgmt;
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100734 bool def_uni, def_multi;
Johannes Bergb9454e82009-07-08 13:29:08 +0200735};
736
737static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
738{
739 struct nlattr *tb[NL80211_KEY_MAX + 1];
740 int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
Johannes Bergfceb6432017-04-12 14:34:07 +0200741 nl80211_key_policy, NULL);
Johannes Bergb9454e82009-07-08 13:29:08 +0200742 if (err)
743 return err;
744
745 k->def = !!tb[NL80211_KEY_DEFAULT];
746 k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
747
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100748 if (k->def) {
749 k->def_uni = true;
750 k->def_multi = true;
751 }
752 if (k->defmgmt)
753 k->def_multi = true;
754
Johannes Bergb9454e82009-07-08 13:29:08 +0200755 if (tb[NL80211_KEY_IDX])
756 k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
757
758 if (tb[NL80211_KEY_DATA]) {
759 k->p.key = nla_data(tb[NL80211_KEY_DATA]);
760 k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
761 }
762
763 if (tb[NL80211_KEY_SEQ]) {
764 k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
765 k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
766 }
767
768 if (tb[NL80211_KEY_CIPHER])
769 k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
770
Johannes Berge31b8212010-10-05 19:39:30 +0200771 if (tb[NL80211_KEY_TYPE]) {
772 k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
773 if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
774 return -EINVAL;
775 }
776
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100777 if (tb[NL80211_KEY_DEFAULT_TYPES]) {
778 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -0700779
Johannes Berg2da8f412012-01-20 13:52:37 +0100780 err = nla_parse_nested(kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
781 tb[NL80211_KEY_DEFAULT_TYPES],
Johannes Bergfceb6432017-04-12 14:34:07 +0200782 nl80211_key_default_policy, NULL);
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100783 if (err)
784 return err;
785
786 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
787 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
788 }
789
Johannes Bergb9454e82009-07-08 13:29:08 +0200790 return 0;
791}
792
793static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
794{
795 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
796 k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
797 k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
798 }
799
800 if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
801 k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
802 k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
803 }
804
805 if (info->attrs[NL80211_ATTR_KEY_IDX])
806 k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
807
808 if (info->attrs[NL80211_ATTR_KEY_CIPHER])
809 k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
810
811 k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
812 k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
813
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100814 if (k->def) {
815 k->def_uni = true;
816 k->def_multi = true;
817 }
818 if (k->defmgmt)
819 k->def_multi = true;
820
Johannes Berge31b8212010-10-05 19:39:30 +0200821 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
822 k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
823 if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
824 return -EINVAL;
825 }
826
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100827 if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
828 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Johannes Bergfceb6432017-04-12 14:34:07 +0200829 int err = nla_parse_nested(kdt,
830 NUM_NL80211_KEY_DEFAULT_TYPES - 1,
831 info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
Johannes Bergfe521452017-04-12 14:34:08 +0200832 nl80211_key_default_policy,
833 info->extack);
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100834 if (err)
835 return err;
836
837 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
838 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
839 }
840
Johannes Bergb9454e82009-07-08 13:29:08 +0200841 return 0;
842}
843
844static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
845{
846 int err;
847
848 memset(k, 0, sizeof(*k));
849 k->idx = -1;
Johannes Berge31b8212010-10-05 19:39:30 +0200850 k->type = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +0200851
852 if (info->attrs[NL80211_ATTR_KEY])
853 err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
854 else
855 err = nl80211_parse_key_old(info, k);
856
857 if (err)
858 return err;
859
860 if (k->def && k->defmgmt)
861 return -EINVAL;
862
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100863 if (k->defmgmt) {
864 if (k->def_uni || !k->def_multi)
865 return -EINVAL;
866 }
867
Johannes Bergb9454e82009-07-08 13:29:08 +0200868 if (k->idx != -1) {
869 if (k->defmgmt) {
870 if (k->idx < 4 || k->idx > 5)
871 return -EINVAL;
872 } else if (k->def) {
873 if (k->idx < 0 || k->idx > 3)
874 return -EINVAL;
875 } else {
876 if (k->idx < 0 || k->idx > 5)
877 return -EINVAL;
878 }
879 }
880
881 return 0;
882}
883
Johannes Bergfffd0932009-07-08 14:22:54 +0200884static struct cfg80211_cached_keys *
885nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +0530886 struct nlattr *keys, bool *no_ht)
Johannes Bergfffd0932009-07-08 14:22:54 +0200887{
888 struct key_parse parse;
889 struct nlattr *key;
890 struct cfg80211_cached_keys *result;
891 int rem, err, def = 0;
Johannes Bergf1c1f172016-09-13 17:08:23 +0200892 bool have_key = false;
893
894 nla_for_each_nested(key, keys, rem) {
895 have_key = true;
896 break;
897 }
898
899 if (!have_key)
900 return NULL;
Johannes Bergfffd0932009-07-08 14:22:54 +0200901
902 result = kzalloc(sizeof(*result), GFP_KERNEL);
903 if (!result)
904 return ERR_PTR(-ENOMEM);
905
906 result->def = -1;
Johannes Bergfffd0932009-07-08 14:22:54 +0200907
908 nla_for_each_nested(key, keys, rem) {
909 memset(&parse, 0, sizeof(parse));
910 parse.idx = -1;
911
912 err = nl80211_parse_key_new(key, &parse);
913 if (err)
914 goto error;
915 err = -EINVAL;
916 if (!parse.p.key)
917 goto error;
Johannes Berg42ee2312016-09-13 15:51:03 +0200918 if (parse.idx < 0 || parse.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +0200919 goto error;
920 if (parse.def) {
921 if (def)
922 goto error;
923 def = 1;
924 result->def = parse.idx;
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100925 if (!parse.def_uni || !parse.def_multi)
926 goto error;
Johannes Bergfffd0932009-07-08 14:22:54 +0200927 } else if (parse.defmgmt)
928 goto error;
929 err = cfg80211_validate_key_settings(rdev, &parse.p,
Johannes Berge31b8212010-10-05 19:39:30 +0200930 parse.idx, false, NULL);
Johannes Bergfffd0932009-07-08 14:22:54 +0200931 if (err)
932 goto error;
Johannes Berg386b1f22016-09-13 16:10:02 +0200933 if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
934 parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) {
935 err = -EINVAL;
936 goto error;
937 }
Johannes Bergfffd0932009-07-08 14:22:54 +0200938 result->params[parse.idx].cipher = parse.p.cipher;
939 result->params[parse.idx].key_len = parse.p.key_len;
940 result->params[parse.idx].key = result->data[parse.idx];
941 memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
Sujith Manoharande7044e2012-10-18 10:19:28 +0530942
Johannes Berg386b1f22016-09-13 16:10:02 +0200943 /* must be WEP key if we got here */
944 if (no_ht)
945 *no_ht = true;
Johannes Bergfffd0932009-07-08 14:22:54 +0200946 }
947
Johannes Bergf1c1f172016-09-13 17:08:23 +0200948 if (result->def < 0) {
949 err = -EINVAL;
950 goto error;
951 }
952
Johannes Bergfffd0932009-07-08 14:22:54 +0200953 return result;
954 error:
955 kfree(result);
956 return ERR_PTR(err);
957}
958
959static int nl80211_key_allowed(struct wireless_dev *wdev)
960{
961 ASSERT_WDEV_LOCK(wdev);
962
Johannes Bergfffd0932009-07-08 14:22:54 +0200963 switch (wdev->iftype) {
964 case NL80211_IFTYPE_AP:
965 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +0200966 case NL80211_IFTYPE_P2P_GO:
Thomas Pedersenff973af2011-05-03 16:57:12 -0700967 case NL80211_IFTYPE_MESH_POINT:
Johannes Bergfffd0932009-07-08 14:22:54 +0200968 break;
969 case NL80211_IFTYPE_ADHOC:
Johannes Bergfffd0932009-07-08 14:22:54 +0200970 case NL80211_IFTYPE_STATION:
Johannes Berg074ac8d2010-09-16 14:58:22 +0200971 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Bergceca7b72013-05-16 00:55:45 +0200972 if (!wdev->current_bss)
Johannes Bergfffd0932009-07-08 14:22:54 +0200973 return -ENOLINK;
974 break;
Johannes Bergde4fcba2014-10-31 14:16:12 +0100975 case NL80211_IFTYPE_UNSPECIFIED:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +0100976 case NL80211_IFTYPE_OCB:
Johannes Bergde4fcba2014-10-31 14:16:12 +0100977 case NL80211_IFTYPE_MONITOR:
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300978 case NL80211_IFTYPE_NAN:
Johannes Bergde4fcba2014-10-31 14:16:12 +0100979 case NL80211_IFTYPE_P2P_DEVICE:
980 case NL80211_IFTYPE_WDS:
981 case NUM_NL80211_IFTYPES:
Johannes Bergfffd0932009-07-08 14:22:54 +0200982 return -EINVAL;
983 }
984
985 return 0;
986}
987
Jouni Malinen664834d2014-01-15 00:01:44 +0200988static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
989 struct nlattr *tb)
990{
991 struct ieee80211_channel *chan;
992
993 if (tb == NULL)
994 return NULL;
995 chan = ieee80211_get_channel(wiphy, nla_get_u32(tb));
996 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
997 return NULL;
998 return chan;
999}
1000
Johannes Berg7527a782011-05-13 10:58:57 +02001001static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
1002{
1003 struct nlattr *nl_modes = nla_nest_start(msg, attr);
1004 int i;
1005
1006 if (!nl_modes)
1007 goto nla_put_failure;
1008
1009 i = 0;
1010 while (ifmodes) {
David S. Miller9360ffd2012-03-29 04:41:26 -04001011 if ((ifmodes & 1) && nla_put_flag(msg, i))
1012 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001013 ifmodes >>= 1;
1014 i++;
1015 }
1016
1017 nla_nest_end(msg, nl_modes);
1018 return 0;
1019
1020nla_put_failure:
1021 return -ENOBUFS;
1022}
1023
1024static int nl80211_put_iface_combinations(struct wiphy *wiphy,
Johannes Bergcdc89b92013-02-18 23:54:36 +01001025 struct sk_buff *msg,
1026 bool large)
Johannes Berg7527a782011-05-13 10:58:57 +02001027{
1028 struct nlattr *nl_combis;
1029 int i, j;
1030
1031 nl_combis = nla_nest_start(msg,
1032 NL80211_ATTR_INTERFACE_COMBINATIONS);
1033 if (!nl_combis)
1034 goto nla_put_failure;
1035
1036 for (i = 0; i < wiphy->n_iface_combinations; i++) {
1037 const struct ieee80211_iface_combination *c;
1038 struct nlattr *nl_combi, *nl_limits;
1039
1040 c = &wiphy->iface_combinations[i];
1041
1042 nl_combi = nla_nest_start(msg, i + 1);
1043 if (!nl_combi)
1044 goto nla_put_failure;
1045
1046 nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS);
1047 if (!nl_limits)
1048 goto nla_put_failure;
1049
1050 for (j = 0; j < c->n_limits; j++) {
1051 struct nlattr *nl_limit;
1052
1053 nl_limit = nla_nest_start(msg, j + 1);
1054 if (!nl_limit)
1055 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04001056 if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
1057 c->limits[j].max))
1058 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001059 if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
1060 c->limits[j].types))
1061 goto nla_put_failure;
1062 nla_nest_end(msg, nl_limit);
1063 }
1064
1065 nla_nest_end(msg, nl_limits);
1066
David S. Miller9360ffd2012-03-29 04:41:26 -04001067 if (c->beacon_int_infra_match &&
1068 nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
1069 goto nla_put_failure;
1070 if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
1071 c->num_different_channels) ||
1072 nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
1073 c->max_interfaces))
1074 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +01001075 if (large &&
Felix Fietkau8c48b502014-05-05 11:48:40 +02001076 (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
1077 c->radar_detect_widths) ||
1078 nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
1079 c->radar_detect_regions)))
Johannes Bergcdc89b92013-02-18 23:54:36 +01001080 goto nla_put_failure;
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05301081 if (c->beacon_int_min_gcd &&
1082 nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
1083 c->beacon_int_min_gcd))
1084 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001085
1086 nla_nest_end(msg, nl_combi);
1087 }
1088
1089 nla_nest_end(msg, nl_combis);
1090
1091 return 0;
1092nla_put_failure:
1093 return -ENOBUFS;
1094}
1095
Johannes Berg3713b4e2013-02-14 16:19:38 +01001096#ifdef CONFIG_PM
Johannes Bergb56cf722013-02-20 01:02:38 +01001097static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
1098 struct sk_buff *msg)
1099{
Johannes Berg964dc9e2013-06-03 17:25:34 +02001100 const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
Johannes Bergb56cf722013-02-20 01:02:38 +01001101 struct nlattr *nl_tcp;
1102
1103 if (!tcp)
1104 return 0;
1105
1106 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
1107 if (!nl_tcp)
1108 return -ENOBUFS;
1109
1110 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1111 tcp->data_payload_max))
1112 return -ENOBUFS;
1113
1114 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1115 tcp->data_payload_max))
1116 return -ENOBUFS;
1117
1118 if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
1119 return -ENOBUFS;
1120
1121 if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
1122 sizeof(*tcp->tok), tcp->tok))
1123 return -ENOBUFS;
1124
1125 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
1126 tcp->data_interval_max))
1127 return -ENOBUFS;
1128
1129 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
1130 tcp->wake_payload_max))
1131 return -ENOBUFS;
1132
1133 nla_nest_end(msg, nl_tcp);
1134 return 0;
1135}
1136
Johannes Berg3713b4e2013-02-14 16:19:38 +01001137static int nl80211_send_wowlan(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001138 struct cfg80211_registered_device *rdev,
Johannes Bergb56cf722013-02-20 01:02:38 +01001139 bool large)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001140{
1141 struct nlattr *nl_wowlan;
1142
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001143 if (!rdev->wiphy.wowlan)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001144 return 0;
1145
1146 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
1147 if (!nl_wowlan)
1148 return -ENOBUFS;
1149
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001150 if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001151 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001152 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001153 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001154 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001155 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001156 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001157 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001158 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001159 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001160 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001161 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001162 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001163 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001164 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001165 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
1166 return -ENOBUFS;
1167
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001168 if (rdev->wiphy.wowlan->n_patterns) {
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07001169 struct nl80211_pattern_support pat = {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001170 .max_patterns = rdev->wiphy.wowlan->n_patterns,
1171 .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
1172 .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
1173 .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001174 };
1175
1176 if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
1177 sizeof(pat), &pat))
1178 return -ENOBUFS;
1179 }
1180
Luciano Coelho75453cc2015-01-09 14:06:37 +02001181 if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
1182 nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
1183 rdev->wiphy.wowlan->max_nd_match_sets))
1184 return -ENOBUFS;
1185
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001186 if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
Johannes Bergb56cf722013-02-20 01:02:38 +01001187 return -ENOBUFS;
1188
Johannes Berg3713b4e2013-02-14 16:19:38 +01001189 nla_nest_end(msg, nl_wowlan);
1190
1191 return 0;
1192}
1193#endif
1194
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001195static int nl80211_send_coalesce(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001196 struct cfg80211_registered_device *rdev)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001197{
1198 struct nl80211_coalesce_rule_support rule;
1199
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001200 if (!rdev->wiphy.coalesce)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001201 return 0;
1202
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001203 rule.max_rules = rdev->wiphy.coalesce->n_rules;
1204 rule.max_delay = rdev->wiphy.coalesce->max_delay;
1205 rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
1206 rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
1207 rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
1208 rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001209
1210 if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
1211 return -ENOBUFS;
1212
1213 return 0;
1214}
1215
Johannes Berg3713b4e2013-02-14 16:19:38 +01001216static int nl80211_send_band_rateinfo(struct sk_buff *msg,
1217 struct ieee80211_supported_band *sband)
1218{
1219 struct nlattr *nl_rates, *nl_rate;
1220 struct ieee80211_rate *rate;
1221 int i;
1222
1223 /* add HT info */
1224 if (sband->ht_cap.ht_supported &&
1225 (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
1226 sizeof(sband->ht_cap.mcs),
1227 &sband->ht_cap.mcs) ||
1228 nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
1229 sband->ht_cap.cap) ||
1230 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
1231 sband->ht_cap.ampdu_factor) ||
1232 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
1233 sband->ht_cap.ampdu_density)))
1234 return -ENOBUFS;
1235
1236 /* add VHT info */
1237 if (sband->vht_cap.vht_supported &&
1238 (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
1239 sizeof(sband->vht_cap.vht_mcs),
1240 &sband->vht_cap.vht_mcs) ||
1241 nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
1242 sband->vht_cap.cap)))
1243 return -ENOBUFS;
1244
1245 /* add bitrates */
1246 nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
1247 if (!nl_rates)
1248 return -ENOBUFS;
1249
1250 for (i = 0; i < sband->n_bitrates; i++) {
1251 nl_rate = nla_nest_start(msg, i);
1252 if (!nl_rate)
1253 return -ENOBUFS;
1254
1255 rate = &sband->bitrates[i];
1256 if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
1257 rate->bitrate))
1258 return -ENOBUFS;
1259 if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
1260 nla_put_flag(msg,
1261 NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
1262 return -ENOBUFS;
1263
1264 nla_nest_end(msg, nl_rate);
1265 }
1266
1267 nla_nest_end(msg, nl_rates);
1268
1269 return 0;
1270}
1271
1272static int
1273nl80211_send_mgmt_stypes(struct sk_buff *msg,
1274 const struct ieee80211_txrx_stypes *mgmt_stypes)
1275{
1276 u16 stypes;
1277 struct nlattr *nl_ftypes, *nl_ifs;
1278 enum nl80211_iftype ift;
1279 int i;
1280
1281 if (!mgmt_stypes)
1282 return 0;
1283
1284 nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
1285 if (!nl_ifs)
1286 return -ENOBUFS;
1287
1288 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1289 nl_ftypes = nla_nest_start(msg, ift);
1290 if (!nl_ftypes)
1291 return -ENOBUFS;
1292 i = 0;
1293 stypes = mgmt_stypes[ift].tx;
1294 while (stypes) {
1295 if ((stypes & 1) &&
1296 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1297 (i << 4) | IEEE80211_FTYPE_MGMT))
1298 return -ENOBUFS;
1299 stypes >>= 1;
1300 i++;
1301 }
1302 nla_nest_end(msg, nl_ftypes);
1303 }
1304
1305 nla_nest_end(msg, nl_ifs);
1306
1307 nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
1308 if (!nl_ifs)
1309 return -ENOBUFS;
1310
1311 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1312 nl_ftypes = nla_nest_start(msg, ift);
1313 if (!nl_ftypes)
1314 return -ENOBUFS;
1315 i = 0;
1316 stypes = mgmt_stypes[ift].rx;
1317 while (stypes) {
1318 if ((stypes & 1) &&
1319 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1320 (i << 4) | IEEE80211_FTYPE_MGMT))
1321 return -ENOBUFS;
1322 stypes >>= 1;
1323 i++;
1324 }
1325 nla_nest_end(msg, nl_ftypes);
1326 }
1327 nla_nest_end(msg, nl_ifs);
1328
1329 return 0;
1330}
1331
Johannes Berg17948992016-10-26 11:42:04 +02001332#define CMD(op, n) \
1333 do { \
1334 if (rdev->ops->op) { \
1335 i++; \
1336 if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
1337 goto nla_put_failure; \
1338 } \
1339 } while (0)
1340
1341static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
1342 struct sk_buff *msg)
1343{
1344 int i = 0;
1345
1346 /*
1347 * do *NOT* add anything into this function, new things need to be
1348 * advertised only to new versions of userspace that can deal with
1349 * the split (and they can't possibly care about new features...
1350 */
1351 CMD(add_virtual_intf, NEW_INTERFACE);
1352 CMD(change_virtual_intf, SET_INTERFACE);
1353 CMD(add_key, NEW_KEY);
1354 CMD(start_ap, START_AP);
1355 CMD(add_station, NEW_STATION);
1356 CMD(add_mpath, NEW_MPATH);
1357 CMD(update_mesh_config, SET_MESH_CONFIG);
1358 CMD(change_bss, SET_BSS);
1359 CMD(auth, AUTHENTICATE);
1360 CMD(assoc, ASSOCIATE);
1361 CMD(deauth, DEAUTHENTICATE);
1362 CMD(disassoc, DISASSOCIATE);
1363 CMD(join_ibss, JOIN_IBSS);
1364 CMD(join_mesh, JOIN_MESH);
1365 CMD(set_pmksa, SET_PMKSA);
1366 CMD(del_pmksa, DEL_PMKSA);
1367 CMD(flush_pmksa, FLUSH_PMKSA);
1368 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
1369 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
1370 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
1371 CMD(mgmt_tx, FRAME);
1372 CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
1373 if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
1374 i++;
1375 if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
1376 goto nla_put_failure;
1377 }
1378 if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
1379 rdev->ops->join_mesh) {
1380 i++;
1381 if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
1382 goto nla_put_failure;
1383 }
1384 CMD(set_wds_peer, SET_WDS_PEER);
1385 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
1386 CMD(tdls_mgmt, TDLS_MGMT);
1387 CMD(tdls_oper, TDLS_OPER);
1388 }
Arend Van Sprielca986ad2017-04-21 13:05:00 +01001389 if (rdev->wiphy.max_sched_scan_reqs)
Johannes Berg17948992016-10-26 11:42:04 +02001390 CMD(sched_scan_start, START_SCHED_SCAN);
1391 CMD(probe_client, PROBE_CLIENT);
1392 CMD(set_noack_map, SET_NOACK_MAP);
1393 if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
1394 i++;
1395 if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1396 goto nla_put_failure;
1397 }
1398 CMD(start_p2p_device, START_P2P_DEVICE);
1399 CMD(set_mcast_rate, SET_MCAST_RATE);
1400#ifdef CONFIG_NL80211_TESTMODE
1401 CMD(testmode_cmd, TESTMODE);
1402#endif
1403
1404 if (rdev->ops->connect || rdev->ops->auth) {
1405 i++;
1406 if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
1407 goto nla_put_failure;
1408 }
1409
1410 if (rdev->ops->disconnect || rdev->ops->deauth) {
1411 i++;
1412 if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
1413 goto nla_put_failure;
1414 }
1415
1416 return i;
1417 nla_put_failure:
1418 return -ENOBUFS;
1419}
1420
Johannes Berg86e8cf92013-06-19 10:57:22 +02001421struct nl80211_dump_wiphy_state {
1422 s64 filter_wiphy;
1423 long start;
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05301424 long split_start, band_start, chan_start, capa_start;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001425 bool split;
1426};
1427
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001428static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
Johannes Berg3bb20552014-05-26 13:52:25 +02001429 enum nl80211_commands cmd,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001430 struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001431 int flags, struct nl80211_dump_wiphy_state *state)
Johannes Berg55682962007-09-20 13:09:35 -04001432{
1433 void *hdr;
Johannes Bergee688b002008-01-24 19:38:39 +01001434 struct nlattr *nl_bands, *nl_band;
1435 struct nlattr *nl_freqs, *nl_freq;
Johannes Berg8fdc6212009-03-14 09:34:01 +01001436 struct nlattr *nl_cmds;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001437 enum nl80211_band band;
Johannes Bergee688b002008-01-24 19:38:39 +01001438 struct ieee80211_channel *chan;
Johannes Bergee688b002008-01-24 19:38:39 +01001439 int i;
Johannes Berg2e161f72010-08-12 15:38:38 +02001440 const struct ieee80211_txrx_stypes *mgmt_stypes =
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001441 rdev->wiphy.mgmt_stypes;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001442 u32 features;
Johannes Berg55682962007-09-20 13:09:35 -04001443
Johannes Berg3bb20552014-05-26 13:52:25 +02001444 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04001445 if (!hdr)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001446 return -ENOBUFS;
1447
Johannes Berg86e8cf92013-06-19 10:57:22 +02001448 if (WARN_ON(!state))
1449 return -EINVAL;
Johannes Berg55682962007-09-20 13:09:35 -04001450
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001451 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001452 nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001453 wiphy_name(&rdev->wiphy)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04001454 nla_put_u32(msg, NL80211_ATTR_GENERATION,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001455 cfg80211_rdev_list_generation))
David S. Miller9360ffd2012-03-29 04:41:26 -04001456 goto nla_put_failure;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02001457
Johannes Berg3bb20552014-05-26 13:52:25 +02001458 if (cmd != NL80211_CMD_NEW_WIPHY)
1459 goto finish;
1460
Johannes Berg86e8cf92013-06-19 10:57:22 +02001461 switch (state->split_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001462 case 0:
1463 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001464 rdev->wiphy.retry_short) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001465 nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001466 rdev->wiphy.retry_long) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001467 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001468 rdev->wiphy.frag_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001469 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001470 rdev->wiphy.rts_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001471 nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001472 rdev->wiphy.coverage_class) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001473 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001474 rdev->wiphy.max_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001475 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001476 rdev->wiphy.max_sched_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001477 nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001478 rdev->wiphy.max_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001479 nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001480 rdev->wiphy.max_sched_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001481 nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
Avraham Stern3b06d272015-10-12 09:51:34 +03001482 rdev->wiphy.max_match_sets) ||
1483 nla_put_u32(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
1484 rdev->wiphy.max_sched_scan_plans) ||
1485 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
1486 rdev->wiphy.max_sched_scan_plan_interval) ||
1487 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
1488 rdev->wiphy.max_sched_scan_plan_iterations))
Johannes Bergee688b002008-01-24 19:38:39 +01001489 goto nla_put_failure;
1490
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001491 if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001492 nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
1493 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001494 if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001495 nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
1496 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001497 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001498 nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
1499 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001500 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001501 nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
1502 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001503 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001504 nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
1505 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001506 if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001507 nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
David S. Miller9360ffd2012-03-29 04:41:26 -04001508 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001509 state->split_start++;
1510 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001511 break;
1512 case 1:
1513 if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001514 sizeof(u32) * rdev->wiphy.n_cipher_suites,
1515 rdev->wiphy.cipher_suites))
Mahesh Palivelabf0c111e2012-06-22 07:27:46 +00001516 goto nla_put_failure;
1517
Johannes Berg3713b4e2013-02-14 16:19:38 +01001518 if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001519 rdev->wiphy.max_num_pmkids))
Johannes Bergee688b002008-01-24 19:38:39 +01001520 goto nla_put_failure;
1521
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001522 if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001523 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
1524 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001525
Johannes Berg3713b4e2013-02-14 16:19:38 +01001526 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001527 rdev->wiphy.available_antennas_tx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001528 nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001529 rdev->wiphy.available_antennas_rx))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001530 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001531
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001532 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001533 nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001534 rdev->wiphy.probe_resp_offload))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001535 goto nla_put_failure;
Jouni Malinene2f367f262008-11-21 19:01:30 +02001536
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001537 if ((rdev->wiphy.available_antennas_tx ||
1538 rdev->wiphy.available_antennas_rx) &&
1539 rdev->ops->get_antenna) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001540 u32 tx_ant = 0, rx_ant = 0;
1541 int res;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07001542
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001543 res = rdev_get_antenna(rdev, &tx_ant, &rx_ant);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001544 if (!res) {
1545 if (nla_put_u32(msg,
1546 NL80211_ATTR_WIPHY_ANTENNA_TX,
1547 tx_ant) ||
1548 nla_put_u32(msg,
1549 NL80211_ATTR_WIPHY_ANTENNA_RX,
1550 rx_ant))
1551 goto nla_put_failure;
1552 }
Johannes Bergee688b002008-01-24 19:38:39 +01001553 }
1554
Johannes Berg86e8cf92013-06-19 10:57:22 +02001555 state->split_start++;
1556 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001557 break;
1558 case 2:
1559 if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001560 rdev->wiphy.interface_modes))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001561 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001562 state->split_start++;
1563 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001564 break;
1565 case 3:
1566 nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
1567 if (!nl_bands)
Johannes Bergee688b002008-01-24 19:38:39 +01001568 goto nla_put_failure;
1569
Johannes Berg86e8cf92013-06-19 10:57:22 +02001570 for (band = state->band_start;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001571 band < NUM_NL80211_BANDS; band++) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001572 struct ieee80211_supported_band *sband;
1573
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001574 sband = rdev->wiphy.bands[band];
Johannes Berg3713b4e2013-02-14 16:19:38 +01001575
1576 if (!sband)
1577 continue;
1578
1579 nl_band = nla_nest_start(msg, band);
1580 if (!nl_band)
Johannes Bergee688b002008-01-24 19:38:39 +01001581 goto nla_put_failure;
1582
Johannes Berg86e8cf92013-06-19 10:57:22 +02001583 switch (state->chan_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001584 case 0:
1585 if (nl80211_send_band_rateinfo(msg, sband))
1586 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001587 state->chan_start++;
1588 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001589 break;
1590 default:
1591 /* add frequencies */
1592 nl_freqs = nla_nest_start(
1593 msg, NL80211_BAND_ATTR_FREQS);
1594 if (!nl_freqs)
1595 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001596
Johannes Berg86e8cf92013-06-19 10:57:22 +02001597 for (i = state->chan_start - 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001598 i < sband->n_channels;
1599 i++) {
1600 nl_freq = nla_nest_start(msg, i);
1601 if (!nl_freq)
1602 goto nla_put_failure;
1603
1604 chan = &sband->channels[i];
1605
Johannes Berg86e8cf92013-06-19 10:57:22 +02001606 if (nl80211_msg_put_channel(
1607 msg, chan,
1608 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001609 goto nla_put_failure;
1610
1611 nla_nest_end(msg, nl_freq);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001612 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001613 break;
1614 }
1615 if (i < sband->n_channels)
Johannes Berg86e8cf92013-06-19 10:57:22 +02001616 state->chan_start = i + 2;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001617 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001618 state->chan_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001619 nla_nest_end(msg, nl_freqs);
1620 }
1621
1622 nla_nest_end(msg, nl_band);
1623
Johannes Berg86e8cf92013-06-19 10:57:22 +02001624 if (state->split) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001625 /* start again here */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001626 if (state->chan_start)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001627 band--;
1628 break;
1629 }
Johannes Bergee688b002008-01-24 19:38:39 +01001630 }
Johannes Berg3713b4e2013-02-14 16:19:38 +01001631 nla_nest_end(msg, nl_bands);
Johannes Bergee688b002008-01-24 19:38:39 +01001632
Johannes Berg57fbcce2016-04-12 15:56:15 +02001633 if (band < NUM_NL80211_BANDS)
Johannes Berg86e8cf92013-06-19 10:57:22 +02001634 state->band_start = band + 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001635 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001636 state->band_start = 0;
Johannes Bergee688b002008-01-24 19:38:39 +01001637
Johannes Berg3713b4e2013-02-14 16:19:38 +01001638 /* if bands & channels are done, continue outside */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001639 if (state->band_start == 0 && state->chan_start == 0)
1640 state->split_start++;
1641 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001642 break;
1643 case 4:
1644 nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
1645 if (!nl_cmds)
David S. Miller9360ffd2012-03-29 04:41:26 -04001646 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001647
Johannes Berg17948992016-10-26 11:42:04 +02001648 i = nl80211_add_commands_unsplit(rdev, msg);
1649 if (i < 0)
1650 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001651 if (state->split) {
Arend van Spriel5de17982013-04-18 15:49:00 +02001652 CMD(crit_proto_start, CRIT_PROTOCOL_START);
1653 CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001654 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02001655 CMD(channel_switch, CHANNEL_SWITCH);
Johannes Berg02df00e2014-06-10 14:06:25 +02001656 CMD(set_qos_map, SET_QOS_MAP);
Johannes Berg723e73a2014-10-22 09:25:06 +02001657 if (rdev->wiphy.features &
1658 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
Johannes Berg960d01a2014-09-09 22:55:35 +03001659 CMD(add_tx_ts, ADD_TX_TS);
Michael Braunce0ce132016-10-10 19:12:22 +02001660 CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
vamsi krishna088e8df2016-10-27 16:51:11 +03001661 CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
Arend van Spriel5de17982013-04-18 15:49:00 +02001662 }
Johannes Berg8fdc6212009-03-14 09:34:01 +01001663#undef CMD
Samuel Ortizb23aa672009-07-01 21:26:54 +02001664
Johannes Berg3713b4e2013-02-14 16:19:38 +01001665 nla_nest_end(msg, nl_cmds);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001666 state->split_start++;
1667 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001668 break;
1669 case 5:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001670 if (rdev->ops->remain_on_channel &&
1671 (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001672 nla_put_u32(msg,
1673 NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001674 rdev->wiphy.max_remain_on_channel_duration))
Johannes Berg2e161f72010-08-12 15:38:38 +02001675 goto nla_put_failure;
1676
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001677 if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001678 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
1679 goto nla_put_failure;
Johannes Berg2e161f72010-08-12 15:38:38 +02001680
Johannes Berg3713b4e2013-02-14 16:19:38 +01001681 if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
1682 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001683 state->split_start++;
1684 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001685 break;
1686 case 6:
Johannes Bergdfb89c52012-06-27 09:23:48 +02001687#ifdef CONFIG_PM
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001688 if (nl80211_send_wowlan(msg, rdev, state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001689 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001690 state->split_start++;
1691 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001692 break;
1693#else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001694 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001695#endif
1696 case 7:
1697 if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001698 rdev->wiphy.software_iftypes))
Johannes Bergff1b6e62011-05-04 15:37:28 +02001699 goto nla_put_failure;
1700
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001701 if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001702 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001703 goto nla_put_failure;
Johannes Bergff1b6e62011-05-04 15:37:28 +02001704
Johannes Berg86e8cf92013-06-19 10:57:22 +02001705 state->split_start++;
1706 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001707 break;
1708 case 8:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001709 if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001710 nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001711 rdev->wiphy.ap_sme_capa))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001712 goto nla_put_failure;
1713
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001714 features = rdev->wiphy.features;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001715 /*
1716 * We can only add the per-channel limit information if the
1717 * dump is split, otherwise it makes it too big. Therefore
1718 * only advertise it in that case.
1719 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001720 if (state->split)
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001721 features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
1722 if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001723 goto nla_put_failure;
1724
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001725 if (rdev->wiphy.ht_capa_mod_mask &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001726 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001727 sizeof(*rdev->wiphy.ht_capa_mod_mask),
1728 rdev->wiphy.ht_capa_mod_mask))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001729 goto nla_put_failure;
1730
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001731 if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
1732 rdev->wiphy.max_acl_mac_addrs &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001733 nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001734 rdev->wiphy.max_acl_mac_addrs))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001735 goto nla_put_failure;
1736
1737 /*
1738 * Any information below this point is only available to
1739 * applications that can deal with it being split. This
1740 * helps ensure that newly added capabilities don't break
1741 * older tools by overrunning their buffers.
1742 *
1743 * We still increment split_start so that in the split
1744 * case we'll continue with more data in the next round,
1745 * but break unconditionally so unsplit data stops here.
1746 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001747 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001748 break;
1749 case 9:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001750 if (rdev->wiphy.extended_capabilities &&
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001751 (nla_put(msg, NL80211_ATTR_EXT_CAPA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001752 rdev->wiphy.extended_capabilities_len,
1753 rdev->wiphy.extended_capabilities) ||
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001754 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001755 rdev->wiphy.extended_capabilities_len,
1756 rdev->wiphy.extended_capabilities_mask)))
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001757 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001758
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001759 if (rdev->wiphy.vht_capa_mod_mask &&
Johannes Bergee2aca32013-02-21 17:36:01 +01001760 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001761 sizeof(*rdev->wiphy.vht_capa_mod_mask),
1762 rdev->wiphy.vht_capa_mod_mask))
Johannes Bergee2aca32013-02-21 17:36:01 +01001763 goto nla_put_failure;
1764
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001765 state->split_start++;
1766 break;
1767 case 10:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001768 if (nl80211_send_coalesce(msg, rdev))
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -07001769 goto nla_put_failure;
1770
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001771 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
Felix Fietkau01e0daa2013-11-09 14:57:54 +01001772 (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
1773 nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
1774 goto nla_put_failure;
Jouni Malinenb43504c2014-01-15 00:01:08 +02001775
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001776 if (rdev->wiphy.max_ap_assoc_sta &&
Jouni Malinenb43504c2014-01-15 00:01:08 +02001777 nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001778 rdev->wiphy.max_ap_assoc_sta))
Jouni Malinenb43504c2014-01-15 00:01:08 +02001779 goto nla_put_failure;
1780
Johannes Bergad7e7182013-11-13 13:37:47 +01001781 state->split_start++;
1782 break;
1783 case 11:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001784 if (rdev->wiphy.n_vendor_commands) {
Johannes Berg567ffc32013-12-18 14:43:31 +01001785 const struct nl80211_vendor_cmd_info *info;
1786 struct nlattr *nested;
Johannes Bergad7e7182013-11-13 13:37:47 +01001787
Johannes Berg567ffc32013-12-18 14:43:31 +01001788 nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
1789 if (!nested)
Johannes Bergad7e7182013-11-13 13:37:47 +01001790 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01001791
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001792 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
1793 info = &rdev->wiphy.vendor_commands[i].info;
Johannes Berg567ffc32013-12-18 14:43:31 +01001794 if (nla_put(msg, i + 1, sizeof(*info), info))
1795 goto nla_put_failure;
1796 }
1797 nla_nest_end(msg, nested);
1798 }
1799
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001800 if (rdev->wiphy.n_vendor_events) {
Johannes Berg567ffc32013-12-18 14:43:31 +01001801 const struct nl80211_vendor_cmd_info *info;
1802 struct nlattr *nested;
1803
1804 nested = nla_nest_start(msg,
1805 NL80211_ATTR_VENDOR_EVENTS);
1806 if (!nested)
1807 goto nla_put_failure;
1808
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001809 for (i = 0; i < rdev->wiphy.n_vendor_events; i++) {
1810 info = &rdev->wiphy.vendor_events[i];
Johannes Berg567ffc32013-12-18 14:43:31 +01001811 if (nla_put(msg, i + 1, sizeof(*info), info))
1812 goto nla_put_failure;
1813 }
1814 nla_nest_end(msg, nested);
1815 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03001816 state->split_start++;
1817 break;
1818 case 12:
1819 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
1820 nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
1821 rdev->wiphy.max_num_csa_counters))
1822 goto nla_put_failure;
Felix Fietkau01e0daa2013-11-09 14:57:54 +01001823
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02001824 if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
1825 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
1826 goto nla_put_failure;
1827
Arend Van Sprielca986ad2017-04-21 13:05:00 +01001828 if (rdev->wiphy.max_sched_scan_reqs &&
1829 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_MAX_REQS,
1830 rdev->wiphy.max_sched_scan_reqs))
1831 goto nla_put_failure;
1832
Gautam Kumar Shuklad75bb062014-12-23 16:55:19 +01001833 if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
1834 sizeof(rdev->wiphy.ext_features),
1835 rdev->wiphy.ext_features))
1836 goto nla_put_failure;
1837
Arend van Spriel38de03d2016-03-02 20:37:18 +01001838 if (rdev->wiphy.bss_select_support) {
1839 struct nlattr *nested;
1840 u32 bss_select_support = rdev->wiphy.bss_select_support;
1841
1842 nested = nla_nest_start(msg, NL80211_ATTR_BSS_SELECT);
1843 if (!nested)
1844 goto nla_put_failure;
1845
1846 i = 0;
1847 while (bss_select_support) {
1848 if ((bss_select_support & 1) &&
1849 nla_put_flag(msg, i))
1850 goto nla_put_failure;
1851 i++;
1852 bss_select_support >>= 1;
1853 }
1854 nla_nest_end(msg, nested);
1855 }
1856
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05301857 state->split_start++;
1858 break;
1859 case 13:
1860 if (rdev->wiphy.num_iftype_ext_capab &&
1861 rdev->wiphy.iftype_ext_capab) {
1862 struct nlattr *nested_ext_capab, *nested;
1863
1864 nested = nla_nest_start(msg,
1865 NL80211_ATTR_IFTYPE_EXT_CAPA);
1866 if (!nested)
1867 goto nla_put_failure;
1868
1869 for (i = state->capa_start;
1870 i < rdev->wiphy.num_iftype_ext_capab; i++) {
1871 const struct wiphy_iftype_ext_capab *capab;
1872
1873 capab = &rdev->wiphy.iftype_ext_capab[i];
1874
1875 nested_ext_capab = nla_nest_start(msg, i);
1876 if (!nested_ext_capab ||
1877 nla_put_u32(msg, NL80211_ATTR_IFTYPE,
1878 capab->iftype) ||
1879 nla_put(msg, NL80211_ATTR_EXT_CAPA,
1880 capab->extended_capabilities_len,
1881 capab->extended_capabilities) ||
1882 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
1883 capab->extended_capabilities_len,
1884 capab->extended_capabilities_mask))
1885 goto nla_put_failure;
1886
1887 nla_nest_end(msg, nested_ext_capab);
1888 if (state->split)
1889 break;
1890 }
1891 nla_nest_end(msg, nested);
1892 if (i < rdev->wiphy.num_iftype_ext_capab) {
1893 state->capa_start = i + 1;
1894 break;
1895 }
1896 }
1897
Luca Coelho85859892017-02-08 15:00:34 +02001898 if (nla_put_u32(msg, NL80211_ATTR_BANDS,
1899 rdev->wiphy.nan_supported_bands))
1900 goto nla_put_failure;
1901
Johannes Berg3713b4e2013-02-14 16:19:38 +01001902 /* done */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001903 state->split_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001904 break;
Johannes Bergff1b6e62011-05-04 15:37:28 +02001905 }
Johannes Berg3bb20552014-05-26 13:52:25 +02001906 finish:
Johannes Berg053c0952015-01-16 22:09:00 +01001907 genlmsg_end(msg, hdr);
1908 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04001909
1910 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001911 genlmsg_cancel(msg, hdr);
1912 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04001913}
1914
Johannes Berg86e8cf92013-06-19 10:57:22 +02001915static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
1916 struct netlink_callback *cb,
1917 struct nl80211_dump_wiphy_state *state)
1918{
Johannes Bergc90c39d2016-10-24 14:40:01 +02001919 struct nlattr **tb = genl_family_attrbuf(&nl80211_fam);
Johannes Bergfceb6432017-04-12 14:34:07 +02001920 int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, tb,
1921 nl80211_fam.maxattr, nl80211_policy, NULL);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001922 /* ignore parse errors for backward compatibility */
1923 if (ret)
1924 return 0;
1925
1926 state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
1927 if (tb[NL80211_ATTR_WIPHY])
1928 state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
1929 if (tb[NL80211_ATTR_WDEV])
1930 state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
1931 if (tb[NL80211_ATTR_IFINDEX]) {
1932 struct net_device *netdev;
1933 struct cfg80211_registered_device *rdev;
1934 int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
1935
Ying Xue7f2b8562014-01-15 10:23:45 +08001936 netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001937 if (!netdev)
1938 return -ENODEV;
1939 if (netdev->ieee80211_ptr) {
Zhao, Gangf26cbf42014-04-21 12:53:03 +08001940 rdev = wiphy_to_rdev(
Johannes Berg86e8cf92013-06-19 10:57:22 +02001941 netdev->ieee80211_ptr->wiphy);
1942 state->filter_wiphy = rdev->wiphy_idx;
1943 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001944 }
1945
1946 return 0;
1947}
1948
Johannes Berg55682962007-09-20 13:09:35 -04001949static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
1950{
Johannes Berg645e77d2013-03-01 14:03:49 +01001951 int idx = 0, ret;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001952 struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001953 struct cfg80211_registered_device *rdev;
Johannes Berg3a5a4232013-06-19 10:09:57 +02001954
Johannes Berg5fe231e2013-05-08 21:45:15 +02001955 rtnl_lock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02001956 if (!state) {
1957 state = kzalloc(sizeof(*state), GFP_KERNEL);
John W. Linville57ed5cd2013-06-28 13:18:21 -04001958 if (!state) {
1959 rtnl_unlock();
Johannes Berg86e8cf92013-06-19 10:57:22 +02001960 return -ENOMEM;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001961 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001962 state->filter_wiphy = -1;
1963 ret = nl80211_dump_wiphy_parse(skb, cb, state);
1964 if (ret) {
1965 kfree(state);
1966 rtnl_unlock();
1967 return ret;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001968 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02001969 cb->args[0] = (long)state;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001970 }
1971
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001972 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
1973 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02001974 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001975 if (++idx <= state->start)
Johannes Berg55682962007-09-20 13:09:35 -04001976 continue;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001977 if (state->filter_wiphy != -1 &&
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001978 state->filter_wiphy != rdev->wiphy_idx)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001979 continue;
1980 /* attempt to fit multiple wiphy data chunks into the skb */
1981 do {
Johannes Berg3bb20552014-05-26 13:52:25 +02001982 ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY,
1983 skb,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001984 NETLINK_CB(cb->skb).portid,
1985 cb->nlh->nlmsg_seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001986 NLM_F_MULTI, state);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001987 if (ret < 0) {
1988 /*
1989 * If sending the wiphy data didn't fit (ENOBUFS
1990 * or EMSGSIZE returned), this SKB is still
1991 * empty (so it's not too big because another
1992 * wiphy dataset is already in the skb) and
1993 * we've not tried to adjust the dump allocation
1994 * yet ... then adjust the alloc size to be
1995 * bigger, and return 1 but with the empty skb.
1996 * This results in an empty message being RX'ed
1997 * in userspace, but that is ignored.
1998 *
1999 * We can then retry with the larger buffer.
2000 */
2001 if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
Pontus Fuchsf12cb282014-01-16 15:00:40 +01002002 !skb->len && !state->split &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01002003 cb->min_dump_alloc < 4096) {
2004 cb->min_dump_alloc = 4096;
Pontus Fuchsf12cb282014-01-16 15:00:40 +01002005 state->split_start = 0;
David S. Millerd98cae64e2013-06-19 16:49:39 -07002006 rtnl_unlock();
Johannes Berg3713b4e2013-02-14 16:19:38 +01002007 return 1;
2008 }
2009 idx--;
2010 break;
Johannes Berg645e77d2013-03-01 14:03:49 +01002011 }
Johannes Berg86e8cf92013-06-19 10:57:22 +02002012 } while (state->split_start > 0);
Johannes Berg3713b4e2013-02-14 16:19:38 +01002013 break;
Johannes Berg55682962007-09-20 13:09:35 -04002014 }
Johannes Berg5fe231e2013-05-08 21:45:15 +02002015 rtnl_unlock();
Johannes Berg55682962007-09-20 13:09:35 -04002016
Johannes Berg86e8cf92013-06-19 10:57:22 +02002017 state->start = idx;
Johannes Berg55682962007-09-20 13:09:35 -04002018
2019 return skb->len;
2020}
2021
Johannes Berg86e8cf92013-06-19 10:57:22 +02002022static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
2023{
2024 kfree((void *)cb->args[0]);
2025 return 0;
2026}
2027
Johannes Berg55682962007-09-20 13:09:35 -04002028static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
2029{
2030 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002031 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg86e8cf92013-06-19 10:57:22 +02002032 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -04002033
Johannes Berg645e77d2013-03-01 14:03:49 +01002034 msg = nlmsg_new(4096, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002035 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002036 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002037
Johannes Berg3bb20552014-05-26 13:52:25 +02002038 if (nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY, msg,
2039 info->snd_portid, info->snd_seq, 0,
Johannes Berg86e8cf92013-06-19 10:57:22 +02002040 &state) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002041 nlmsg_free(msg);
2042 return -ENOBUFS;
2043 }
Johannes Berg55682962007-09-20 13:09:35 -04002044
Johannes Berg134e6372009-07-10 09:51:34 +00002045 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002046}
2047
Jouni Malinen31888482008-10-30 16:59:24 +02002048static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
2049 [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 },
2050 [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 },
2051 [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 },
2052 [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 },
2053 [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 },
2054};
2055
2056static int parse_txq_params(struct nlattr *tb[],
2057 struct ieee80211_txq_params *txq_params)
2058{
Johannes Berga3304b02012-03-28 11:04:24 +02002059 if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
Jouni Malinen31888482008-10-30 16:59:24 +02002060 !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
2061 !tb[NL80211_TXQ_ATTR_AIFS])
2062 return -EINVAL;
2063
Johannes Berga3304b02012-03-28 11:04:24 +02002064 txq_params->ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
Jouni Malinen31888482008-10-30 16:59:24 +02002065 txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
2066 txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
2067 txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
2068 txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
2069
Johannes Berga3304b02012-03-28 11:04:24 +02002070 if (txq_params->ac >= NL80211_NUM_ACS)
2071 return -EINVAL;
2072
Jouni Malinen31888482008-10-30 16:59:24 +02002073 return 0;
2074}
2075
Johannes Bergf444de02010-05-05 15:25:02 +02002076static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
2077{
2078 /*
Johannes Bergcc1d2802012-05-16 23:50:20 +02002079 * You can only set the channel explicitly for WDS interfaces,
2080 * all others have their channel managed via their respective
2081 * "establish a connection" command (connect, join, ...)
2082 *
2083 * For AP/GO and mesh mode, the channel can be set with the
2084 * channel userspace API, but is only stored and passed to the
2085 * low-level driver when the AP starts or the mesh is joined.
2086 * This is for backward compatibility, userspace can also give
2087 * the channel in the start-ap or join-mesh commands instead.
Johannes Bergf444de02010-05-05 15:25:02 +02002088 *
2089 * Monitors are special as they are normally slaved to
Johannes Berge8c9bd52012-06-06 08:18:22 +02002090 * whatever else is going on, so they have their own special
2091 * operation to set the monitor channel if possible.
Johannes Bergf444de02010-05-05 15:25:02 +02002092 */
2093 return !wdev ||
2094 wdev->iftype == NL80211_IFTYPE_AP ||
Johannes Bergf444de02010-05-05 15:25:02 +02002095 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
Johannes Berg074ac8d2010-09-16 14:58:22 +02002096 wdev->iftype == NL80211_IFTYPE_MONITOR ||
2097 wdev->iftype == NL80211_IFTYPE_P2P_GO;
Johannes Bergf444de02010-05-05 15:25:02 +02002098}
2099
Johannes Berg683b6d32012-11-08 21:25:48 +01002100static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
2101 struct genl_info *info,
2102 struct cfg80211_chan_def *chandef)
2103{
Mahesh Paliveladbeca2e2012-11-29 14:11:07 +05302104 u32 control_freq;
Johannes Berg683b6d32012-11-08 21:25:48 +01002105
2106 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
2107 return -EINVAL;
2108
2109 control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
2110
2111 chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002112 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
2113 chandef->center_freq1 = control_freq;
2114 chandef->center_freq2 = 0;
Johannes Berg683b6d32012-11-08 21:25:48 +01002115
2116 /* Primary channel not allowed */
2117 if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
2118 return -EINVAL;
2119
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002120 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
2121 enum nl80211_channel_type chantype;
Johannes Berg683b6d32012-11-08 21:25:48 +01002122
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002123 chantype = nla_get_u32(
2124 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
2125
2126 switch (chantype) {
2127 case NL80211_CHAN_NO_HT:
2128 case NL80211_CHAN_HT20:
2129 case NL80211_CHAN_HT40PLUS:
2130 case NL80211_CHAN_HT40MINUS:
2131 cfg80211_chandef_create(chandef, chandef->chan,
2132 chantype);
Tova Mussaiffa46292017-08-05 11:44:38 +03002133 /* user input for center_freq is incorrect */
2134 if (info->attrs[NL80211_ATTR_CENTER_FREQ1] &&
2135 chandef->center_freq1 != nla_get_u32(
2136 info->attrs[NL80211_ATTR_CENTER_FREQ1]))
2137 return -EINVAL;
2138 /* center_freq2 must be zero */
2139 if (info->attrs[NL80211_ATTR_CENTER_FREQ2] &&
2140 nla_get_u32(info->attrs[NL80211_ATTR_CENTER_FREQ2]))
2141 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002142 break;
2143 default:
Johannes Berg683b6d32012-11-08 21:25:48 +01002144 return -EINVAL;
Johannes Berg683b6d32012-11-08 21:25:48 +01002145 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002146 } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
2147 chandef->width =
2148 nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
2149 if (info->attrs[NL80211_ATTR_CENTER_FREQ1])
2150 chandef->center_freq1 =
2151 nla_get_u32(
2152 info->attrs[NL80211_ATTR_CENTER_FREQ1]);
2153 if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
2154 chandef->center_freq2 =
2155 nla_get_u32(
2156 info->attrs[NL80211_ATTR_CENTER_FREQ2]);
2157 }
2158
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002159 if (!cfg80211_chandef_valid(chandef))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002160 return -EINVAL;
2161
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002162 if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
2163 IEEE80211_CHAN_DISABLED))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002164 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002165
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02002166 if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
2167 chandef->width == NL80211_CHAN_WIDTH_10) &&
2168 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
2169 return -EINVAL;
2170
Johannes Berg683b6d32012-11-08 21:25:48 +01002171 return 0;
2172}
2173
Johannes Bergf444de02010-05-05 15:25:02 +02002174static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
Jouni Malinene16821b2014-04-28 11:22:08 +03002175 struct net_device *dev,
Johannes Bergf444de02010-05-05 15:25:02 +02002176 struct genl_info *info)
2177{
Johannes Berg683b6d32012-11-08 21:25:48 +01002178 struct cfg80211_chan_def chandef;
Johannes Bergf444de02010-05-05 15:25:02 +02002179 int result;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002180 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
Jouni Malinene16821b2014-04-28 11:22:08 +03002181 struct wireless_dev *wdev = NULL;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002182
Jouni Malinene16821b2014-04-28 11:22:08 +03002183 if (dev)
2184 wdev = dev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002185 if (!nl80211_can_set_dev_channel(wdev))
2186 return -EOPNOTSUPP;
Jouni Malinene16821b2014-04-28 11:22:08 +03002187 if (wdev)
2188 iftype = wdev->iftype;
Johannes Bergf444de02010-05-05 15:25:02 +02002189
Johannes Berg683b6d32012-11-08 21:25:48 +01002190 result = nl80211_parse_chandef(rdev, info, &chandef);
2191 if (result)
2192 return result;
Johannes Bergf444de02010-05-05 15:25:02 +02002193
Johannes Berge8c9bd52012-06-06 08:18:22 +02002194 switch (iftype) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002195 case NL80211_IFTYPE_AP:
2196 case NL80211_IFTYPE_P2P_GO:
Arik Nemtsov923b3522015-07-08 15:41:44 +03002197 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
2198 iftype)) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002199 result = -EINVAL;
2200 break;
2201 }
Jouni Malinene16821b2014-04-28 11:22:08 +03002202 if (wdev->beacon_interval) {
2203 if (!dev || !rdev->ops->set_ap_chanwidth ||
2204 !(rdev->wiphy.features &
2205 NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
2206 result = -EBUSY;
2207 break;
2208 }
2209
2210 /* Only allow dynamic channel width changes */
2211 if (chandef.chan != wdev->preset_chandef.chan) {
2212 result = -EBUSY;
2213 break;
2214 }
2215 result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
2216 if (result)
2217 break;
2218 }
Johannes Berg683b6d32012-11-08 21:25:48 +01002219 wdev->preset_chandef = chandef;
Johannes Bergaa430da2012-05-16 23:50:18 +02002220 result = 0;
2221 break;
Johannes Bergcc1d2802012-05-16 23:50:20 +02002222 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg683b6d32012-11-08 21:25:48 +01002223 result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
Johannes Bergcc1d2802012-05-16 23:50:20 +02002224 break;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002225 case NL80211_IFTYPE_MONITOR:
Johannes Berg683b6d32012-11-08 21:25:48 +01002226 result = cfg80211_set_monitor_channel(rdev, &chandef);
Johannes Berge8c9bd52012-06-06 08:18:22 +02002227 break;
Johannes Bergaa430da2012-05-16 23:50:18 +02002228 default:
Johannes Berge8c9bd52012-06-06 08:18:22 +02002229 result = -EINVAL;
Johannes Bergf444de02010-05-05 15:25:02 +02002230 }
Johannes Bergf444de02010-05-05 15:25:02 +02002231
2232 return result;
2233}
2234
2235static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
2236{
Johannes Berg4c476992010-10-04 21:36:35 +02002237 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2238 struct net_device *netdev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02002239
Jouni Malinene16821b2014-04-28 11:22:08 +03002240 return __nl80211_set_channel(rdev, netdev, info);
Johannes Bergf444de02010-05-05 15:25:02 +02002241}
2242
Bill Jordane8347eb2010-10-01 13:54:28 -04002243static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
2244{
Johannes Berg43b19952010-10-07 13:10:30 +02002245 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2246 struct net_device *dev = info->user_ptr[1];
2247 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg388ac772010-10-07 13:11:09 +02002248 const u8 *bssid;
Bill Jordane8347eb2010-10-01 13:54:28 -04002249
2250 if (!info->attrs[NL80211_ATTR_MAC])
2251 return -EINVAL;
2252
Johannes Berg43b19952010-10-07 13:10:30 +02002253 if (netif_running(dev))
2254 return -EBUSY;
Bill Jordane8347eb2010-10-01 13:54:28 -04002255
Johannes Berg43b19952010-10-07 13:10:30 +02002256 if (!rdev->ops->set_wds_peer)
2257 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002258
Johannes Berg43b19952010-10-07 13:10:30 +02002259 if (wdev->iftype != NL80211_IFTYPE_WDS)
2260 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002261
2262 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Hila Gonene35e4d22012-06-27 17:19:42 +03002263 return rdev_set_wds_peer(rdev, dev, bssid);
Bill Jordane8347eb2010-10-01 13:54:28 -04002264}
2265
Johannes Berg55682962007-09-20 13:09:35 -04002266static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
2267{
2268 struct cfg80211_registered_device *rdev;
Johannes Bergf444de02010-05-05 15:25:02 +02002269 struct net_device *netdev = NULL;
2270 struct wireless_dev *wdev;
Bill Jordana1e567c2010-09-10 11:22:32 -04002271 int result = 0, rem_txq_params = 0;
Jouni Malinen31888482008-10-30 16:59:24 +02002272 struct nlattr *nl_txq_params;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002273 u32 changed;
2274 u8 retry_short = 0, retry_long = 0;
2275 u32 frag_threshold = 0, rts_threshold = 0;
Lukáš Turek81077e82009-12-21 22:50:47 +01002276 u8 coverage_class = 0;
Johannes Berg55682962007-09-20 13:09:35 -04002277
Johannes Berg5fe231e2013-05-08 21:45:15 +02002278 ASSERT_RTNL();
2279
Johannes Bergf444de02010-05-05 15:25:02 +02002280 /*
2281 * Try to find the wiphy and netdev. Normally this
2282 * function shouldn't need the netdev, but this is
2283 * done for backward compatibility -- previously
2284 * setting the channel was done per wiphy, but now
2285 * it is per netdev. Previous userland like hostapd
2286 * also passed a netdev to set_wiphy, so that it is
2287 * possible to let that go to the right netdev!
2288 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002289
Johannes Bergf444de02010-05-05 15:25:02 +02002290 if (info->attrs[NL80211_ATTR_IFINDEX]) {
2291 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
2292
Ying Xue7f2b8562014-01-15 10:23:45 +08002293 netdev = __dev_get_by_index(genl_info_net(info), ifindex);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002294 if (netdev && netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002295 rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002296 else
Johannes Bergf444de02010-05-05 15:25:02 +02002297 netdev = NULL;
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002298 }
2299
Johannes Bergf444de02010-05-05 15:25:02 +02002300 if (!netdev) {
Johannes Berg878d9ec2012-06-15 14:18:32 +02002301 rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
2302 info->attrs);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002303 if (IS_ERR(rdev))
Johannes Berg4c476992010-10-04 21:36:35 +02002304 return PTR_ERR(rdev);
Johannes Bergf444de02010-05-05 15:25:02 +02002305 wdev = NULL;
2306 netdev = NULL;
2307 result = 0;
Johannes Berg71fe96b2012-10-24 10:04:58 +02002308 } else
Johannes Bergf444de02010-05-05 15:25:02 +02002309 wdev = netdev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002310
2311 /*
2312 * end workaround code, by now the rdev is available
2313 * and locked, and wdev may or may not be NULL.
2314 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002315
2316 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
Jouni Malinen31888482008-10-30 16:59:24 +02002317 result = cfg80211_dev_rename(
2318 rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002319
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002320 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002321 return result;
Johannes Berg55682962007-09-20 13:09:35 -04002322
Jouni Malinen31888482008-10-30 16:59:24 +02002323 if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
2324 struct ieee80211_txq_params txq_params;
2325 struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
2326
Ying Xue7f2b8562014-01-15 10:23:45 +08002327 if (!rdev->ops->set_txq_params)
2328 return -EOPNOTSUPP;
Jouni Malinen31888482008-10-30 16:59:24 +02002329
Ying Xue7f2b8562014-01-15 10:23:45 +08002330 if (!netdev)
2331 return -EINVAL;
Eliad Pellerf70f01c2011-09-25 20:06:53 +03002332
Johannes Berg133a3ff2011-11-03 14:50:13 +01002333 if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002334 netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2335 return -EINVAL;
Johannes Berg133a3ff2011-11-03 14:50:13 +01002336
Ying Xue7f2b8562014-01-15 10:23:45 +08002337 if (!netif_running(netdev))
2338 return -ENETDOWN;
Johannes Berg2b5f8b02012-04-02 10:51:55 +02002339
Jouni Malinen31888482008-10-30 16:59:24 +02002340 nla_for_each_nested(nl_txq_params,
2341 info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
2342 rem_txq_params) {
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02002343 result = nla_parse_nested(tb, NL80211_TXQ_ATTR_MAX,
2344 nl_txq_params,
Johannes Bergfe521452017-04-12 14:34:08 +02002345 txq_params_policy,
2346 info->extack);
Johannes Bergae811e22014-01-24 10:17:47 +01002347 if (result)
2348 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002349 result = parse_txq_params(tb, &txq_params);
2350 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002351 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002352
Hila Gonene35e4d22012-06-27 17:19:42 +03002353 result = rdev_set_txq_params(rdev, netdev,
2354 &txq_params);
Jouni Malinen31888482008-10-30 16:59:24 +02002355 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002356 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002357 }
2358 }
2359
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002360 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinene16821b2014-04-28 11:22:08 +03002361 result = __nl80211_set_channel(
2362 rdev,
2363 nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
2364 info);
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002365 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002366 return result;
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002367 }
2368
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002369 if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
Johannes Bergc8442112012-10-24 10:17:18 +02002370 struct wireless_dev *txp_wdev = wdev;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002371 enum nl80211_tx_power_setting type;
2372 int idx, mbm = 0;
2373
Johannes Bergc8442112012-10-24 10:17:18 +02002374 if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
2375 txp_wdev = NULL;
2376
Ying Xue7f2b8562014-01-15 10:23:45 +08002377 if (!rdev->ops->set_tx_power)
2378 return -EOPNOTSUPP;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002379
2380 idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
2381 type = nla_get_u32(info->attrs[idx]);
2382
2383 if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002384 (type != NL80211_TX_POWER_AUTOMATIC))
2385 return -EINVAL;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002386
2387 if (type != NL80211_TX_POWER_AUTOMATIC) {
2388 idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
2389 mbm = nla_get_u32(info->attrs[idx]);
2390 }
2391
Johannes Bergc8442112012-10-24 10:17:18 +02002392 result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002393 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002394 return result;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002395 }
2396
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002397 if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
2398 info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
2399 u32 tx_ant, rx_ant;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07002400
Bruno Randolf7f531e02010-12-16 11:30:22 +09002401 if ((!rdev->wiphy.available_antennas_tx &&
2402 !rdev->wiphy.available_antennas_rx) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002403 !rdev->ops->set_antenna)
2404 return -EOPNOTSUPP;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002405
2406 tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
2407 rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
2408
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002409 /* reject antenna configurations which don't match the
Bruno Randolf7f531e02010-12-16 11:30:22 +09002410 * available antenna masks, except for the "all" mask */
2411 if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002412 (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
2413 return -EINVAL;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002414
Bruno Randolf7f531e02010-12-16 11:30:22 +09002415 tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
2416 rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002417
Hila Gonene35e4d22012-06-27 17:19:42 +03002418 result = rdev_set_antenna(rdev, tx_ant, rx_ant);
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002419 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002420 return result;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002421 }
2422
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002423 changed = 0;
2424
2425 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
2426 retry_short = nla_get_u8(
2427 info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002428 if (retry_short == 0)
2429 return -EINVAL;
2430
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002431 changed |= WIPHY_PARAM_RETRY_SHORT;
2432 }
2433
2434 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
2435 retry_long = nla_get_u8(
2436 info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002437 if (retry_long == 0)
2438 return -EINVAL;
2439
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002440 changed |= WIPHY_PARAM_RETRY_LONG;
2441 }
2442
2443 if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
2444 frag_threshold = nla_get_u32(
2445 info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002446 if (frag_threshold < 256)
2447 return -EINVAL;
2448
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002449 if (frag_threshold != (u32) -1) {
2450 /*
2451 * Fragments (apart from the last one) are required to
2452 * have even length. Make the fragmentation code
2453 * simpler by stripping LSB should someone try to use
2454 * odd threshold value.
2455 */
2456 frag_threshold &= ~0x1;
2457 }
2458 changed |= WIPHY_PARAM_FRAG_THRESHOLD;
2459 }
2460
2461 if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
2462 rts_threshold = nla_get_u32(
2463 info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
2464 changed |= WIPHY_PARAM_RTS_THRESHOLD;
2465 }
2466
Lukáš Turek81077e82009-12-21 22:50:47 +01002467 if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002468 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK])
2469 return -EINVAL;
2470
Lukáš Turek81077e82009-12-21 22:50:47 +01002471 coverage_class = nla_get_u8(
2472 info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
2473 changed |= WIPHY_PARAM_COVERAGE_CLASS;
2474 }
2475
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002476 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
2477 if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION))
2478 return -EOPNOTSUPP;
2479
2480 changed |= WIPHY_PARAM_DYN_ACK;
2481 }
2482
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002483 if (changed) {
2484 u8 old_retry_short, old_retry_long;
2485 u32 old_frag_threshold, old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002486 u8 old_coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002487
Ying Xue7f2b8562014-01-15 10:23:45 +08002488 if (!rdev->ops->set_wiphy_params)
2489 return -EOPNOTSUPP;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002490
2491 old_retry_short = rdev->wiphy.retry_short;
2492 old_retry_long = rdev->wiphy.retry_long;
2493 old_frag_threshold = rdev->wiphy.frag_threshold;
2494 old_rts_threshold = rdev->wiphy.rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002495 old_coverage_class = rdev->wiphy.coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002496
2497 if (changed & WIPHY_PARAM_RETRY_SHORT)
2498 rdev->wiphy.retry_short = retry_short;
2499 if (changed & WIPHY_PARAM_RETRY_LONG)
2500 rdev->wiphy.retry_long = retry_long;
2501 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
2502 rdev->wiphy.frag_threshold = frag_threshold;
2503 if (changed & WIPHY_PARAM_RTS_THRESHOLD)
2504 rdev->wiphy.rts_threshold = rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002505 if (changed & WIPHY_PARAM_COVERAGE_CLASS)
2506 rdev->wiphy.coverage_class = coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002507
Hila Gonene35e4d22012-06-27 17:19:42 +03002508 result = rdev_set_wiphy_params(rdev, changed);
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002509 if (result) {
2510 rdev->wiphy.retry_short = old_retry_short;
2511 rdev->wiphy.retry_long = old_retry_long;
2512 rdev->wiphy.frag_threshold = old_frag_threshold;
2513 rdev->wiphy.rts_threshold = old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002514 rdev->wiphy.coverage_class = old_coverage_class;
Michal Kazior9189ee32015-08-03 10:55:24 +02002515 return result;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002516 }
2517 }
Ying Xue7f2b8562014-01-15 10:23:45 +08002518 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002519}
2520
Johannes Berg71bbc992012-06-15 15:30:18 +02002521static inline u64 wdev_id(struct wireless_dev *wdev)
2522{
2523 return (u64)wdev->identifier |
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002524 ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
Johannes Berg71bbc992012-06-15 15:30:18 +02002525}
Johannes Berg55682962007-09-20 13:09:35 -04002526
Johannes Berg683b6d32012-11-08 21:25:48 +01002527static int nl80211_send_chandef(struct sk_buff *msg,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01002528 const struct cfg80211_chan_def *chandef)
Johannes Berg683b6d32012-11-08 21:25:48 +01002529{
Johannes Berg601555c2014-11-27 17:26:56 +01002530 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
2531 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002532
Johannes Berg683b6d32012-11-08 21:25:48 +01002533 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
2534 chandef->chan->center_freq))
2535 return -ENOBUFS;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002536 switch (chandef->width) {
2537 case NL80211_CHAN_WIDTH_20_NOHT:
2538 case NL80211_CHAN_WIDTH_20:
2539 case NL80211_CHAN_WIDTH_40:
2540 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
2541 cfg80211_get_chandef_type(chandef)))
2542 return -ENOBUFS;
2543 break;
2544 default:
2545 break;
2546 }
2547 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
2548 return -ENOBUFS;
2549 if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
2550 return -ENOBUFS;
2551 if (chandef->center_freq2 &&
2552 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
Johannes Berg683b6d32012-11-08 21:25:48 +01002553 return -ENOBUFS;
2554 return 0;
2555}
2556
Eric W. Biederman15e47302012-09-07 20:12:54 +00002557static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
Johannes Bergd7264052009-04-19 16:23:20 +02002558 struct cfg80211_registered_device *rdev,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002559 struct wireless_dev *wdev, bool removal)
Johannes Berg55682962007-09-20 13:09:35 -04002560{
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002561 struct net_device *dev = wdev->netdev;
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002562 u8 cmd = NL80211_CMD_NEW_INTERFACE;
Johannes Berg55682962007-09-20 13:09:35 -04002563 void *hdr;
2564
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002565 if (removal)
2566 cmd = NL80211_CMD_DEL_INTERFACE;
2567
2568 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04002569 if (!hdr)
2570 return -1;
2571
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002572 if (dev &&
2573 (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002574 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002575 goto nla_put_failure;
2576
2577 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
2578 nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02002579 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
2580 NL80211_ATTR_PAD) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002581 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04002582 nla_put_u32(msg, NL80211_ATTR_GENERATION,
2583 rdev->devlist_generation ^
2584 (cfg80211_rdev_list_generation << 2)))
2585 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002586
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002587 if (rdev->ops->get_channel) {
Johannes Berg683b6d32012-11-08 21:25:48 +01002588 int ret;
2589 struct cfg80211_chan_def chandef;
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002590
Johannes Berg683b6d32012-11-08 21:25:48 +01002591 ret = rdev_get_channel(rdev, wdev, &chandef);
2592 if (ret == 0) {
2593 if (nl80211_send_chandef(msg, &chandef))
2594 goto nla_put_failure;
2595 }
Pontus Fuchsd91df0e2012-04-03 16:39:58 +02002596 }
2597
Rafał Miłeckid55d0d52015-08-31 22:59:38 +02002598 if (rdev->ops->get_tx_power) {
2599 int dbm, ret;
2600
2601 ret = rdev_get_tx_power(rdev, wdev, &dbm);
2602 if (ret == 0 &&
2603 nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
2604 DBM_TO_MBM(dbm)))
2605 goto nla_put_failure;
2606 }
2607
Johannes Berg44905262017-10-17 21:56:01 +02002608 wdev_lock(wdev);
2609 switch (wdev->iftype) {
2610 case NL80211_IFTYPE_AP:
2611 if (wdev->ssid_len &&
2612 nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
Johannes Berg4564b182017-12-11 12:33:47 +01002613 goto nla_put_failure_locked;
Johannes Berg44905262017-10-17 21:56:01 +02002614 break;
2615 case NL80211_IFTYPE_STATION:
2616 case NL80211_IFTYPE_P2P_CLIENT:
2617 case NL80211_IFTYPE_ADHOC: {
2618 const u8 *ssid_ie;
2619 if (!wdev->current_bss)
2620 break;
2621 ssid_ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
2622 WLAN_EID_SSID);
2623 if (!ssid_ie)
2624 break;
2625 if (nla_put(msg, NL80211_ATTR_SSID, ssid_ie[1], ssid_ie + 2))
Johannes Berg4564b182017-12-11 12:33:47 +01002626 goto nla_put_failure_locked;
Johannes Berg44905262017-10-17 21:56:01 +02002627 break;
2628 }
2629 default:
2630 /* nothing */
2631 break;
Antonio Quartullib84e7a02012-11-07 12:52:20 +01002632 }
Johannes Berg44905262017-10-17 21:56:01 +02002633 wdev_unlock(wdev);
Antonio Quartullib84e7a02012-11-07 12:52:20 +01002634
Johannes Berg053c0952015-01-16 22:09:00 +01002635 genlmsg_end(msg, hdr);
2636 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002637
Johannes Berg4564b182017-12-11 12:33:47 +01002638 nla_put_failure_locked:
2639 wdev_unlock(wdev);
Johannes Berg55682962007-09-20 13:09:35 -04002640 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002641 genlmsg_cancel(msg, hdr);
2642 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04002643}
2644
2645static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
2646{
2647 int wp_idx = 0;
2648 int if_idx = 0;
2649 int wp_start = cb->args[0];
2650 int if_start = cb->args[1];
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002651 int filter_wiphy = -1;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002652 struct cfg80211_registered_device *rdev;
Johannes Berg55682962007-09-20 13:09:35 -04002653 struct wireless_dev *wdev;
Johannes Bergea90e0d2017-03-15 14:26:04 +01002654 int ret;
Johannes Berg55682962007-09-20 13:09:35 -04002655
Johannes Berg5fe231e2013-05-08 21:45:15 +02002656 rtnl_lock();
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002657 if (!cb->args[2]) {
2658 struct nl80211_dump_wiphy_state state = {
2659 .filter_wiphy = -1,
2660 };
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002661
2662 ret = nl80211_dump_wiphy_parse(skb, cb, &state);
2663 if (ret)
Johannes Bergea90e0d2017-03-15 14:26:04 +01002664 goto out_unlock;
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002665
2666 filter_wiphy = state.filter_wiphy;
2667
2668 /*
2669 * if filtering, set cb->args[2] to +1 since 0 is the default
2670 * value needed to determine that parsing is necessary.
2671 */
2672 if (filter_wiphy >= 0)
2673 cb->args[2] = filter_wiphy + 1;
2674 else
2675 cb->args[2] = -1;
2676 } else if (cb->args[2] > 0) {
2677 filter_wiphy = cb->args[2] - 1;
2678 }
2679
Johannes Bergf5ea9122009-08-07 16:17:38 +02002680 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2681 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02002682 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002683 if (wp_idx < wp_start) {
2684 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002685 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002686 }
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002687
2688 if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx)
2689 continue;
2690
Johannes Berg55682962007-09-20 13:09:35 -04002691 if_idx = 0;
2692
Johannes Berg53873f12016-05-03 16:52:04 +03002693 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002694 if (if_idx < if_start) {
2695 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002696 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002697 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002698 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
Johannes Berg55682962007-09-20 13:09:35 -04002699 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002700 rdev, wdev, false) < 0) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002701 goto out;
2702 }
2703 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002704 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002705
2706 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002707 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002708 out:
Johannes Berg55682962007-09-20 13:09:35 -04002709 cb->args[0] = wp_idx;
2710 cb->args[1] = if_idx;
2711
Johannes Bergea90e0d2017-03-15 14:26:04 +01002712 ret = skb->len;
2713 out_unlock:
2714 rtnl_unlock();
2715
2716 return ret;
Johannes Berg55682962007-09-20 13:09:35 -04002717}
2718
2719static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
2720{
2721 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002722 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002723 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04002724
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07002725 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002726 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002727 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002728
Eric W. Biederman15e47302012-09-07 20:12:54 +00002729 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002730 rdev, wdev, false) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002731 nlmsg_free(msg);
2732 return -ENOBUFS;
2733 }
Johannes Berg55682962007-09-20 13:09:35 -04002734
Johannes Berg134e6372009-07-10 09:51:34 +00002735 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002736}
2737
Michael Wu66f7ac52008-01-31 19:48:22 +01002738static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
2739 [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
2740 [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
2741 [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
2742 [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
2743 [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002744 [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
Michael Wu66f7ac52008-01-31 19:48:22 +01002745};
2746
2747static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
2748{
2749 struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
2750 int flag;
2751
2752 *mntrflags = 0;
2753
2754 if (!nla)
2755 return -EINVAL;
2756
Johannes Bergfceb6432017-04-12 14:34:07 +02002757 if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, nla,
2758 mntr_flags_policy, NULL))
Michael Wu66f7ac52008-01-31 19:48:22 +01002759 return -EINVAL;
2760
2761 for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
2762 if (flags[flag])
2763 *mntrflags |= (1<<flag);
2764
Johannes Berg818a9862017-04-12 11:23:28 +02002765 *mntrflags |= MONITOR_FLAG_CHANGED;
2766
Michael Wu66f7ac52008-01-31 19:48:22 +01002767 return 0;
2768}
2769
Johannes Berg1db77592017-04-12 11:36:31 +02002770static int nl80211_parse_mon_options(struct cfg80211_registered_device *rdev,
2771 enum nl80211_iftype type,
2772 struct genl_info *info,
2773 struct vif_params *params)
2774{
2775 bool change = false;
2776 int err;
2777
2778 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
2779 if (type != NL80211_IFTYPE_MONITOR)
2780 return -EINVAL;
2781
2782 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
2783 &params->flags);
2784 if (err)
2785 return err;
2786
2787 change = true;
2788 }
2789
2790 if (params->flags & MONITOR_FLAG_ACTIVE &&
2791 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2792 return -EOPNOTSUPP;
2793
2794 if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
2795 const u8 *mumimo_groups;
2796 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2797
2798 if (type != NL80211_IFTYPE_MONITOR)
2799 return -EINVAL;
2800
2801 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2802 return -EOPNOTSUPP;
2803
2804 mumimo_groups =
2805 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
2806
2807 /* bits 0 and 63 are reserved and must be zero */
Johannes Berg49546012017-04-27 09:13:38 +02002808 if ((mumimo_groups[0] & BIT(0)) ||
2809 (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(7)))
Johannes Berg1db77592017-04-12 11:36:31 +02002810 return -EINVAL;
2811
2812 params->vht_mumimo_groups = mumimo_groups;
2813 change = true;
2814 }
2815
2816 if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
2817 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2818
2819 if (type != NL80211_IFTYPE_MONITOR)
2820 return -EINVAL;
2821
2822 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2823 return -EOPNOTSUPP;
2824
2825 params->vht_mumimo_follow_addr =
2826 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]);
2827 change = true;
2828 }
2829
2830 return change ? 1 : 0;
2831}
2832
Johannes Berg9bc383d2009-11-19 11:55:19 +01002833static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002834 struct net_device *netdev, u8 use_4addr,
2835 enum nl80211_iftype iftype)
Johannes Berg9bc383d2009-11-19 11:55:19 +01002836{
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002837 if (!use_4addr) {
Jiri Pirkof350a0a82010-06-15 06:50:45 +00002838 if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002839 return -EBUSY;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002840 return 0;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002841 }
Johannes Berg9bc383d2009-11-19 11:55:19 +01002842
2843 switch (iftype) {
2844 case NL80211_IFTYPE_AP_VLAN:
2845 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
2846 return 0;
2847 break;
2848 case NL80211_IFTYPE_STATION:
2849 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
2850 return 0;
2851 break;
2852 default:
2853 break;
2854 }
2855
2856 return -EOPNOTSUPP;
2857}
2858
Johannes Berg55682962007-09-20 13:09:35 -04002859static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
2860{
Johannes Berg4c476992010-10-04 21:36:35 +02002861 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002862 struct vif_params params;
Johannes Berge36d56b2009-06-09 21:04:43 +02002863 int err;
Johannes Berg04a773a2009-04-19 21:24:32 +02002864 enum nl80211_iftype otype, ntype;
Johannes Berg4c476992010-10-04 21:36:35 +02002865 struct net_device *dev = info->user_ptr[1];
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002866 bool change = false;
Johannes Berg55682962007-09-20 13:09:35 -04002867
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002868 memset(&params, 0, sizeof(params));
2869
Johannes Berg04a773a2009-04-19 21:24:32 +02002870 otype = ntype = dev->ieee80211_ptr->iftype;
Johannes Berg55682962007-09-20 13:09:35 -04002871
Johannes Berg723b0382008-09-16 20:22:09 +02002872 if (info->attrs[NL80211_ATTR_IFTYPE]) {
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002873 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
Johannes Berg04a773a2009-04-19 21:24:32 +02002874 if (otype != ntype)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002875 change = true;
Johannes Berg4c476992010-10-04 21:36:35 +02002876 if (ntype > NL80211_IFTYPE_MAX)
2877 return -EINVAL;
Johannes Berg723b0382008-09-16 20:22:09 +02002878 }
2879
Johannes Berg92ffe052008-09-16 20:39:36 +02002880 if (info->attrs[NL80211_ATTR_MESH_ID]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01002881 struct wireless_dev *wdev = dev->ieee80211_ptr;
2882
Johannes Berg4c476992010-10-04 21:36:35 +02002883 if (ntype != NL80211_IFTYPE_MESH_POINT)
2884 return -EINVAL;
Johannes Berg29cbe682010-12-03 09:20:44 +01002885 if (netif_running(dev))
2886 return -EBUSY;
2887
2888 wdev_lock(wdev);
2889 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2890 IEEE80211_MAX_MESH_ID_LEN);
2891 wdev->mesh_id_up_len =
2892 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2893 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2894 wdev->mesh_id_up_len);
2895 wdev_unlock(wdev);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002896 }
2897
Felix Fietkau8b787642009-11-10 18:53:10 +01002898 if (info->attrs[NL80211_ATTR_4ADDR]) {
2899 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
2900 change = true;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002901 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002902 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002903 return err;
Felix Fietkau8b787642009-11-10 18:53:10 +01002904 } else {
2905 params.use_4addr = -1;
2906 }
2907
Johannes Berg1db77592017-04-12 11:36:31 +02002908 err = nl80211_parse_mon_options(rdev, ntype, info, &params);
2909 if (err < 0)
2910 return err;
2911 if (err > 0)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002912 change = true;
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002913
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002914 if (change)
Johannes Berg818a9862017-04-12 11:23:28 +02002915 err = cfg80211_change_iface(rdev, dev, ntype, &params);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002916 else
2917 err = 0;
Johannes Berg60719ff2008-09-16 14:55:09 +02002918
Johannes Berg9bc383d2009-11-19 11:55:19 +01002919 if (!err && params.use_4addr != -1)
2920 dev->ieee80211_ptr->use_4addr = params.use_4addr;
2921
Johannes Berg55682962007-09-20 13:09:35 -04002922 return err;
2923}
2924
2925static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
2926{
Johannes Berg4c476992010-10-04 21:36:35 +02002927 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002928 struct vif_params params;
Johannes Berg84efbb82012-06-16 00:00:26 +02002929 struct wireless_dev *wdev;
Denis Kenzior896ff062016-08-03 16:58:33 -05002930 struct sk_buff *msg;
Johannes Berg55682962007-09-20 13:09:35 -04002931 int err;
2932 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
2933
Johannes Berg78f22b62014-03-24 17:57:27 +01002934 /* to avoid failing a new interface creation due to pending removal */
2935 cfg80211_destroy_ifaces(rdev);
2936
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002937 memset(&params, 0, sizeof(params));
2938
Johannes Berg55682962007-09-20 13:09:35 -04002939 if (!info->attrs[NL80211_ATTR_IFNAME])
2940 return -EINVAL;
2941
2942 if (info->attrs[NL80211_ATTR_IFTYPE]) {
2943 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
2944 if (type > NL80211_IFTYPE_MAX)
2945 return -EINVAL;
2946 }
2947
Johannes Berg79c97e92009-07-07 03:56:12 +02002948 if (!rdev->ops->add_virtual_intf ||
Johannes Berg4c476992010-10-04 21:36:35 +02002949 !(rdev->wiphy.interface_modes & (1 << type)))
2950 return -EOPNOTSUPP;
Johannes Berg55682962007-09-20 13:09:35 -04002951
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002952 if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
Ben Greeare8f479b2014-10-22 12:23:05 -07002953 rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
2954 info->attrs[NL80211_ATTR_MAC]) {
Arend van Spriel1c18f142013-01-08 10:17:27 +01002955 nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
2956 ETH_ALEN);
2957 if (!is_valid_ether_addr(params.macaddr))
2958 return -EADDRNOTAVAIL;
2959 }
2960
Johannes Berg9bc383d2009-11-19 11:55:19 +01002961 if (info->attrs[NL80211_ATTR_4ADDR]) {
Felix Fietkau8b787642009-11-10 18:53:10 +01002962 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002963 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002964 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002965 return err;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002966 }
Felix Fietkau8b787642009-11-10 18:53:10 +01002967
Johannes Berg1db77592017-04-12 11:36:31 +02002968 err = nl80211_parse_mon_options(rdev, type, info, &params);
2969 if (err < 0)
2970 return err;
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002971
Johannes Berga18c7192015-02-24 10:56:42 +01002972 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2973 if (!msg)
2974 return -ENOMEM;
2975
Hila Gonene35e4d22012-06-27 17:19:42 +03002976 wdev = rdev_add_virtual_intf(rdev,
2977 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
Johannes Berg818a9862017-04-12 11:23:28 +02002978 NET_NAME_USER, type, &params);
Rafał Miłeckid687cbb2014-11-14 18:43:28 +01002979 if (WARN_ON(!wdev)) {
2980 nlmsg_free(msg);
2981 return -EPROTO;
2982 } else if (IS_ERR(wdev)) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002983 nlmsg_free(msg);
Johannes Berg84efbb82012-06-16 00:00:26 +02002984 return PTR_ERR(wdev);
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002985 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002986
Jukka Rissanen18e5ca62014-11-13 17:25:14 +02002987 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
Johannes Berg78f22b62014-03-24 17:57:27 +01002988 wdev->owner_nlportid = info->snd_portid;
2989
Johannes Berg98104fde2012-06-16 00:19:54 +02002990 switch (type) {
2991 case NL80211_IFTYPE_MESH_POINT:
2992 if (!info->attrs[NL80211_ATTR_MESH_ID])
2993 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01002994 wdev_lock(wdev);
2995 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2996 IEEE80211_MAX_MESH_ID_LEN);
2997 wdev->mesh_id_up_len =
2998 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2999 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
3000 wdev->mesh_id_up_len);
3001 wdev_unlock(wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +02003002 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03003003 case NL80211_IFTYPE_NAN:
Johannes Berg98104fde2012-06-16 00:19:54 +02003004 case NL80211_IFTYPE_P2P_DEVICE:
3005 /*
Ayala Bekercb3b7d82016-09-20 17:31:13 +03003006 * P2P Device and NAN do not have a netdev, so don't go
Johannes Berg98104fde2012-06-16 00:19:54 +02003007 * through the netdev notifier and must be added here
3008 */
3009 mutex_init(&wdev->mtx);
3010 INIT_LIST_HEAD(&wdev->event_list);
3011 spin_lock_init(&wdev->event_lock);
3012 INIT_LIST_HEAD(&wdev->mgmt_registrations);
3013 spin_lock_init(&wdev->mgmt_registrations_lock);
3014
Johannes Berg98104fde2012-06-16 00:19:54 +02003015 wdev->identifier = ++rdev->wdev_id;
Johannes Berg53873f12016-05-03 16:52:04 +03003016 list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
Johannes Berg98104fde2012-06-16 00:19:54 +02003017 rdev->devlist_generation++;
Johannes Berg98104fde2012-06-16 00:19:54 +02003018 break;
3019 default:
3020 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01003021 }
3022
Eric W. Biederman15e47302012-09-07 20:12:54 +00003023 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02003024 rdev, wdev, false) < 0) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02003025 nlmsg_free(msg);
3026 return -ENOBUFS;
3027 }
3028
Denis Kenzior896ff062016-08-03 16:58:33 -05003029 /*
3030 * For wdevs which have no associated netdev object (e.g. of type
3031 * NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here.
3032 * For all other types, the event will be generated from the
3033 * netdev notifier
3034 */
3035 if (!wdev->netdev)
3036 nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02003037
Johannes Berg1c90f9d2012-06-16 00:05:37 +02003038 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04003039}
3040
3041static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
3042{
Johannes Berg4c476992010-10-04 21:36:35 +02003043 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg84efbb82012-06-16 00:00:26 +02003044 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04003045
Johannes Berg4c476992010-10-04 21:36:35 +02003046 if (!rdev->ops->del_virtual_intf)
3047 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01003048
Johannes Berg84efbb82012-06-16 00:00:26 +02003049 /*
3050 * If we remove a wireless device without a netdev then clear
3051 * user_ptr[1] so that nl80211_post_doit won't dereference it
3052 * to check if it needs to do dev_put(). Otherwise it crashes
3053 * since the wdev has been freed, unlike with a netdev where
3054 * we need the dev_put() for the netdev to really be freed.
3055 */
3056 if (!wdev->netdev)
3057 info->user_ptr[1] = NULL;
3058
Denis Kenzior7f8ed012016-08-03 16:58:35 -05003059 return rdev_del_virtual_intf(rdev, wdev);
Johannes Berg55682962007-09-20 13:09:35 -04003060}
3061
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003062static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
3063{
3064 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3065 struct net_device *dev = info->user_ptr[1];
3066 u16 noack_map;
3067
3068 if (!info->attrs[NL80211_ATTR_NOACK_MAP])
3069 return -EINVAL;
3070
3071 if (!rdev->ops->set_noack_map)
3072 return -EOPNOTSUPP;
3073
3074 noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
3075
Hila Gonene35e4d22012-06-27 17:19:42 +03003076 return rdev_set_noack_map(rdev, dev, noack_map);
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003077}
3078
Johannes Berg41ade002007-12-19 02:03:29 +01003079struct get_key_cookie {
3080 struct sk_buff *msg;
3081 int error;
Johannes Bergb9454e82009-07-08 13:29:08 +02003082 int idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003083};
3084
3085static void get_key_callback(void *c, struct key_params *params)
3086{
Johannes Bergb9454e82009-07-08 13:29:08 +02003087 struct nlattr *key;
Johannes Berg41ade002007-12-19 02:03:29 +01003088 struct get_key_cookie *cookie = c;
3089
David S. Miller9360ffd2012-03-29 04:41:26 -04003090 if ((params->key &&
3091 nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
3092 params->key_len, params->key)) ||
3093 (params->seq &&
3094 nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
3095 params->seq_len, params->seq)) ||
3096 (params->cipher &&
3097 nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
3098 params->cipher)))
3099 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003100
Johannes Bergb9454e82009-07-08 13:29:08 +02003101 key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
3102 if (!key)
3103 goto nla_put_failure;
3104
David S. Miller9360ffd2012-03-29 04:41:26 -04003105 if ((params->key &&
3106 nla_put(cookie->msg, NL80211_KEY_DATA,
3107 params->key_len, params->key)) ||
3108 (params->seq &&
3109 nla_put(cookie->msg, NL80211_KEY_SEQ,
3110 params->seq_len, params->seq)) ||
3111 (params->cipher &&
3112 nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
3113 params->cipher)))
3114 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003115
David S. Miller9360ffd2012-03-29 04:41:26 -04003116 if (nla_put_u8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx))
3117 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003118
3119 nla_nest_end(cookie->msg, key);
3120
Johannes Berg41ade002007-12-19 02:03:29 +01003121 return;
3122 nla_put_failure:
3123 cookie->error = 1;
3124}
3125
3126static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
3127{
Johannes Berg4c476992010-10-04 21:36:35 +02003128 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003129 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003130 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003131 u8 key_idx = 0;
Johannes Berge31b8212010-10-05 19:39:30 +02003132 const u8 *mac_addr = NULL;
3133 bool pairwise;
Johannes Berg41ade002007-12-19 02:03:29 +01003134 struct get_key_cookie cookie = {
3135 .error = 0,
3136 };
3137 void *hdr;
3138 struct sk_buff *msg;
3139
3140 if (info->attrs[NL80211_ATTR_KEY_IDX])
3141 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
3142
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +02003143 if (key_idx > 5)
Johannes Berg41ade002007-12-19 02:03:29 +01003144 return -EINVAL;
3145
3146 if (info->attrs[NL80211_ATTR_MAC])
3147 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3148
Johannes Berge31b8212010-10-05 19:39:30 +02003149 pairwise = !!mac_addr;
3150 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
3151 u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07003152
Johannes Berge31b8212010-10-05 19:39:30 +02003153 if (kt >= NUM_NL80211_KEYTYPES)
3154 return -EINVAL;
3155 if (kt != NL80211_KEYTYPE_GROUP &&
3156 kt != NL80211_KEYTYPE_PAIRWISE)
3157 return -EINVAL;
3158 pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
3159 }
3160
Johannes Berg4c476992010-10-04 21:36:35 +02003161 if (!rdev->ops->get_key)
3162 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003163
Johannes Berg0fa7b392015-01-23 11:10:12 +01003164 if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3165 return -ENOENT;
3166
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07003167 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02003168 if (!msg)
3169 return -ENOMEM;
Johannes Berg41ade002007-12-19 02:03:29 +01003170
Eric W. Biederman15e47302012-09-07 20:12:54 +00003171 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg41ade002007-12-19 02:03:29 +01003172 NL80211_CMD_NEW_KEY);
Dan Carpentercb35fba2013-08-14 14:50:01 +03003173 if (!hdr)
Johannes Berg9fe271a2013-10-25 11:15:12 +02003174 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003175
3176 cookie.msg = msg;
Johannes Bergb9454e82009-07-08 13:29:08 +02003177 cookie.idx = key_idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003178
David S. Miller9360ffd2012-03-29 04:41:26 -04003179 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
3180 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
3181 goto nla_put_failure;
3182 if (mac_addr &&
3183 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
3184 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003185
Hila Gonene35e4d22012-06-27 17:19:42 +03003186 err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
3187 get_key_callback);
Johannes Berg41ade002007-12-19 02:03:29 +01003188
3189 if (err)
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003190 goto free_msg;
Johannes Berg41ade002007-12-19 02:03:29 +01003191
3192 if (cookie.error)
3193 goto nla_put_failure;
3194
3195 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02003196 return genlmsg_reply(msg, info);
Johannes Berg41ade002007-12-19 02:03:29 +01003197
3198 nla_put_failure:
3199 err = -ENOBUFS;
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003200 free_msg:
Johannes Berg41ade002007-12-19 02:03:29 +01003201 nlmsg_free(msg);
Johannes Berg41ade002007-12-19 02:03:29 +01003202 return err;
3203}
3204
3205static int nl80211_set_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 Bergb9454e82009-07-08 13:29:08 +02003208 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003209 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003210 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003211
Johannes Bergb9454e82009-07-08 13:29:08 +02003212 err = nl80211_parse_key(info, &key);
3213 if (err)
3214 return err;
3215
3216 if (key.idx < 0)
Johannes Berg41ade002007-12-19 02:03:29 +01003217 return -EINVAL;
3218
Johannes Bergb9454e82009-07-08 13:29:08 +02003219 /* only support setting default key */
3220 if (!key.def && !key.defmgmt)
Johannes Berg41ade002007-12-19 02:03:29 +01003221 return -EINVAL;
3222
Johannes Bergfffd0932009-07-08 14:22:54 +02003223 wdev_lock(dev->ieee80211_ptr);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003224
3225 if (key.def) {
3226 if (!rdev->ops->set_default_key) {
3227 err = -EOPNOTSUPP;
3228 goto out;
3229 }
3230
3231 err = nl80211_key_allowed(dev->ieee80211_ptr);
3232 if (err)
3233 goto out;
3234
Hila Gonene35e4d22012-06-27 17:19:42 +03003235 err = rdev_set_default_key(rdev, dev, key.idx,
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003236 key.def_uni, key.def_multi);
3237
3238 if (err)
3239 goto out;
Johannes Bergfffd0932009-07-08 14:22:54 +02003240
Johannes Berg3d23e342009-09-29 23:27:28 +02003241#ifdef CONFIG_CFG80211_WEXT
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003242 dev->ieee80211_ptr->wext.default_key = key.idx;
Johannes Berg08645122009-05-11 13:54:58 +02003243#endif
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003244 } else {
3245 if (key.def_uni || !key.def_multi) {
3246 err = -EINVAL;
3247 goto out;
3248 }
3249
3250 if (!rdev->ops->set_default_mgmt_key) {
3251 err = -EOPNOTSUPP;
3252 goto out;
3253 }
3254
3255 err = nl80211_key_allowed(dev->ieee80211_ptr);
3256 if (err)
3257 goto out;
3258
Hila Gonene35e4d22012-06-27 17:19:42 +03003259 err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003260 if (err)
3261 goto out;
3262
3263#ifdef CONFIG_CFG80211_WEXT
3264 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
3265#endif
3266 }
3267
3268 out:
Johannes Bergfffd0932009-07-08 14:22:54 +02003269 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003270
Johannes Berg41ade002007-12-19 02:03:29 +01003271 return err;
3272}
3273
3274static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
3275{
Johannes Berg4c476992010-10-04 21:36:35 +02003276 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfffd0932009-07-08 14:22:54 +02003277 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003278 struct net_device *dev = info->user_ptr[1];
Johannes Bergb9454e82009-07-08 13:29:08 +02003279 struct key_parse key;
Johannes Berge31b8212010-10-05 19:39:30 +02003280 const u8 *mac_addr = NULL;
Johannes Berg41ade002007-12-19 02:03:29 +01003281
Johannes Bergb9454e82009-07-08 13:29:08 +02003282 err = nl80211_parse_key(info, &key);
3283 if (err)
3284 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003285
Johannes Bergb9454e82009-07-08 13:29:08 +02003286 if (!key.p.key)
Johannes Berg41ade002007-12-19 02:03:29 +01003287 return -EINVAL;
3288
Johannes Berg41ade002007-12-19 02:03:29 +01003289 if (info->attrs[NL80211_ATTR_MAC])
3290 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3291
Johannes Berge31b8212010-10-05 19:39:30 +02003292 if (key.type == -1) {
3293 if (mac_addr)
3294 key.type = NL80211_KEYTYPE_PAIRWISE;
3295 else
3296 key.type = NL80211_KEYTYPE_GROUP;
3297 }
3298
3299 /* for now */
3300 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3301 key.type != NL80211_KEYTYPE_GROUP)
3302 return -EINVAL;
3303
Johannes Berg4c476992010-10-04 21:36:35 +02003304 if (!rdev->ops->add_key)
3305 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01003306
Johannes Berge31b8212010-10-05 19:39:30 +02003307 if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
3308 key.type == NL80211_KEYTYPE_PAIRWISE,
3309 mac_addr))
Johannes Berg4c476992010-10-04 21:36:35 +02003310 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02003311
3312 wdev_lock(dev->ieee80211_ptr);
3313 err = nl80211_key_allowed(dev->ieee80211_ptr);
3314 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003315 err = rdev_add_key(rdev, dev, key.idx,
3316 key.type == NL80211_KEYTYPE_PAIRWISE,
3317 mac_addr, &key.p);
Johannes Bergfffd0932009-07-08 14:22:54 +02003318 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003319
Johannes Berg41ade002007-12-19 02:03:29 +01003320 return err;
3321}
3322
3323static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
3324{
Johannes Berg4c476992010-10-04 21:36:35 +02003325 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003326 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003327 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003328 u8 *mac_addr = NULL;
Johannes Bergb9454e82009-07-08 13:29:08 +02003329 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003330
Johannes Bergb9454e82009-07-08 13:29:08 +02003331 err = nl80211_parse_key(info, &key);
3332 if (err)
3333 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003334
3335 if (info->attrs[NL80211_ATTR_MAC])
3336 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3337
Johannes Berge31b8212010-10-05 19:39:30 +02003338 if (key.type == -1) {
3339 if (mac_addr)
3340 key.type = NL80211_KEYTYPE_PAIRWISE;
3341 else
3342 key.type = NL80211_KEYTYPE_GROUP;
3343 }
3344
3345 /* for now */
3346 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3347 key.type != NL80211_KEYTYPE_GROUP)
3348 return -EINVAL;
3349
Johannes Berg4c476992010-10-04 21:36:35 +02003350 if (!rdev->ops->del_key)
3351 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003352
Johannes Bergfffd0932009-07-08 14:22:54 +02003353 wdev_lock(dev->ieee80211_ptr);
3354 err = nl80211_key_allowed(dev->ieee80211_ptr);
Johannes Berge31b8212010-10-05 19:39:30 +02003355
Johannes Berg0fa7b392015-01-23 11:10:12 +01003356 if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
Johannes Berge31b8212010-10-05 19:39:30 +02003357 !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3358 err = -ENOENT;
3359
Johannes Bergfffd0932009-07-08 14:22:54 +02003360 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003361 err = rdev_del_key(rdev, dev, key.idx,
3362 key.type == NL80211_KEYTYPE_PAIRWISE,
3363 mac_addr);
Johannes Berg41ade002007-12-19 02:03:29 +01003364
Johannes Berg3d23e342009-09-29 23:27:28 +02003365#ifdef CONFIG_CFG80211_WEXT
Johannes Berg08645122009-05-11 13:54:58 +02003366 if (!err) {
Johannes Bergb9454e82009-07-08 13:29:08 +02003367 if (key.idx == dev->ieee80211_ptr->wext.default_key)
Johannes Berg08645122009-05-11 13:54:58 +02003368 dev->ieee80211_ptr->wext.default_key = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +02003369 else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
Johannes Berg08645122009-05-11 13:54:58 +02003370 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
3371 }
3372#endif
Johannes Bergfffd0932009-07-08 14:22:54 +02003373 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg08645122009-05-11 13:54:58 +02003374
Johannes Berg41ade002007-12-19 02:03:29 +01003375 return err;
3376}
3377
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05303378/* This function returns an error or the number of nested attributes */
3379static int validate_acl_mac_addrs(struct nlattr *nl_attr)
3380{
3381 struct nlattr *attr;
3382 int n_entries = 0, tmp;
3383
3384 nla_for_each_nested(attr, nl_attr, tmp) {
3385 if (nla_len(attr) != ETH_ALEN)
3386 return -EINVAL;
3387
3388 n_entries++;
3389 }
3390
3391 return n_entries;
3392}
3393
3394/*
3395 * This function parses ACL information and allocates memory for ACL data.
3396 * On successful return, the calling function is responsible to free the
3397 * ACL buffer returned by this function.
3398 */
3399static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
3400 struct genl_info *info)
3401{
3402 enum nl80211_acl_policy acl_policy;
3403 struct nlattr *attr;
3404 struct cfg80211_acl_data *acl;
3405 int i = 0, n_entries, tmp;
3406
3407 if (!wiphy->max_acl_mac_addrs)
3408 return ERR_PTR(-EOPNOTSUPP);
3409
3410 if (!info->attrs[NL80211_ATTR_ACL_POLICY])
3411 return ERR_PTR(-EINVAL);
3412
3413 acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
3414 if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
3415 acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
3416 return ERR_PTR(-EINVAL);
3417
3418 if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
3419 return ERR_PTR(-EINVAL);
3420
3421 n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
3422 if (n_entries < 0)
3423 return ERR_PTR(n_entries);
3424
3425 if (n_entries > wiphy->max_acl_mac_addrs)
3426 return ERR_PTR(-ENOTSUPP);
3427
3428 acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
3429 GFP_KERNEL);
3430 if (!acl)
3431 return ERR_PTR(-ENOMEM);
3432
3433 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
3434 memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
3435 i++;
3436 }
3437
3438 acl->n_acl_entries = n_entries;
3439 acl->acl_policy = acl_policy;
3440
3441 return acl;
3442}
3443
3444static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
3445{
3446 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3447 struct net_device *dev = info->user_ptr[1];
3448 struct cfg80211_acl_data *acl;
3449 int err;
3450
3451 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3452 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3453 return -EOPNOTSUPP;
3454
3455 if (!dev->ieee80211_ptr->beacon_interval)
3456 return -EINVAL;
3457
3458 acl = parse_acl_data(&rdev->wiphy, info);
3459 if (IS_ERR(acl))
3460 return PTR_ERR(acl);
3461
3462 err = rdev_set_mac_acl(rdev, dev, acl);
3463
3464 kfree(acl);
3465
3466 return err;
3467}
3468
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303469static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
3470 u8 *rates, u8 rates_len)
3471{
3472 u8 i;
3473 u32 mask = 0;
3474
3475 for (i = 0; i < rates_len; i++) {
3476 int rate = (rates[i] & 0x7f) * 5;
3477 int ridx;
3478
3479 for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
3480 struct ieee80211_rate *srate =
3481 &sband->bitrates[ridx];
3482 if (rate == srate->bitrate) {
3483 mask |= 1 << ridx;
3484 break;
3485 }
3486 }
3487 if (ridx == sband->n_bitrates)
3488 return 0; /* rate not found */
3489 }
3490
3491 return mask;
3492}
3493
3494static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
3495 u8 *rates, u8 rates_len,
3496 u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
3497{
3498 u8 i;
3499
3500 memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
3501
3502 for (i = 0; i < rates_len; i++) {
3503 int ridx, rbit;
3504
3505 ridx = rates[i] / 8;
3506 rbit = BIT(rates[i] % 8);
3507
3508 /* check validity */
3509 if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
3510 return false;
3511
3512 /* check availability */
3513 if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
3514 mcs[ridx] |= rbit;
3515 else
3516 return false;
3517 }
3518
3519 return true;
3520}
3521
3522static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
3523{
3524 u16 mcs_mask = 0;
3525
3526 switch (vht_mcs_map) {
3527 case IEEE80211_VHT_MCS_NOT_SUPPORTED:
3528 break;
3529 case IEEE80211_VHT_MCS_SUPPORT_0_7:
3530 mcs_mask = 0x00FF;
3531 break;
3532 case IEEE80211_VHT_MCS_SUPPORT_0_8:
3533 mcs_mask = 0x01FF;
3534 break;
3535 case IEEE80211_VHT_MCS_SUPPORT_0_9:
3536 mcs_mask = 0x03FF;
3537 break;
3538 default:
3539 break;
3540 }
3541
3542 return mcs_mask;
3543}
3544
3545static void vht_build_mcs_mask(u16 vht_mcs_map,
3546 u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
3547{
3548 u8 nss;
3549
3550 for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
3551 vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
3552 vht_mcs_map >>= 2;
3553 }
3554}
3555
3556static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
3557 struct nl80211_txrate_vht *txrate,
3558 u16 mcs[NL80211_VHT_NSS_MAX])
3559{
3560 u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3561 u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
3562 u8 i;
3563
3564 if (!sband->vht_cap.vht_supported)
3565 return false;
3566
3567 memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
3568
3569 /* Build vht_mcs_mask from VHT capabilities */
3570 vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
3571
3572 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
3573 if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
3574 mcs[i] = txrate->mcs[i];
3575 else
3576 return false;
3577 }
3578
3579 return true;
3580}
3581
3582static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
3583 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
3584 .len = NL80211_MAX_SUPP_RATES },
3585 [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
3586 .len = NL80211_MAX_SUPP_HT_RATES },
3587 [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
3588 [NL80211_TXRATE_GI] = { .type = NLA_U8 },
3589};
3590
3591static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
3592 struct cfg80211_bitrate_mask *mask)
3593{
3594 struct nlattr *tb[NL80211_TXRATE_MAX + 1];
3595 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3596 int rem, i;
3597 struct nlattr *tx_rates;
3598 struct ieee80211_supported_band *sband;
3599 u16 vht_tx_mcs_map;
3600
3601 memset(mask, 0, sizeof(*mask));
3602 /* Default to all rates enabled */
3603 for (i = 0; i < NUM_NL80211_BANDS; i++) {
3604 sband = rdev->wiphy.bands[i];
3605
3606 if (!sband)
3607 continue;
3608
3609 mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
3610 memcpy(mask->control[i].ht_mcs,
3611 sband->ht_cap.mcs.rx_mask,
3612 sizeof(mask->control[i].ht_mcs));
3613
3614 if (!sband->vht_cap.vht_supported)
3615 continue;
3616
3617 vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3618 vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
3619 }
3620
3621 /* if no rates are given set it back to the defaults */
3622 if (!info->attrs[NL80211_ATTR_TX_RATES])
3623 goto out;
3624
3625 /* The nested attribute uses enum nl80211_band as the index. This maps
3626 * directly to the enum nl80211_band values used in cfg80211.
3627 */
3628 BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
3629 nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
3630 enum nl80211_band band = nla_type(tx_rates);
3631 int err;
3632
3633 if (band < 0 || band >= NUM_NL80211_BANDS)
3634 return -EINVAL;
3635 sband = rdev->wiphy.bands[band];
3636 if (sband == NULL)
3637 return -EINVAL;
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02003638 err = nla_parse_nested(tb, NL80211_TXRATE_MAX, tx_rates,
Johannes Bergfe521452017-04-12 14:34:08 +02003639 nl80211_txattr_policy, info->extack);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303640 if (err)
3641 return err;
3642 if (tb[NL80211_TXRATE_LEGACY]) {
3643 mask->control[band].legacy = rateset_to_mask(
3644 sband,
3645 nla_data(tb[NL80211_TXRATE_LEGACY]),
3646 nla_len(tb[NL80211_TXRATE_LEGACY]));
3647 if ((mask->control[band].legacy == 0) &&
3648 nla_len(tb[NL80211_TXRATE_LEGACY]))
3649 return -EINVAL;
3650 }
3651 if (tb[NL80211_TXRATE_HT]) {
3652 if (!ht_rateset_to_mask(
3653 sband,
3654 nla_data(tb[NL80211_TXRATE_HT]),
3655 nla_len(tb[NL80211_TXRATE_HT]),
3656 mask->control[band].ht_mcs))
3657 return -EINVAL;
3658 }
3659 if (tb[NL80211_TXRATE_VHT]) {
3660 if (!vht_set_mcs_mask(
3661 sband,
3662 nla_data(tb[NL80211_TXRATE_VHT]),
3663 mask->control[band].vht_mcs))
3664 return -EINVAL;
3665 }
3666 if (tb[NL80211_TXRATE_GI]) {
3667 mask->control[band].gi =
3668 nla_get_u8(tb[NL80211_TXRATE_GI]);
3669 if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
3670 return -EINVAL;
3671 }
3672
3673 if (mask->control[band].legacy == 0) {
3674 /* don't allow empty legacy rates if HT or VHT
3675 * are not even supported.
3676 */
3677 if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
3678 rdev->wiphy.bands[band]->vht_cap.vht_supported))
3679 return -EINVAL;
3680
3681 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
3682 if (mask->control[band].ht_mcs[i])
3683 goto out;
3684
3685 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
3686 if (mask->control[band].vht_mcs[i])
3687 goto out;
3688
3689 /* legacy and mcs rates may not be both empty */
3690 return -EINVAL;
3691 }
3692 }
3693
3694out:
3695 return 0;
3696}
3697
Johannes Berg8564e382016-09-19 09:44:44 +02003698static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
3699 enum nl80211_band band,
3700 struct cfg80211_bitrate_mask *beacon_rate)
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303701{
Johannes Berg8564e382016-09-19 09:44:44 +02003702 u32 count_ht, count_vht, i;
3703 u32 rate = beacon_rate->control[band].legacy;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303704
3705 /* Allow only one rate */
3706 if (hweight32(rate) > 1)
3707 return -EINVAL;
3708
3709 count_ht = 0;
3710 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003711 if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303712 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003713 } else if (beacon_rate->control[band].ht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303714 count_ht++;
3715 if (count_ht > 1)
3716 return -EINVAL;
3717 }
3718 if (count_ht && rate)
3719 return -EINVAL;
3720 }
3721
3722 count_vht = 0;
3723 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003724 if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303725 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003726 } else if (beacon_rate->control[band].vht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303727 count_vht++;
3728 if (count_vht > 1)
3729 return -EINVAL;
3730 }
3731 if (count_vht && rate)
3732 return -EINVAL;
3733 }
3734
3735 if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
3736 return -EINVAL;
3737
Johannes Berg8564e382016-09-19 09:44:44 +02003738 if (rate &&
3739 !wiphy_ext_feature_isset(&rdev->wiphy,
3740 NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
3741 return -EINVAL;
3742 if (count_ht &&
3743 !wiphy_ext_feature_isset(&rdev->wiphy,
3744 NL80211_EXT_FEATURE_BEACON_RATE_HT))
3745 return -EINVAL;
3746 if (count_vht &&
3747 !wiphy_ext_feature_isset(&rdev->wiphy,
3748 NL80211_EXT_FEATURE_BEACON_RATE_VHT))
3749 return -EINVAL;
3750
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303751 return 0;
3752}
3753
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003754static int nl80211_parse_beacon(struct nlattr *attrs[],
Johannes Berg88600202012-02-13 15:17:18 +01003755 struct cfg80211_beacon_data *bcn)
Johannes Berged1b6cc2007-12-19 02:03:32 +01003756{
Johannes Berg88600202012-02-13 15:17:18 +01003757 bool haveinfo = false;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003758
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003759 if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
3760 !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
3761 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
3762 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
Johannes Bergf4a11bb2009-03-27 12:40:28 +01003763 return -EINVAL;
3764
Johannes Berg88600202012-02-13 15:17:18 +01003765 memset(bcn, 0, sizeof(*bcn));
Johannes Berged1b6cc2007-12-19 02:03:32 +01003766
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003767 if (attrs[NL80211_ATTR_BEACON_HEAD]) {
3768 bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
3769 bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
Johannes Berg88600202012-02-13 15:17:18 +01003770 if (!bcn->head_len)
3771 return -EINVAL;
3772 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003773 }
3774
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003775 if (attrs[NL80211_ATTR_BEACON_TAIL]) {
3776 bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
3777 bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
Johannes Berg88600202012-02-13 15:17:18 +01003778 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003779 }
3780
Johannes Berg4c476992010-10-04 21:36:35 +02003781 if (!haveinfo)
3782 return -EINVAL;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003783
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003784 if (attrs[NL80211_ATTR_IE]) {
3785 bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
3786 bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003787 }
3788
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003789 if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003790 bcn->proberesp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003791 nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003792 bcn->proberesp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003793 nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003794 }
3795
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003796 if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003797 bcn->assocresp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003798 nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003799 bcn->assocresp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003800 nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003801 }
3802
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003803 if (attrs[NL80211_ATTR_PROBE_RESP]) {
3804 bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
3805 bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
Arik Nemtsov00f740e2011-11-10 11:28:56 +02003806 }
3807
Johannes Berg88600202012-02-13 15:17:18 +01003808 return 0;
3809}
3810
Johannes Berg66cd7942017-02-07 22:40:44 +02003811static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
3812 const u8 *rates)
3813{
3814 int i;
3815
3816 if (!rates)
3817 return;
3818
3819 for (i = 0; i < rates[1]; i++) {
3820 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
3821 params->ht_required = true;
3822 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
3823 params->vht_required = true;
3824 }
3825}
3826
3827/*
3828 * Since the nl80211 API didn't include, from the beginning, attributes about
3829 * HT/VHT requirements/capabilities, we parse them out of the IEs for the
3830 * benefit of drivers that rebuild IEs in the firmware.
3831 */
3832static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
3833{
3834 const struct cfg80211_beacon_data *bcn = &params->beacon;
Igor Mitsyankoba83bfb2017-08-30 13:52:25 -07003835 size_t ies_len = bcn->tail_len;
3836 const u8 *ies = bcn->tail;
Johannes Berg66cd7942017-02-07 22:40:44 +02003837 const u8 *rates;
3838 const u8 *cap;
3839
3840 rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
3841 nl80211_check_ap_rate_selectors(params, rates);
3842
3843 rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
3844 nl80211_check_ap_rate_selectors(params, rates);
3845
3846 cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
3847 if (cap && cap[1] >= sizeof(*params->ht_cap))
3848 params->ht_cap = (void *)(cap + 2);
3849 cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
3850 if (cap && cap[1] >= sizeof(*params->vht_cap))
3851 params->vht_cap = (void *)(cap + 2);
3852}
3853
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003854static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
3855 struct cfg80211_ap_settings *params)
3856{
3857 struct wireless_dev *wdev;
3858 bool ret = false;
3859
Johannes Berg53873f12016-05-03 16:52:04 +03003860 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003861 if (wdev->iftype != NL80211_IFTYPE_AP &&
3862 wdev->iftype != NL80211_IFTYPE_P2P_GO)
3863 continue;
3864
Johannes Berg683b6d32012-11-08 21:25:48 +01003865 if (!wdev->preset_chandef.chan)
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003866 continue;
3867
Johannes Berg683b6d32012-11-08 21:25:48 +01003868 params->chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003869 ret = true;
3870 break;
3871 }
3872
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003873 return ret;
3874}
3875
Jouni Malinene39e5b52012-09-30 19:29:39 +03003876static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
3877 enum nl80211_auth_type auth_type,
3878 enum nl80211_commands cmd)
3879{
3880 if (auth_type > NL80211_AUTHTYPE_MAX)
3881 return false;
3882
3883 switch (cmd) {
3884 case NL80211_CMD_AUTHENTICATE:
3885 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
3886 auth_type == NL80211_AUTHTYPE_SAE)
3887 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03003888 if (!wiphy_ext_feature_isset(&rdev->wiphy,
3889 NL80211_EXT_FEATURE_FILS_STA) &&
3890 (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3891 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3892 auth_type == NL80211_AUTHTYPE_FILS_PK))
3893 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003894 return true;
3895 case NL80211_CMD_CONNECT:
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03003896 /* SAE not supported yet */
3897 if (auth_type == NL80211_AUTHTYPE_SAE)
3898 return false;
3899 /* FILS with SK PFS or PK not supported yet */
3900 if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3901 auth_type == NL80211_AUTHTYPE_FILS_PK)
3902 return false;
3903 if (!wiphy_ext_feature_isset(
3904 &rdev->wiphy,
3905 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
3906 auth_type == NL80211_AUTHTYPE_FILS_SK)
3907 return false;
3908 return true;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003909 case NL80211_CMD_START_AP:
3910 /* SAE not supported yet */
3911 if (auth_type == NL80211_AUTHTYPE_SAE)
3912 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03003913 /* FILS not supported yet */
3914 if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3915 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3916 auth_type == NL80211_AUTHTYPE_FILS_PK)
3917 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003918 return true;
3919 default:
3920 return false;
3921 }
3922}
3923
Johannes Berg88600202012-02-13 15:17:18 +01003924static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
3925{
3926 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3927 struct net_device *dev = info->user_ptr[1];
3928 struct wireless_dev *wdev = dev->ieee80211_ptr;
3929 struct cfg80211_ap_settings params;
3930 int err;
3931
3932 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3933 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3934 return -EOPNOTSUPP;
3935
3936 if (!rdev->ops->start_ap)
3937 return -EOPNOTSUPP;
3938
3939 if (wdev->beacon_interval)
3940 return -EALREADY;
3941
3942 memset(&params, 0, sizeof(params));
3943
3944 /* these are required for START_AP */
3945 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
3946 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
3947 !info->attrs[NL80211_ATTR_BEACON_HEAD])
3948 return -EINVAL;
3949
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003950 err = nl80211_parse_beacon(info->attrs, &params.beacon);
Johannes Berg88600202012-02-13 15:17:18 +01003951 if (err)
3952 return err;
3953
3954 params.beacon_interval =
3955 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
3956 params.dtim_period =
3957 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
3958
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05303959 err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
3960 params.beacon_interval);
Johannes Berg88600202012-02-13 15:17:18 +01003961 if (err)
3962 return err;
3963
3964 /*
3965 * In theory, some of these attributes should be required here
3966 * but since they were not used when the command was originally
3967 * added, keep them optional for old user space programs to let
3968 * them continue to work with drivers that do not need the
3969 * additional information -- drivers must check!
3970 */
3971 if (info->attrs[NL80211_ATTR_SSID]) {
3972 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3973 params.ssid_len =
3974 nla_len(info->attrs[NL80211_ATTR_SSID]);
3975 if (params.ssid_len == 0 ||
3976 params.ssid_len > IEEE80211_MAX_SSID_LEN)
3977 return -EINVAL;
3978 }
3979
3980 if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
3981 params.hidden_ssid = nla_get_u32(
3982 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
3983 if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
3984 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
3985 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
3986 return -EINVAL;
3987 }
3988
3989 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
3990
3991 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
3992 params.auth_type = nla_get_u32(
3993 info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03003994 if (!nl80211_valid_auth_type(rdev, params.auth_type,
3995 NL80211_CMD_START_AP))
Johannes Berg88600202012-02-13 15:17:18 +01003996 return -EINVAL;
3997 } else
3998 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
3999
4000 err = nl80211_crypto_settings(rdev, info, &params.crypto,
4001 NL80211_MAX_NR_CIPHER_SUITES);
4002 if (err)
4003 return err;
4004
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +05304005 if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
4006 if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
4007 return -EOPNOTSUPP;
4008 params.inactivity_timeout = nla_get_u16(
4009 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
4010 }
4011
Johannes Berg53cabad2012-11-14 15:17:28 +01004012 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
4013 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4014 return -EINVAL;
4015 params.p2p_ctwindow =
4016 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
4017 if (params.p2p_ctwindow > 127)
4018 return -EINVAL;
4019 if (params.p2p_ctwindow != 0 &&
4020 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
4021 return -EINVAL;
4022 }
4023
4024 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
4025 u8 tmp;
4026
4027 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4028 return -EINVAL;
4029 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
4030 if (tmp > 1)
4031 return -EINVAL;
4032 params.p2p_opp_ps = tmp;
4033 if (params.p2p_opp_ps != 0 &&
4034 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
4035 return -EINVAL;
4036 }
4037
Johannes Bergaa430da2012-05-16 23:50:18 +02004038 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01004039 err = nl80211_parse_chandef(rdev, info, &params.chandef);
4040 if (err)
4041 return err;
4042 } else if (wdev->preset_chandef.chan) {
4043 params.chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004044 } else if (!nl80211_get_ap_channel(rdev, &params))
Johannes Bergaa430da2012-05-16 23:50:18 +02004045 return -EINVAL;
4046
Arik Nemtsov923b3522015-07-08 15:41:44 +03004047 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
4048 wdev->iftype))
Johannes Bergaa430da2012-05-16 23:50:18 +02004049 return -EINVAL;
4050
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304051 if (info->attrs[NL80211_ATTR_TX_RATES]) {
4052 err = nl80211_parse_tx_bitrate_mask(info, &params.beacon_rate);
4053 if (err)
4054 return err;
4055
Johannes Berg8564e382016-09-19 09:44:44 +02004056 err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
4057 &params.beacon_rate);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304058 if (err)
4059 return err;
4060 }
4061
Eliad Peller18998c32014-09-10 14:07:34 +03004062 if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
4063 params.smps_mode =
4064 nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
4065 switch (params.smps_mode) {
4066 case NL80211_SMPS_OFF:
4067 break;
4068 case NL80211_SMPS_STATIC:
4069 if (!(rdev->wiphy.features &
4070 NL80211_FEATURE_STATIC_SMPS))
4071 return -EINVAL;
4072 break;
4073 case NL80211_SMPS_DYNAMIC:
4074 if (!(rdev->wiphy.features &
4075 NL80211_FEATURE_DYNAMIC_SMPS))
4076 return -EINVAL;
4077 break;
4078 default:
4079 return -EINVAL;
4080 }
4081 } else {
4082 params.smps_mode = NL80211_SMPS_OFF;
4083 }
4084
Purushottam Kushwaha6e8ef842016-07-05 13:44:51 +05304085 params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
4086 if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
4087 return -EOPNOTSUPP;
4088
Ola Olsson4baf6be2015-10-29 07:04:58 +01004089 if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
4090 params.acl = parse_acl_data(&rdev->wiphy, info);
4091 if (IS_ERR(params.acl))
4092 return PTR_ERR(params.acl);
4093 }
4094
Johannes Berg66cd7942017-02-07 22:40:44 +02004095 nl80211_calculate_ap_params(&params);
4096
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004097 wdev_lock(wdev);
Hila Gonene35e4d22012-06-27 17:19:42 +03004098 err = rdev_start_ap(rdev, dev, &params);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004099 if (!err) {
Johannes Berg683b6d32012-11-08 21:25:48 +01004100 wdev->preset_chandef = params.chandef;
Johannes Berg88600202012-02-13 15:17:18 +01004101 wdev->beacon_interval = params.beacon_interval;
Michal Kazior9e0e2962014-01-29 14:22:27 +01004102 wdev->chandef = params.chandef;
Antonio Quartulli06e191e2012-11-07 12:52:19 +01004103 wdev->ssid_len = params.ssid_len;
4104 memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004105 }
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004106 wdev_unlock(wdev);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05304107
4108 kfree(params.acl);
4109
Johannes Berg56d18932011-05-09 18:41:15 +02004110 return err;
Johannes Berged1b6cc2007-12-19 02:03:32 +01004111}
4112
Johannes Berg88600202012-02-13 15:17:18 +01004113static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
4114{
4115 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4116 struct net_device *dev = info->user_ptr[1];
4117 struct wireless_dev *wdev = dev->ieee80211_ptr;
4118 struct cfg80211_beacon_data params;
4119 int err;
4120
4121 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4122 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4123 return -EOPNOTSUPP;
4124
4125 if (!rdev->ops->change_beacon)
4126 return -EOPNOTSUPP;
4127
4128 if (!wdev->beacon_interval)
4129 return -EINVAL;
4130
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004131 err = nl80211_parse_beacon(info->attrs, &params);
Johannes Berg88600202012-02-13 15:17:18 +01004132 if (err)
4133 return err;
4134
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004135 wdev_lock(wdev);
4136 err = rdev_change_beacon(rdev, dev, &params);
4137 wdev_unlock(wdev);
4138
4139 return err;
Johannes Berg88600202012-02-13 15:17:18 +01004140}
4141
4142static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
Johannes Berged1b6cc2007-12-19 02:03:32 +01004143{
Johannes Berg4c476992010-10-04 21:36:35 +02004144 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4145 struct net_device *dev = info->user_ptr[1];
Johannes Berged1b6cc2007-12-19 02:03:32 +01004146
Ilan Peer7c8d5e02014-02-25 15:33:38 +02004147 return cfg80211_stop_ap(rdev, dev, false);
Johannes Berged1b6cc2007-12-19 02:03:32 +01004148}
4149
Johannes Berg5727ef12007-12-19 02:03:34 +01004150static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
4151 [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
4152 [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
4153 [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
Jouni Malinen0e467242009-05-11 21:57:55 +03004154 [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
Javier Cardonab39c48f2011-04-07 15:08:30 -07004155 [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
Johannes Bergd83023d2011-12-14 09:29:15 +01004156 [NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },
Johannes Berg5727ef12007-12-19 02:03:34 +01004157};
4158
Johannes Bergeccb8e82009-05-11 21:57:56 +03004159static int parse_station_flags(struct genl_info *info,
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004160 enum nl80211_iftype iftype,
Johannes Bergeccb8e82009-05-11 21:57:56 +03004161 struct station_parameters *params)
Johannes Berg5727ef12007-12-19 02:03:34 +01004162{
4163 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
Johannes Bergeccb8e82009-05-11 21:57:56 +03004164 struct nlattr *nla;
Johannes Berg5727ef12007-12-19 02:03:34 +01004165 int flag;
4166
Johannes Bergeccb8e82009-05-11 21:57:56 +03004167 /*
4168 * Try parsing the new attribute first so userspace
4169 * can specify both for older kernels.
4170 */
4171 nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
4172 if (nla) {
4173 struct nl80211_sta_flag_update *sta_flags;
Johannes Berg5727ef12007-12-19 02:03:34 +01004174
Johannes Bergeccb8e82009-05-11 21:57:56 +03004175 sta_flags = nla_data(nla);
4176 params->sta_flags_mask = sta_flags->mask;
4177 params->sta_flags_set = sta_flags->set;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004178 params->sta_flags_set &= params->sta_flags_mask;
Johannes Bergeccb8e82009-05-11 21:57:56 +03004179 if ((params->sta_flags_mask |
4180 params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
4181 return -EINVAL;
4182 return 0;
4183 }
4184
4185 /* if present, parse the old attribute */
4186
4187 nla = info->attrs[NL80211_ATTR_STA_FLAGS];
Johannes Berg5727ef12007-12-19 02:03:34 +01004188 if (!nla)
4189 return 0;
4190
Johannes Bergfceb6432017-04-12 14:34:07 +02004191 if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX, nla,
Johannes Bergfe521452017-04-12 14:34:08 +02004192 sta_flags_policy, info->extack))
Johannes Berg5727ef12007-12-19 02:03:34 +01004193 return -EINVAL;
4194
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004195 /*
4196 * Only allow certain flags for interface types so that
4197 * other attributes are silently ignored. Remember that
4198 * this is backward compatibility code with old userspace
4199 * and shouldn't be hit in other cases anyway.
4200 */
4201 switch (iftype) {
4202 case NL80211_IFTYPE_AP:
4203 case NL80211_IFTYPE_AP_VLAN:
4204 case NL80211_IFTYPE_P2P_GO:
4205 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4206 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4207 BIT(NL80211_STA_FLAG_WME) |
4208 BIT(NL80211_STA_FLAG_MFP);
4209 break;
4210 case NL80211_IFTYPE_P2P_CLIENT:
4211 case NL80211_IFTYPE_STATION:
4212 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4213 BIT(NL80211_STA_FLAG_TDLS_PEER);
4214 break;
4215 case NL80211_IFTYPE_MESH_POINT:
4216 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4217 BIT(NL80211_STA_FLAG_MFP) |
4218 BIT(NL80211_STA_FLAG_AUTHORIZED);
4219 default:
4220 return -EINVAL;
4221 }
Johannes Berg5727ef12007-12-19 02:03:34 +01004222
Johannes Berg3383b5a2012-05-10 20:14:43 +02004223 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
4224 if (flags[flag]) {
Johannes Bergeccb8e82009-05-11 21:57:56 +03004225 params->sta_flags_set |= (1<<flag);
Johannes Berg5727ef12007-12-19 02:03:34 +01004226
Johannes Berg3383b5a2012-05-10 20:14:43 +02004227 /* no longer support new API additions in old API */
4228 if (flag > NL80211_STA_FLAG_MAX_OLD_API)
4229 return -EINVAL;
4230 }
4231 }
4232
Johannes Berg5727ef12007-12-19 02:03:34 +01004233 return 0;
4234}
4235
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004236static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
4237 int attr)
4238{
4239 struct nlattr *rate;
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004240 u32 bitrate;
4241 u16 bitrate_compat;
Matthias Kaehlckebbf67e42017-04-17 15:59:52 -07004242 enum nl80211_rate_info rate_flg;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004243
4244 rate = nla_nest_start(msg, attr);
4245 if (!rate)
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004246 return false;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004247
4248 /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
4249 bitrate = cfg80211_calculate_bitrate(info);
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004250 /* report 16-bit bitrate only if we can */
4251 bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004252 if (bitrate > 0 &&
4253 nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
4254 return false;
4255 if (bitrate_compat > 0 &&
4256 nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
4257 return false;
4258
Johannes Bergb51f3be2015-01-15 16:14:02 +01004259 switch (info->bw) {
4260 case RATE_INFO_BW_5:
4261 rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
4262 break;
4263 case RATE_INFO_BW_10:
4264 rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
4265 break;
4266 default:
4267 WARN_ON(1);
4268 /* fall through */
4269 case RATE_INFO_BW_20:
4270 rate_flg = 0;
4271 break;
4272 case RATE_INFO_BW_40:
4273 rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
4274 break;
4275 case RATE_INFO_BW_80:
4276 rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
4277 break;
4278 case RATE_INFO_BW_160:
4279 rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
4280 break;
4281 }
4282
4283 if (rate_flg && nla_put_flag(msg, rate_flg))
4284 return false;
4285
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004286 if (info->flags & RATE_INFO_FLAGS_MCS) {
4287 if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
4288 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004289 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4290 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4291 return false;
4292 } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
4293 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
4294 return false;
4295 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
4296 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004297 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4298 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4299 return false;
4300 }
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004301
4302 nla_nest_end(msg, rate);
4303 return true;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004304}
4305
Felix Fietkau119363c2013-04-22 16:29:30 +02004306static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
4307 int id)
4308{
4309 void *attr;
4310 int i = 0;
4311
4312 if (!mask)
4313 return true;
4314
4315 attr = nla_nest_start(msg, id);
4316 if (!attr)
4317 return false;
4318
4319 for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
4320 if (!(mask & BIT(i)))
4321 continue;
4322
4323 if (nla_put_u8(msg, i, signal[i]))
4324 return false;
4325 }
4326
4327 nla_nest_end(msg, attr);
4328
4329 return true;
4330}
4331
Johannes Bergcf5ead82014-11-14 17:14:00 +01004332static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
4333 u32 seq, int flags,
John W. Linville66266b32012-03-15 13:25:41 -04004334 struct cfg80211_registered_device *rdev,
4335 struct net_device *dev,
Johannes Berg98b62182009-12-23 13:15:44 +01004336 const u8 *mac_addr, struct station_info *sinfo)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004337{
4338 void *hdr;
Paul Stewartf4263c92011-03-31 09:25:41 -07004339 struct nlattr *sinfoattr, *bss_param;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004340
Johannes Bergcf5ead82014-11-14 17:14:00 +01004341 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004342 if (!hdr)
4343 return -1;
4344
David S. Miller9360ffd2012-03-29 04:41:26 -04004345 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
4346 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
4347 nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
4348 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02004349
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004350 sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
4351 if (!sinfoattr)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004352 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004353
4354#define PUT_SINFO(attr, memb, type) do { \
Johannes Bergd686b922016-04-26 09:54:11 +02004355 BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
Mohammed Shafi Shajakhan739960f2016-04-07 19:59:34 +05304356 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
Johannes Berg319090b2014-11-17 14:08:11 +01004357 nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
4358 sinfo->memb)) \
4359 goto nla_put_failure; \
4360 } while (0)
Johannes Bergd686b922016-04-26 09:54:11 +02004361#define PUT_SINFO_U64(attr, memb) do { \
4362 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
4363 nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
4364 sinfo->memb, NL80211_STA_INFO_PAD)) \
4365 goto nla_put_failure; \
4366 } while (0)
Johannes Berg319090b2014-11-17 14:08:11 +01004367
4368 PUT_SINFO(CONNECTED_TIME, connected_time, u32);
4369 PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
4370
4371 if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) |
4372 BIT(NL80211_STA_INFO_RX_BYTES64)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004373 nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004374 (u32)sinfo->rx_bytes))
4375 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004376
4377 if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) |
4378 BIT(NL80211_STA_INFO_TX_BYTES64)) &&
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004379 nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
4380 (u32)sinfo->tx_bytes))
4381 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004382
Johannes Bergd686b922016-04-26 09:54:11 +02004383 PUT_SINFO_U64(RX_BYTES64, rx_bytes);
4384 PUT_SINFO_U64(TX_BYTES64, tx_bytes);
Johannes Berg319090b2014-11-17 14:08:11 +01004385 PUT_SINFO(LLID, llid, u16);
4386 PUT_SINFO(PLID, plid, u16);
4387 PUT_SINFO(PLINK_STATE, plink_state, u8);
Johannes Bergd686b922016-04-26 09:54:11 +02004388 PUT_SINFO_U64(RX_DURATION, rx_duration);
Johannes Berg319090b2014-11-17 14:08:11 +01004389
John W. Linville66266b32012-03-15 13:25:41 -04004390 switch (rdev->wiphy.signal_type) {
4391 case CFG80211_SIGNAL_TYPE_MBM:
Johannes Berg319090b2014-11-17 14:08:11 +01004392 PUT_SINFO(SIGNAL, signal, u8);
4393 PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
John W. Linville66266b32012-03-15 13:25:41 -04004394 break;
4395 default:
4396 break;
4397 }
Johannes Berg319090b2014-11-17 14:08:11 +01004398 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004399 if (!nl80211_put_signal(msg, sinfo->chains,
4400 sinfo->chain_signal,
4401 NL80211_STA_INFO_CHAIN_SIGNAL))
4402 goto nla_put_failure;
4403 }
Johannes Berg319090b2014-11-17 14:08:11 +01004404 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004405 if (!nl80211_put_signal(msg, sinfo->chains,
4406 sinfo->chain_signal_avg,
4407 NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
4408 goto nla_put_failure;
4409 }
Johannes Berg319090b2014-11-17 14:08:11 +01004410 if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004411 if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
4412 NL80211_STA_INFO_TX_BITRATE))
Henning Rogge420e7fa2008-12-11 22:04:19 +01004413 goto nla_put_failure;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004414 }
Johannes Berg319090b2014-11-17 14:08:11 +01004415 if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004416 if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
4417 NL80211_STA_INFO_RX_BITRATE))
4418 goto nla_put_failure;
Henning Rogge420e7fa2008-12-11 22:04:19 +01004419 }
Johannes Berg319090b2014-11-17 14:08:11 +01004420
4421 PUT_SINFO(RX_PACKETS, rx_packets, u32);
4422 PUT_SINFO(TX_PACKETS, tx_packets, u32);
4423 PUT_SINFO(TX_RETRIES, tx_retries, u32);
4424 PUT_SINFO(TX_FAILED, tx_failed, u32);
4425 PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
4426 PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
4427 PUT_SINFO(LOCAL_PM, local_pm, u32);
4428 PUT_SINFO(PEER_PM, peer_pm, u32);
4429 PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
4430
4431 if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) {
Paul Stewartf4263c92011-03-31 09:25:41 -07004432 bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
4433 if (!bss_param)
4434 goto nla_put_failure;
4435
David S. Miller9360ffd2012-03-29 04:41:26 -04004436 if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
4437 nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
4438 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
4439 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
4440 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
4441 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
4442 nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
4443 sinfo->bss_param.dtim_period) ||
4444 nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
4445 sinfo->bss_param.beacon_interval))
4446 goto nla_put_failure;
Paul Stewartf4263c92011-03-31 09:25:41 -07004447
4448 nla_nest_end(msg, bss_param);
4449 }
Johannes Berg319090b2014-11-17 14:08:11 +01004450 if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004451 nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
4452 sizeof(struct nl80211_sta_flag_update),
4453 &sinfo->sta_flags))
4454 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004455
Johannes Bergd686b922016-04-26 09:54:11 +02004456 PUT_SINFO_U64(T_OFFSET, t_offset);
4457 PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
4458 PUT_SINFO_U64(BEACON_RX, rx_beacon);
Johannes Berga76b1942014-11-17 14:12:22 +01004459 PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
Johannes Berg319090b2014-11-17 14:08:11 +01004460
4461#undef PUT_SINFO
Johannes Bergd686b922016-04-26 09:54:11 +02004462#undef PUT_SINFO_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004463
4464 if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) {
4465 struct nlattr *tidsattr;
4466 int tid;
4467
4468 tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS);
4469 if (!tidsattr)
4470 goto nla_put_failure;
4471
4472 for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
4473 struct cfg80211_tid_stats *tidstats;
4474 struct nlattr *tidattr;
4475
4476 tidstats = &sinfo->pertid[tid];
4477
4478 if (!tidstats->filled)
4479 continue;
4480
4481 tidattr = nla_nest_start(msg, tid + 1);
4482 if (!tidattr)
4483 goto nla_put_failure;
4484
Johannes Bergd686b922016-04-26 09:54:11 +02004485#define PUT_TIDVAL_U64(attr, memb) do { \
Johannes Berg6de39802014-12-19 12:34:00 +01004486 if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
Johannes Bergd686b922016-04-26 09:54:11 +02004487 nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
4488 tidstats->memb, NL80211_TID_STATS_PAD)) \
Johannes Berg6de39802014-12-19 12:34:00 +01004489 goto nla_put_failure; \
4490 } while (0)
4491
Johannes Bergd686b922016-04-26 09:54:11 +02004492 PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
4493 PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
4494 PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
4495 PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
Johannes Berg6de39802014-12-19 12:34:00 +01004496
Johannes Bergd686b922016-04-26 09:54:11 +02004497#undef PUT_TIDVAL_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004498 nla_nest_end(msg, tidattr);
4499 }
4500
4501 nla_nest_end(msg, tidsattr);
4502 }
4503
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004504 nla_nest_end(msg, sinfoattr);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004505
Johannes Berg319090b2014-11-17 14:08:11 +01004506 if (sinfo->assoc_req_ies_len &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004507 nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
4508 sinfo->assoc_req_ies))
4509 goto nla_put_failure;
Jouni Malinen50d3dfb2011-08-08 12:11:52 +03004510
Johannes Berg053c0952015-01-16 22:09:00 +01004511 genlmsg_end(msg, hdr);
4512 return 0;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004513
4514 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07004515 genlmsg_cancel(msg, hdr);
4516 return -EMSGSIZE;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004517}
4518
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004519static int nl80211_dump_station(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004520 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004521{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004522 struct station_info sinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004523 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02004524 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004525 u8 mac_addr[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02004526 int sta_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004527 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004528
Johannes Bergea90e0d2017-03-15 14:26:04 +01004529 rtnl_lock();
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004530 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02004531 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +01004532 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004533
Johannes Berg97990a02013-04-19 01:02:55 +02004534 if (!wdev->netdev) {
4535 err = -EINVAL;
4536 goto out_err;
4537 }
4538
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004539 if (!rdev->ops->dump_station) {
Jouni Malineneec60b02009-03-20 21:21:19 +02004540 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004541 goto out_err;
4542 }
4543
Johannes Bergbba95fe2008-07-29 13:22:51 +02004544 while (1) {
Jouni Malinenf612ced2011-08-11 11:46:22 +03004545 memset(&sinfo, 0, sizeof(sinfo));
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004546 err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
Hila Gonene35e4d22012-06-27 17:19:42 +03004547 mac_addr, &sinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02004548 if (err == -ENOENT)
4549 break;
4550 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01004551 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004552
Johannes Bergcf5ead82014-11-14 17:14:00 +01004553 if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004554 NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004555 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004556 rdev, wdev->netdev, mac_addr,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004557 &sinfo) < 0)
4558 goto out;
4559
4560 sta_idx++;
4561 }
4562
Johannes Bergbba95fe2008-07-29 13:22:51 +02004563 out:
Johannes Berg97990a02013-04-19 01:02:55 +02004564 cb->args[2] = sta_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004565 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004566 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01004567 rtnl_unlock();
Johannes Bergbba95fe2008-07-29 13:22:51 +02004568
4569 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004570}
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004571
Johannes Berg5727ef12007-12-19 02:03:34 +01004572static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
4573{
Johannes Berg4c476992010-10-04 21:36:35 +02004574 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4575 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004576 struct station_info sinfo;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004577 struct sk_buff *msg;
4578 u8 *mac_addr = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02004579 int err;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004580
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004581 memset(&sinfo, 0, sizeof(sinfo));
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004582
4583 if (!info->attrs[NL80211_ATTR_MAC])
4584 return -EINVAL;
4585
4586 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4587
Johannes Berg4c476992010-10-04 21:36:35 +02004588 if (!rdev->ops->get_station)
4589 return -EOPNOTSUPP;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004590
Hila Gonene35e4d22012-06-27 17:19:42 +03004591 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004592 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02004593 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004594
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07004595 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004596 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02004597 return -ENOMEM;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004598
Johannes Bergcf5ead82014-11-14 17:14:00 +01004599 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
4600 info->snd_portid, info->snd_seq, 0,
John W. Linville66266b32012-03-15 13:25:41 -04004601 rdev, dev, mac_addr, &sinfo) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02004602 nlmsg_free(msg);
4603 return -ENOBUFS;
4604 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004605
Johannes Berg4c476992010-10-04 21:36:35 +02004606 return genlmsg_reply(msg, info);
Johannes Berg5727ef12007-12-19 02:03:34 +01004607}
4608
Johannes Berg77ee7c82013-02-15 00:48:33 +01004609int cfg80211_check_station_change(struct wiphy *wiphy,
4610 struct station_parameters *params,
4611 enum cfg80211_station_type statype)
4612{
Ayala Bekere4208422015-10-23 11:20:06 +03004613 if (params->listen_interval != -1 &&
4614 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004615 return -EINVAL;
Ayala Bekere4208422015-10-23 11:20:06 +03004616
Ayala Beker17b94242016-03-17 15:41:38 +02004617 if (params->support_p2p_ps != -1 &&
4618 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
4619 return -EINVAL;
4620
Arik Nemtsovc72e1142014-07-17 17:14:29 +03004621 if (params->aid &&
Ayala Bekere4208422015-10-23 11:20:06 +03004622 !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
4623 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004624 return -EINVAL;
4625
4626 /* When you run into this, adjust the code below for the new flag */
4627 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
4628
4629 switch (statype) {
Thomas Pederseneef941e2013-03-04 13:06:11 -08004630 case CFG80211_STA_MESH_PEER_KERNEL:
4631 case CFG80211_STA_MESH_PEER_USER:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004632 /*
4633 * No ignoring the TDLS flag here -- the userspace mesh
4634 * code doesn't have the bug of including TDLS in the
4635 * mask everywhere.
4636 */
4637 if (params->sta_flags_mask &
4638 ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4639 BIT(NL80211_STA_FLAG_MFP) |
4640 BIT(NL80211_STA_FLAG_AUTHORIZED)))
4641 return -EINVAL;
4642 break;
4643 case CFG80211_STA_TDLS_PEER_SETUP:
4644 case CFG80211_STA_TDLS_PEER_ACTIVE:
4645 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
4646 return -EINVAL;
4647 /* ignore since it can't change */
4648 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4649 break;
4650 default:
4651 /* disallow mesh-specific things */
4652 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
4653 return -EINVAL;
4654 if (params->local_pm)
4655 return -EINVAL;
4656 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4657 return -EINVAL;
4658 }
4659
4660 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4661 statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
4662 /* TDLS can't be set, ... */
4663 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
4664 return -EINVAL;
4665 /*
4666 * ... but don't bother the driver with it. This works around
4667 * a hostapd/wpa_supplicant issue -- it always includes the
4668 * TLDS_PEER flag in the mask even for AP mode.
4669 */
4670 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4671 }
4672
Ayala Beker47edb112015-09-21 15:49:53 +03004673 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4674 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004675 /* reject other things that can't change */
4676 if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
4677 return -EINVAL;
4678 if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
4679 return -EINVAL;
4680 if (params->supported_rates)
4681 return -EINVAL;
4682 if (params->ext_capab || params->ht_capa || params->vht_capa)
4683 return -EINVAL;
4684 }
4685
Ayala Beker47edb112015-09-21 15:49:53 +03004686 if (statype != CFG80211_STA_AP_CLIENT &&
4687 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004688 if (params->vlan)
4689 return -EINVAL;
4690 }
4691
4692 switch (statype) {
4693 case CFG80211_STA_AP_MLME_CLIENT:
4694 /* Use this only for authorizing/unauthorizing a station */
4695 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4696 return -EOPNOTSUPP;
4697 break;
4698 case CFG80211_STA_AP_CLIENT:
Ayala Beker47edb112015-09-21 15:49:53 +03004699 case CFG80211_STA_AP_CLIENT_UNASSOC:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004700 /* accept only the listed bits */
4701 if (params->sta_flags_mask &
4702 ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4703 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4704 BIT(NL80211_STA_FLAG_ASSOCIATED) |
4705 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4706 BIT(NL80211_STA_FLAG_WME) |
4707 BIT(NL80211_STA_FLAG_MFP)))
4708 return -EINVAL;
4709
4710 /* but authenticated/associated only if driver handles it */
4711 if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
4712 params->sta_flags_mask &
4713 (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4714 BIT(NL80211_STA_FLAG_ASSOCIATED)))
4715 return -EINVAL;
4716 break;
4717 case CFG80211_STA_IBSS:
4718 case CFG80211_STA_AP_STA:
4719 /* reject any changes other than AUTHORIZED */
4720 if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
4721 return -EINVAL;
4722 break;
4723 case CFG80211_STA_TDLS_PEER_SETUP:
4724 /* reject any changes other than AUTHORIZED or WME */
4725 if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4726 BIT(NL80211_STA_FLAG_WME)))
4727 return -EINVAL;
4728 /* force (at least) rates when authorizing */
4729 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
4730 !params->supported_rates)
4731 return -EINVAL;
4732 break;
4733 case CFG80211_STA_TDLS_PEER_ACTIVE:
4734 /* reject any changes */
4735 return -EINVAL;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004736 case CFG80211_STA_MESH_PEER_KERNEL:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004737 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4738 return -EINVAL;
4739 break;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004740 case CFG80211_STA_MESH_PEER_USER:
Chun-Yeow Yeoh42925042015-04-18 01:30:02 +08004741 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
4742 params->plink_action != NL80211_PLINK_ACTION_BLOCK)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004743 return -EINVAL;
4744 break;
4745 }
4746
Beni Lev06f7c882016-07-19 19:28:56 +03004747 /*
4748 * Older kernel versions ignored this attribute entirely, so don't
4749 * reject attempts to update it but mark it as unused instead so the
4750 * driver won't look at the data.
4751 */
4752 if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
4753 statype != CFG80211_STA_TDLS_PEER_SETUP)
4754 params->opmode_notif_used = false;
4755
Johannes Berg77ee7c82013-02-15 00:48:33 +01004756 return 0;
4757}
4758EXPORT_SYMBOL(cfg80211_check_station_change);
4759
Johannes Berg5727ef12007-12-19 02:03:34 +01004760/*
Felix Fietkauc258d2d2009-11-11 17:23:31 +01004761 * Get vlan interface making sure it is running and on the right wiphy.
Johannes Berg5727ef12007-12-19 02:03:34 +01004762 */
Johannes Berg80b99892011-11-18 16:23:01 +01004763static struct net_device *get_vlan(struct genl_info *info,
4764 struct cfg80211_registered_device *rdev)
Johannes Berg5727ef12007-12-19 02:03:34 +01004765{
Johannes Berg463d0182009-07-14 00:33:35 +02004766 struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
Johannes Berg80b99892011-11-18 16:23:01 +01004767 struct net_device *v;
4768 int ret;
Johannes Berg5727ef12007-12-19 02:03:34 +01004769
Johannes Berg80b99892011-11-18 16:23:01 +01004770 if (!vlanattr)
4771 return NULL;
4772
4773 v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
4774 if (!v)
4775 return ERR_PTR(-ENODEV);
4776
4777 if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
4778 ret = -EINVAL;
4779 goto error;
Johannes Berg5727ef12007-12-19 02:03:34 +01004780 }
Johannes Berg80b99892011-11-18 16:23:01 +01004781
Johannes Berg77ee7c82013-02-15 00:48:33 +01004782 if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
4783 v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4784 v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
4785 ret = -EINVAL;
4786 goto error;
4787 }
4788
Johannes Berg80b99892011-11-18 16:23:01 +01004789 if (!netif_running(v)) {
4790 ret = -ENETDOWN;
4791 goto error;
4792 }
4793
4794 return v;
4795 error:
4796 dev_put(v);
4797 return ERR_PTR(ret);
Johannes Berg5727ef12007-12-19 02:03:34 +01004798}
4799
Johannes Berg94e860f2014-01-20 23:58:15 +01004800static const struct nla_policy
4801nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
Jouni Malinendf881292013-02-14 21:10:54 +02004802 [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
4803 [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
4804};
4805
Johannes Bergff276692013-02-15 00:09:01 +01004806static int nl80211_parse_sta_wme(struct genl_info *info,
4807 struct station_parameters *params)
Jouni Malinendf881292013-02-14 21:10:54 +02004808{
Jouni Malinendf881292013-02-14 21:10:54 +02004809 struct nlattr *tb[NL80211_STA_WME_MAX + 1];
4810 struct nlattr *nla;
4811 int err;
4812
Jouni Malinendf881292013-02-14 21:10:54 +02004813 /* parse WME attributes if present */
4814 if (!info->attrs[NL80211_ATTR_STA_WME])
4815 return 0;
4816
4817 nla = info->attrs[NL80211_ATTR_STA_WME];
4818 err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
Johannes Bergfe521452017-04-12 14:34:08 +02004819 nl80211_sta_wme_policy, info->extack);
Jouni Malinendf881292013-02-14 21:10:54 +02004820 if (err)
4821 return err;
4822
4823 if (tb[NL80211_STA_WME_UAPSD_QUEUES])
4824 params->uapsd_queues = nla_get_u8(
4825 tb[NL80211_STA_WME_UAPSD_QUEUES]);
4826 if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
4827 return -EINVAL;
4828
4829 if (tb[NL80211_STA_WME_MAX_SP])
4830 params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
4831
4832 if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
4833 return -EINVAL;
4834
4835 params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
4836
4837 return 0;
4838}
4839
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304840static int nl80211_parse_sta_channel_info(struct genl_info *info,
4841 struct station_parameters *params)
4842{
4843 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
4844 params->supported_channels =
4845 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4846 params->supported_channels_len =
4847 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4848 /*
4849 * Need to include at least one (first channel, number of
4850 * channels) tuple for each subband, and must have proper
4851 * tuples for the rest of the data as well.
4852 */
4853 if (params->supported_channels_len < 2)
4854 return -EINVAL;
4855 if (params->supported_channels_len % 2)
4856 return -EINVAL;
4857 }
4858
4859 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
4860 params->supported_oper_classes =
4861 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4862 params->supported_oper_classes_len =
4863 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4864 /*
4865 * The value of the Length field of the Supported Operating
4866 * Classes element is between 2 and 253.
4867 */
4868 if (params->supported_oper_classes_len < 2 ||
4869 params->supported_oper_classes_len > 253)
4870 return -EINVAL;
4871 }
4872 return 0;
4873}
4874
Johannes Bergff276692013-02-15 00:09:01 +01004875static int nl80211_set_station_tdls(struct genl_info *info,
4876 struct station_parameters *params)
4877{
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304878 int err;
Johannes Bergff276692013-02-15 00:09:01 +01004879 /* Dummy STA entry gets updated once the peer capabilities are known */
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03004880 if (info->attrs[NL80211_ATTR_PEER_AID])
4881 params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Johannes Bergff276692013-02-15 00:09:01 +01004882 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
4883 params->ht_capa =
4884 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
4885 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
4886 params->vht_capa =
4887 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
4888
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304889 err = nl80211_parse_sta_channel_info(info, params);
4890 if (err)
4891 return err;
4892
Johannes Bergff276692013-02-15 00:09:01 +01004893 return nl80211_parse_sta_wme(info, params);
4894}
4895
Johannes Berg5727ef12007-12-19 02:03:34 +01004896static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
4897{
Johannes Berg4c476992010-10-04 21:36:35 +02004898 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02004899 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01004900 struct station_parameters params;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004901 u8 *mac_addr;
4902 int err;
Johannes Berg5727ef12007-12-19 02:03:34 +01004903
4904 memset(&params, 0, sizeof(params));
4905
Johannes Berg77ee7c82013-02-15 00:48:33 +01004906 if (!rdev->ops->change_station)
4907 return -EOPNOTSUPP;
4908
Ayala Bekere4208422015-10-23 11:20:06 +03004909 /*
4910 * AID and listen_interval properties can be set only for unassociated
4911 * station. Include these parameters here and will check them in
4912 * cfg80211_check_station_change().
4913 */
Ayala Bekera9bc31e2015-11-26 16:26:12 +01004914 if (info->attrs[NL80211_ATTR_STA_AID])
4915 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Ayala Bekere4208422015-10-23 11:20:06 +03004916
4917 if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
4918 params.listen_interval =
4919 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
4920 else
4921 params.listen_interval = -1;
Johannes Berg5727ef12007-12-19 02:03:34 +01004922
Ayala Beker17b94242016-03-17 15:41:38 +02004923 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
4924 u8 tmp;
4925
4926 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
4927 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
4928 return -EINVAL;
4929
4930 params.support_p2p_ps = tmp;
4931 } else {
4932 params.support_p2p_ps = -1;
4933 }
4934
Johannes Berg5727ef12007-12-19 02:03:34 +01004935 if (!info->attrs[NL80211_ATTR_MAC])
4936 return -EINVAL;
4937
4938 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4939
4940 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
4941 params.supported_rates =
4942 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4943 params.supported_rates_len =
4944 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4945 }
4946
Jouni Malinen9d62a982013-02-14 21:10:13 +02004947 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
4948 params.capability =
4949 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
4950 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
4951 }
4952
4953 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
4954 params.ext_capab =
4955 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4956 params.ext_capab_len =
4957 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4958 }
4959
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004960 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01004961 return -EINVAL;
4962
Johannes Bergf8bacc22013-02-14 23:27:01 +01004963 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004964 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01004965 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
4966 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
4967 return -EINVAL;
4968 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004969
Johannes Bergf8bacc22013-02-14 23:27:01 +01004970 if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
Javier Cardona9c3990a2011-05-03 16:57:11 -07004971 params.plink_state =
Johannes Bergf8bacc22013-02-14 23:27:01 +01004972 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
4973 if (params.plink_state >= NUM_NL80211_PLINK_STATES)
4974 return -EINVAL;
Masashi Honma7d27a0b2016-07-01 10:19:34 +09004975 if (info->attrs[NL80211_ATTR_MESH_PEER_AID]) {
4976 params.peer_aid = nla_get_u16(
4977 info->attrs[NL80211_ATTR_MESH_PEER_AID]);
4978 if (params.peer_aid > IEEE80211_MAX_AID)
4979 return -EINVAL;
4980 }
Johannes Bergf8bacc22013-02-14 23:27:01 +01004981 params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
4982 }
Javier Cardona9c3990a2011-05-03 16:57:11 -07004983
Marco Porsch3b1c5a52013-01-07 16:04:52 +01004984 if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
4985 enum nl80211_mesh_power_mode pm = nla_get_u32(
4986 info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
4987
4988 if (pm <= NL80211_MESH_POWER_UNKNOWN ||
4989 pm > NL80211_MESH_POWER_MAX)
4990 return -EINVAL;
4991
4992 params.local_pm = pm;
4993 }
4994
Beni Lev06f7c882016-07-19 19:28:56 +03004995 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
4996 params.opmode_notif_used = true;
4997 params.opmode_notif =
4998 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
4999 }
5000
Johannes Berg77ee7c82013-02-15 00:48:33 +01005001 /* Include parameters for TDLS peer (will check later) */
5002 err = nl80211_set_station_tdls(info, &params);
5003 if (err)
5004 return err;
5005
5006 params.vlan = get_vlan(info, rdev);
5007 if (IS_ERR(params.vlan))
5008 return PTR_ERR(params.vlan);
5009
Johannes Berga97f4422009-06-18 17:23:43 +02005010 switch (dev->ieee80211_ptr->iftype) {
5011 case NL80211_IFTYPE_AP:
5012 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02005013 case NL80211_IFTYPE_P2P_GO:
Johannes Berg074ac8d2010-09-16 14:58:22 +02005014 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berga97f4422009-06-18 17:23:43 +02005015 case NL80211_IFTYPE_STATION:
Antonio Quartulli267335d2012-01-31 20:25:47 +01005016 case NL80211_IFTYPE_ADHOC:
Johannes Berga97f4422009-06-18 17:23:43 +02005017 case NL80211_IFTYPE_MESH_POINT:
Johannes Berga97f4422009-06-18 17:23:43 +02005018 break;
5019 default:
Johannes Berg77ee7c82013-02-15 00:48:33 +01005020 err = -EOPNOTSUPP;
5021 goto out_put_vlan;
Johannes Berg034d6552009-05-27 10:35:29 +02005022 }
5023
Johannes Berg77ee7c82013-02-15 00:48:33 +01005024 /* driver will call cfg80211_check_station_change() */
Hila Gonene35e4d22012-06-27 17:19:42 +03005025 err = rdev_change_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005026
Johannes Berg77ee7c82013-02-15 00:48:33 +01005027 out_put_vlan:
Johannes Berg5727ef12007-12-19 02:03:34 +01005028 if (params.vlan)
5029 dev_put(params.vlan);
Johannes Berg3b858752009-03-12 09:55:09 +01005030
Johannes Berg5727ef12007-12-19 02:03:34 +01005031 return err;
5032}
5033
5034static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
5035{
Johannes Berg4c476992010-10-04 21:36:35 +02005036 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg5727ef12007-12-19 02:03:34 +01005037 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02005038 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01005039 struct station_parameters params;
5040 u8 *mac_addr = NULL;
Johannes Bergbda95eb2015-11-26 16:26:13 +01005041 u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
5042 BIT(NL80211_STA_FLAG_ASSOCIATED);
Johannes Berg5727ef12007-12-19 02:03:34 +01005043
5044 memset(&params, 0, sizeof(params));
5045
Johannes Berg984c3112013-02-14 23:43:25 +01005046 if (!rdev->ops->add_station)
5047 return -EOPNOTSUPP;
5048
Johannes Berg5727ef12007-12-19 02:03:34 +01005049 if (!info->attrs[NL80211_ATTR_MAC])
5050 return -EINVAL;
5051
Johannes Berg5727ef12007-12-19 02:03:34 +01005052 if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
5053 return -EINVAL;
5054
5055 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
5056 return -EINVAL;
5057
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03005058 if (!info->attrs[NL80211_ATTR_STA_AID] &&
5059 !info->attrs[NL80211_ATTR_PEER_AID])
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02005060 return -EINVAL;
5061
Johannes Berg5727ef12007-12-19 02:03:34 +01005062 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
5063 params.supported_rates =
5064 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5065 params.supported_rates_len =
5066 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5067 params.listen_interval =
5068 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
Johannes Berg51b50fb2009-05-24 16:42:30 +02005069
Ayala Beker17b94242016-03-17 15:41:38 +02005070 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
5071 u8 tmp;
5072
5073 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
5074 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
5075 return -EINVAL;
5076
5077 params.support_p2p_ps = tmp;
5078 } else {
5079 /*
5080 * if not specified, assume it's supported for P2P GO interface,
5081 * and is NOT supported for AP interface
5082 */
5083 params.support_p2p_ps =
5084 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO;
5085 }
5086
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005087 if (info->attrs[NL80211_ATTR_PEER_AID])
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03005088 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005089 else
5090 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02005091 if (!params.aid || params.aid > IEEE80211_MAX_AID)
5092 return -EINVAL;
Johannes Berg51b50fb2009-05-24 16:42:30 +02005093
Jouni Malinen9d62a982013-02-14 21:10:13 +02005094 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
5095 params.capability =
5096 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
5097 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
5098 }
5099
5100 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
5101 params.ext_capab =
5102 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5103 params.ext_capab_len =
5104 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5105 }
5106
Jouni Malinen36aedc92008-08-25 11:58:58 +03005107 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
5108 params.ht_capa =
5109 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005110
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +00005111 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
5112 params.vht_capa =
5113 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
5114
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +01005115 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
5116 params.opmode_notif_used = true;
5117 params.opmode_notif =
5118 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
5119 }
5120
Johannes Bergf8bacc22013-02-14 23:27:01 +01005121 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Javier Cardona96b78df2011-04-07 15:08:33 -07005122 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01005123 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
5124 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
5125 return -EINVAL;
5126 }
Javier Cardona96b78df2011-04-07 15:08:33 -07005127
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305128 err = nl80211_parse_sta_channel_info(info, &params);
5129 if (err)
5130 return err;
5131
Johannes Bergff276692013-02-15 00:09:01 +01005132 err = nl80211_parse_sta_wme(info, &params);
5133 if (err)
5134 return err;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005135
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005136 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01005137 return -EINVAL;
5138
Johannes Berg496fcc22015-03-12 08:53:27 +02005139 /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
5140 * as userspace might just pass through the capabilities from the IEs
5141 * directly, rather than enforcing this restriction and returning an
5142 * error in this case.
5143 */
5144 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
5145 params.ht_capa = NULL;
5146 params.vht_capa = NULL;
5147 }
5148
Johannes Berg77ee7c82013-02-15 00:48:33 +01005149 /* When you run into this, adjust the code below for the new flag */
5150 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
5151
Johannes Bergbdd90d52011-12-14 12:20:27 +01005152 switch (dev->ieee80211_ptr->iftype) {
5153 case NL80211_IFTYPE_AP:
5154 case NL80211_IFTYPE_AP_VLAN:
5155 case NL80211_IFTYPE_P2P_GO:
Johannes Berg984c3112013-02-14 23:43:25 +01005156 /* ignore WME attributes if iface/sta is not capable */
5157 if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
5158 !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
5159 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005160
Johannes Bergbdd90d52011-12-14 12:20:27 +01005161 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005162 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5163 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005164 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005165 /* but don't bother the driver with it */
5166 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
Eliad Pellerc75786c2011-08-23 14:37:46 +03005167
Johannes Bergd582cff2012-10-26 17:53:44 +02005168 /* allow authenticated/associated only if driver handles it */
5169 if (!(rdev->wiphy.features &
5170 NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
Johannes Bergbda95eb2015-11-26 16:26:13 +01005171 params.sta_flags_mask & auth_assoc)
Johannes Bergd582cff2012-10-26 17:53:44 +02005172 return -EINVAL;
5173
Johannes Bergbda95eb2015-11-26 16:26:13 +01005174 /* Older userspace, or userspace wanting to be compatible with
5175 * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
5176 * and assoc flags in the mask, but assumes the station will be
5177 * added as associated anyway since this was the required driver
5178 * behaviour before NL80211_FEATURE_FULL_AP_CLIENT_STATE was
5179 * introduced.
5180 * In order to not bother drivers with this quirk in the API
5181 * set the flags in both the mask and set for new stations in
5182 * this case.
5183 */
5184 if (!(params.sta_flags_mask & auth_assoc)) {
5185 params.sta_flags_mask |= auth_assoc;
5186 params.sta_flags_set |= auth_assoc;
5187 }
5188
Johannes Bergbdd90d52011-12-14 12:20:27 +01005189 /* must be last in here for error handling */
5190 params.vlan = get_vlan(info, rdev);
5191 if (IS_ERR(params.vlan))
5192 return PTR_ERR(params.vlan);
5193 break;
5194 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg984c3112013-02-14 23:43:25 +01005195 /* ignore uAPSD data */
5196 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5197
Johannes Bergd582cff2012-10-26 17:53:44 +02005198 /* associated is disallowed */
5199 if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
5200 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005201 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005202 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5203 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005204 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005205 break;
5206 case NL80211_IFTYPE_STATION:
Johannes Berg93d08f02013-03-04 09:29:46 +01005207 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg984c3112013-02-14 23:43:25 +01005208 /* ignore uAPSD data */
5209 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5210
Johannes Berg77ee7c82013-02-15 00:48:33 +01005211 /* these are disallowed */
5212 if (params.sta_flags_mask &
5213 (BIT(NL80211_STA_FLAG_ASSOCIATED) |
5214 BIT(NL80211_STA_FLAG_AUTHENTICATED)))
Johannes Bergd582cff2012-10-26 17:53:44 +02005215 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005216 /* Only TDLS peers can be added */
5217 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
5218 return -EINVAL;
5219 /* Can only add if TDLS ... */
5220 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
5221 return -EOPNOTSUPP;
5222 /* ... with external setup is supported */
5223 if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
5224 return -EOPNOTSUPP;
Johannes Berg77ee7c82013-02-15 00:48:33 +01005225 /*
5226 * Older wpa_supplicant versions always mark the TDLS peer
5227 * as authorized, but it shouldn't yet be.
5228 */
5229 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
Johannes Bergbdd90d52011-12-14 12:20:27 +01005230 break;
5231 default:
5232 return -EOPNOTSUPP;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005233 }
5234
Johannes Bergbdd90d52011-12-14 12:20:27 +01005235 /* be aware of params.vlan when changing code here */
Johannes Berg5727ef12007-12-19 02:03:34 +01005236
Hila Gonene35e4d22012-06-27 17:19:42 +03005237 err = rdev_add_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005238
Johannes Berg5727ef12007-12-19 02:03:34 +01005239 if (params.vlan)
5240 dev_put(params.vlan);
Johannes Berg5727ef12007-12-19 02:03:34 +01005241 return err;
5242}
5243
5244static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
5245{
Johannes Berg4c476992010-10-04 21:36:35 +02005246 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5247 struct net_device *dev = info->user_ptr[1];
Jouni Malinen89c771e2014-10-10 20:52:40 +03005248 struct station_del_parameters params;
5249
5250 memset(&params, 0, sizeof(params));
Johannes Berg5727ef12007-12-19 02:03:34 +01005251
5252 if (info->attrs[NL80211_ATTR_MAC])
Jouni Malinen89c771e2014-10-10 20:52:40 +03005253 params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005254
Johannes Berge80cf852009-05-11 14:43:13 +02005255 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Marco Porschd5d9de02010-03-30 10:00:16 +02005256 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
Johannes Berg074ac8d2010-09-16 14:58:22 +02005257 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
Johannes Berg4c476992010-10-04 21:36:35 +02005258 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5259 return -EINVAL;
Johannes Berge80cf852009-05-11 14:43:13 +02005260
Johannes Berg4c476992010-10-04 21:36:35 +02005261 if (!rdev->ops->del_station)
5262 return -EOPNOTSUPP;
Johannes Berg5727ef12007-12-19 02:03:34 +01005263
Jouni Malinen98856862014-10-20 13:20:45 +03005264 if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
5265 params.subtype =
5266 nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
5267 if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
5268 params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
5269 return -EINVAL;
5270 } else {
5271 /* Default to Deauthentication frame */
5272 params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
5273 }
5274
5275 if (info->attrs[NL80211_ATTR_REASON_CODE]) {
5276 params.reason_code =
5277 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
5278 if (params.reason_code == 0)
5279 return -EINVAL; /* 0 is reserved */
5280 } else {
5281 /* Default to reason code 2 */
5282 params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
5283 }
5284
Jouni Malinen89c771e2014-10-10 20:52:40 +03005285 return rdev_del_station(rdev, dev, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005286}
5287
Eric W. Biederman15e47302012-09-07 20:12:54 +00005288static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005289 int flags, struct net_device *dev,
5290 u8 *dst, u8 *next_hop,
5291 struct mpath_info *pinfo)
5292{
5293 void *hdr;
5294 struct nlattr *pinfoattr;
5295
Henning Rogge1ef4c852014-11-04 16:14:58 +01005296 hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005297 if (!hdr)
5298 return -1;
5299
David S. Miller9360ffd2012-03-29 04:41:26 -04005300 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5301 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
5302 nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
5303 nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
5304 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02005305
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005306 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
5307 if (!pinfoattr)
5308 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005309 if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
5310 nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
5311 pinfo->frame_qlen))
5312 goto nla_put_failure;
5313 if (((pinfo->filled & MPATH_INFO_SN) &&
5314 nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
5315 ((pinfo->filled & MPATH_INFO_METRIC) &&
5316 nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
5317 pinfo->metric)) ||
5318 ((pinfo->filled & MPATH_INFO_EXPTIME) &&
5319 nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
5320 pinfo->exptime)) ||
5321 ((pinfo->filled & MPATH_INFO_FLAGS) &&
5322 nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
5323 pinfo->flags)) ||
5324 ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
5325 nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
5326 pinfo->discovery_timeout)) ||
5327 ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
5328 nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
5329 pinfo->discovery_retries)))
5330 goto nla_put_failure;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005331
5332 nla_nest_end(msg, pinfoattr);
5333
Johannes Berg053c0952015-01-16 22:09:00 +01005334 genlmsg_end(msg, hdr);
5335 return 0;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005336
5337 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07005338 genlmsg_cancel(msg, hdr);
5339 return -EMSGSIZE;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005340}
5341
5342static int nl80211_dump_mpath(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005343 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005344{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005345 struct mpath_info pinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005346 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02005347 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005348 u8 dst[ETH_ALEN];
5349 u8 next_hop[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02005350 int path_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005351 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005352
Johannes Bergea90e0d2017-03-15 14:26:04 +01005353 rtnl_lock();
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005354 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02005355 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +01005356 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005357
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005358 if (!rdev->ops->dump_mpath) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005359 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005360 goto out_err;
5361 }
5362
Johannes Berg97990a02013-04-19 01:02:55 +02005363 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005364 err = -EOPNOTSUPP;
Roel Kluin0448b5f2009-08-22 21:15:49 +02005365 goto out_err;
Jouni Malineneec60b02009-03-20 21:21:19 +02005366 }
5367
Johannes Bergbba95fe2008-07-29 13:22:51 +02005368 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005369 err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
Johannes Berg97990a02013-04-19 01:02:55 +02005370 next_hop, &pinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02005371 if (err == -ENOENT)
5372 break;
5373 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01005374 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005375
Eric W. Biederman15e47302012-09-07 20:12:54 +00005376 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005377 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg97990a02013-04-19 01:02:55 +02005378 wdev->netdev, dst, next_hop,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005379 &pinfo) < 0)
5380 goto out;
5381
5382 path_idx++;
5383 }
5384
Johannes Bergbba95fe2008-07-29 13:22:51 +02005385 out:
Johannes Berg97990a02013-04-19 01:02:55 +02005386 cb->args[2] = path_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005387 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005388 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01005389 rtnl_unlock();
Johannes Bergbba95fe2008-07-29 13:22:51 +02005390 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005391}
5392
5393static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
5394{
Johannes Berg4c476992010-10-04 21:36:35 +02005395 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005396 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02005397 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005398 struct mpath_info pinfo;
5399 struct sk_buff *msg;
5400 u8 *dst = NULL;
5401 u8 next_hop[ETH_ALEN];
5402
5403 memset(&pinfo, 0, sizeof(pinfo));
5404
5405 if (!info->attrs[NL80211_ATTR_MAC])
5406 return -EINVAL;
5407
5408 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5409
Johannes Berg4c476992010-10-04 21:36:35 +02005410 if (!rdev->ops->get_mpath)
5411 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005412
Johannes Berg4c476992010-10-04 21:36:35 +02005413 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5414 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005415
Hila Gonene35e4d22012-06-27 17:19:42 +03005416 err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005417 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005418 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005419
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005420 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005421 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02005422 return -ENOMEM;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005423
Eric W. Biederman15e47302012-09-07 20:12:54 +00005424 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg4c476992010-10-04 21:36:35 +02005425 dev, dst, next_hop, &pinfo) < 0) {
5426 nlmsg_free(msg);
5427 return -ENOBUFS;
5428 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005429
Johannes Berg4c476992010-10-04 21:36:35 +02005430 return genlmsg_reply(msg, info);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005431}
5432
5433static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
5434{
Johannes Berg4c476992010-10-04 21:36:35 +02005435 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5436 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005437 u8 *dst = NULL;
5438 u8 *next_hop = NULL;
5439
5440 if (!info->attrs[NL80211_ATTR_MAC])
5441 return -EINVAL;
5442
5443 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5444 return -EINVAL;
5445
5446 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5447 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5448
Johannes Berg4c476992010-10-04 21:36:35 +02005449 if (!rdev->ops->change_mpath)
5450 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005451
Johannes Berg4c476992010-10-04 21:36:35 +02005452 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5453 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005454
Hila Gonene35e4d22012-06-27 17:19:42 +03005455 return rdev_change_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005456}
Johannes Berg4c476992010-10-04 21:36:35 +02005457
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005458static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
5459{
Johannes Berg4c476992010-10-04 21:36:35 +02005460 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5461 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005462 u8 *dst = NULL;
5463 u8 *next_hop = NULL;
5464
5465 if (!info->attrs[NL80211_ATTR_MAC])
5466 return -EINVAL;
5467
5468 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5469 return -EINVAL;
5470
5471 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5472 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5473
Johannes Berg4c476992010-10-04 21:36:35 +02005474 if (!rdev->ops->add_mpath)
5475 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005476
Johannes Berg4c476992010-10-04 21:36:35 +02005477 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5478 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005479
Hila Gonene35e4d22012-06-27 17:19:42 +03005480 return rdev_add_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005481}
5482
5483static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
5484{
Johannes Berg4c476992010-10-04 21:36:35 +02005485 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5486 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005487 u8 *dst = NULL;
5488
5489 if (info->attrs[NL80211_ATTR_MAC])
5490 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5491
Johannes Berg4c476992010-10-04 21:36:35 +02005492 if (!rdev->ops->del_mpath)
5493 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005494
Hila Gonene35e4d22012-06-27 17:19:42 +03005495 return rdev_del_mpath(rdev, dev, dst);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005496}
5497
Henning Rogge66be7d22014-09-12 08:58:49 +02005498static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
5499{
5500 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5501 int err;
5502 struct net_device *dev = info->user_ptr[1];
5503 struct mpath_info pinfo;
5504 struct sk_buff *msg;
5505 u8 *dst = NULL;
5506 u8 mpp[ETH_ALEN];
5507
5508 memset(&pinfo, 0, sizeof(pinfo));
5509
5510 if (!info->attrs[NL80211_ATTR_MAC])
5511 return -EINVAL;
5512
5513 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5514
5515 if (!rdev->ops->get_mpp)
5516 return -EOPNOTSUPP;
5517
5518 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5519 return -EOPNOTSUPP;
5520
5521 err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
5522 if (err)
5523 return err;
5524
5525 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5526 if (!msg)
5527 return -ENOMEM;
5528
5529 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
5530 dev, dst, mpp, &pinfo) < 0) {
5531 nlmsg_free(msg);
5532 return -ENOBUFS;
5533 }
5534
5535 return genlmsg_reply(msg, info);
5536}
5537
5538static int nl80211_dump_mpp(struct sk_buff *skb,
5539 struct netlink_callback *cb)
5540{
5541 struct mpath_info pinfo;
5542 struct cfg80211_registered_device *rdev;
5543 struct wireless_dev *wdev;
5544 u8 dst[ETH_ALEN];
5545 u8 mpp[ETH_ALEN];
5546 int path_idx = cb->args[2];
5547 int err;
5548
Johannes Bergea90e0d2017-03-15 14:26:04 +01005549 rtnl_lock();
Henning Rogge66be7d22014-09-12 08:58:49 +02005550 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
5551 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +01005552 goto out_err;
Henning Rogge66be7d22014-09-12 08:58:49 +02005553
5554 if (!rdev->ops->dump_mpp) {
5555 err = -EOPNOTSUPP;
5556 goto out_err;
5557 }
5558
5559 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
5560 err = -EOPNOTSUPP;
5561 goto out_err;
5562 }
5563
5564 while (1) {
5565 err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
5566 mpp, &pinfo);
5567 if (err == -ENOENT)
5568 break;
5569 if (err)
5570 goto out_err;
5571
5572 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
5573 cb->nlh->nlmsg_seq, NLM_F_MULTI,
5574 wdev->netdev, dst, mpp,
5575 &pinfo) < 0)
5576 goto out;
5577
5578 path_idx++;
5579 }
5580
5581 out:
5582 cb->args[2] = path_idx;
5583 err = skb->len;
5584 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01005585 rtnl_unlock();
Henning Rogge66be7d22014-09-12 08:58:49 +02005586 return err;
5587}
5588
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005589static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
5590{
Johannes Berg4c476992010-10-04 21:36:35 +02005591 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5592 struct net_device *dev = info->user_ptr[1];
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005593 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005594 struct bss_parameters params;
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005595 int err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005596
5597 memset(&params, 0, sizeof(params));
5598 /* default to not changing parameters */
5599 params.use_cts_prot = -1;
5600 params.use_short_preamble = -1;
5601 params.use_short_slot_time = -1;
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005602 params.ap_isolate = -1;
Helmut Schaa50b12f52010-11-19 12:40:25 +01005603 params.ht_opmode = -1;
Johannes Berg53cabad2012-11-14 15:17:28 +01005604 params.p2p_ctwindow = -1;
5605 params.p2p_opp_ps = -1;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005606
5607 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
5608 params.use_cts_prot =
5609 nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
5610 if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
5611 params.use_short_preamble =
5612 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
5613 if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
5614 params.use_short_slot_time =
5615 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
Jouni Malinen90c97a02008-10-30 16:59:22 +02005616 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
5617 params.basic_rates =
5618 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5619 params.basic_rates_len =
5620 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5621 }
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005622 if (info->attrs[NL80211_ATTR_AP_ISOLATE])
5623 params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
Helmut Schaa50b12f52010-11-19 12:40:25 +01005624 if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
5625 params.ht_opmode =
5626 nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005627
Johannes Berg53cabad2012-11-14 15:17:28 +01005628 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
5629 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5630 return -EINVAL;
5631 params.p2p_ctwindow =
5632 nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
5633 if (params.p2p_ctwindow < 0)
5634 return -EINVAL;
5635 if (params.p2p_ctwindow != 0 &&
5636 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
5637 return -EINVAL;
5638 }
5639
5640 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
5641 u8 tmp;
5642
5643 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5644 return -EINVAL;
5645 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
5646 if (tmp > 1)
5647 return -EINVAL;
5648 params.p2p_opp_ps = tmp;
5649 if (params.p2p_opp_ps &&
5650 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
5651 return -EINVAL;
5652 }
5653
Johannes Berg4c476992010-10-04 21:36:35 +02005654 if (!rdev->ops->change_bss)
5655 return -EOPNOTSUPP;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005656
Johannes Berg074ac8d2010-09-16 14:58:22 +02005657 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Johannes Berg4c476992010-10-04 21:36:35 +02005658 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5659 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005660
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005661 wdev_lock(wdev);
5662 err = rdev_change_bss(rdev, dev, &params);
5663 wdev_unlock(wdev);
5664
5665 return err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005666}
5667
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005668static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
5669{
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005670 char *data = NULL;
Ilan peer05050752015-03-04 00:32:06 -05005671 bool is_indoor;
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005672 enum nl80211_user_reg_hint_type user_reg_hint_type;
Ilan peer05050752015-03-04 00:32:06 -05005673 u32 owner_nlportid;
5674
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005675 /*
5676 * You should only get this when cfg80211 hasn't yet initialized
5677 * completely when built-in to the kernel right between the time
5678 * window between nl80211_init() and regulatory_init(), if that is
5679 * even possible.
5680 */
Johannes Berg458f4f92012-12-06 15:47:38 +01005681 if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
Luis R. Rodriguezfe33eb32009-02-21 00:04:30 -05005682 return -EINPROGRESS;
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005683
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005684 if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
5685 user_reg_hint_type =
5686 nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
5687 else
5688 user_reg_hint_type = NL80211_USER_REG_HINT_USER;
5689
5690 switch (user_reg_hint_type) {
5691 case NL80211_USER_REG_HINT_USER:
5692 case NL80211_USER_REG_HINT_CELL_BASE:
Ilan Peer52616f22014-02-25 16:26:00 +02005693 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
5694 return -EINVAL;
5695
5696 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
5697 return regulatory_hint_user(data, user_reg_hint_type);
5698 case NL80211_USER_REG_HINT_INDOOR:
Ilan peer05050752015-03-04 00:32:06 -05005699 if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
5700 owner_nlportid = info->snd_portid;
5701 is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
5702 } else {
5703 owner_nlportid = 0;
5704 is_indoor = true;
5705 }
5706
5707 return regulatory_hint_indoor(is_indoor, owner_nlportid);
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005708 default:
5709 return -EINVAL;
5710 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005711}
5712
Johannes Berg1ea4ff32017-09-13 16:07:22 +02005713static int nl80211_reload_regdb(struct sk_buff *skb, struct genl_info *info)
5714{
5715 return reg_reload_regdb();
5716}
5717
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005718static int nl80211_get_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01005719 struct genl_info *info)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005720{
Johannes Berg4c476992010-10-04 21:36:35 +02005721 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02005722 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01005723 struct wireless_dev *wdev = dev->ieee80211_ptr;
5724 struct mesh_config cur_params;
5725 int err = 0;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005726 void *hdr;
5727 struct nlattr *pinfoattr;
5728 struct sk_buff *msg;
5729
Johannes Berg29cbe682010-12-03 09:20:44 +01005730 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
5731 return -EOPNOTSUPP;
5732
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005733 if (!rdev->ops->get_mesh_config)
Johannes Berg4c476992010-10-04 21:36:35 +02005734 return -EOPNOTSUPP;
Jouni Malinenf3f92582009-03-20 17:57:36 +02005735
Johannes Berg29cbe682010-12-03 09:20:44 +01005736 wdev_lock(wdev);
5737 /* If not connected, get default parameters */
5738 if (!wdev->mesh_id_len)
5739 memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
5740 else
Hila Gonene35e4d22012-06-27 17:19:42 +03005741 err = rdev_get_mesh_config(rdev, dev, &cur_params);
Johannes Berg29cbe682010-12-03 09:20:44 +01005742 wdev_unlock(wdev);
5743
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005744 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005745 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005746
5747 /* Draw up a netlink message to send back */
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005748 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02005749 if (!msg)
5750 return -ENOMEM;
Eric W. Biederman15e47302012-09-07 20:12:54 +00005751 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005752 NL80211_CMD_GET_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005753 if (!hdr)
Julia Lawallefe1cf02011-01-28 15:17:11 +01005754 goto out;
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005755 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005756 if (!pinfoattr)
5757 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005758 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5759 nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
5760 cur_params.dot11MeshRetryTimeout) ||
5761 nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
5762 cur_params.dot11MeshConfirmTimeout) ||
5763 nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
5764 cur_params.dot11MeshHoldingTimeout) ||
5765 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
5766 cur_params.dot11MeshMaxPeerLinks) ||
5767 nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
5768 cur_params.dot11MeshMaxRetries) ||
5769 nla_put_u8(msg, NL80211_MESHCONF_TTL,
5770 cur_params.dot11MeshTTL) ||
5771 nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
5772 cur_params.element_ttl) ||
5773 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
5774 cur_params.auto_open_plinks) ||
John W. Linville7eab0f62012-04-12 14:25:14 -04005775 nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
5776 cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04005777 nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
5778 cur_params.dot11MeshHWMPmaxPREQretries) ||
5779 nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
5780 cur_params.path_refresh_time) ||
5781 nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
5782 cur_params.min_discovery_timeout) ||
5783 nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
5784 cur_params.dot11MeshHWMPactivePathTimeout) ||
5785 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
5786 cur_params.dot11MeshHWMPpreqMinInterval) ||
5787 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
5788 cur_params.dot11MeshHWMPperrMinInterval) ||
5789 nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
5790 cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
5791 nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
5792 cur_params.dot11MeshHWMPRootMode) ||
5793 nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
5794 cur_params.dot11MeshHWMPRannInterval) ||
5795 nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
5796 cur_params.dot11MeshGateAnnouncementProtocol) ||
5797 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
5798 cur_params.dot11MeshForwarding) ||
Masashi Honma335d5342017-03-16 10:57:17 +09005799 nla_put_s32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
Ashok Nagarajan70c33ea2012-04-30 14:20:32 -07005800 cur_params.rssi_threshold) ||
5801 nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005802 cur_params.ht_opmode) ||
5803 nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
5804 cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
5805 nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005806 cur_params.dot11MeshHWMProotInterval) ||
5807 nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005808 cur_params.dot11MeshHWMPconfirmationInterval) ||
5809 nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
5810 cur_params.power_mode) ||
5811 nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005812 cur_params.dot11MeshAwakeWindowDuration) ||
5813 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
5814 cur_params.plink_timeout))
David S. Miller9360ffd2012-03-29 04:41:26 -04005815 goto nla_put_failure;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005816 nla_nest_end(msg, pinfoattr);
5817 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02005818 return genlmsg_reply(msg, info);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005819
Johannes Berg3b858752009-03-12 09:55:09 +01005820 nla_put_failure:
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005821 genlmsg_cancel(msg, hdr);
Julia Lawallefe1cf02011-01-28 15:17:11 +01005822 out:
Yuri Ershovd080e272010-06-29 15:08:07 +04005823 nlmsg_free(msg);
Johannes Berg4c476992010-10-04 21:36:35 +02005824 return -ENOBUFS;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005825}
5826
Alexey Dobriyanb54452b2010-02-18 08:14:31 +00005827static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005828 [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
5829 [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
5830 [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
5831 [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
5832 [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
5833 [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
Javier Cardona45904f22010-12-03 09:20:40 +01005834 [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005835 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
Javier Cardonad299a1f2012-03-31 11:31:33 -07005836 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005837 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
5838 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
5839 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
5840 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
5841 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
Thomas Pedersendca7e942011-11-24 17:15:24 -08005842 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005843 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
Javier Cardona699403d2011-08-09 16:45:09 -07005844 [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
Javier Cardona0507e152011-08-09 16:45:10 -07005845 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
Javier Cardona16dd7262011-08-09 16:45:11 -07005846 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
Chun-Yeow Yeoh94f90652012-01-21 01:02:16 +08005847 [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005848 [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
5849 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005850 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
5851 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005852 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005853 [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
5854 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005855 [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005856};
5857
Javier Cardonac80d5452010-12-16 17:37:49 -08005858static const struct nla_policy
5859 nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
Javier Cardonad299a1f2012-03-31 11:31:33 -07005860 [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
Javier Cardonac80d5452010-12-16 17:37:49 -08005861 [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
5862 [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
Javier Cardona15d5dda2011-04-07 15:08:28 -07005863 [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
Colleen Twitty6e16d902013-05-08 11:45:59 -07005864 [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 },
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08005865 [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
Javier Cardona581a8b02011-04-07 15:08:27 -07005866 [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005867 .len = IEEE80211_MAX_DATA_LEN },
Javier Cardonab130e5c2011-05-03 16:57:07 -07005868 [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
Javier Cardonac80d5452010-12-16 17:37:49 -08005869};
5870
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005871static int nl80211_check_bool(const struct nlattr *nla, u8 min, u8 max, bool *out)
5872{
5873 u8 val = nla_get_u8(nla);
5874 if (val < min || val > max)
5875 return -EINVAL;
5876 *out = val;
5877 return 0;
5878}
5879
5880static int nl80211_check_u8(const struct nlattr *nla, u8 min, u8 max, u8 *out)
5881{
5882 u8 val = nla_get_u8(nla);
5883 if (val < min || val > max)
5884 return -EINVAL;
5885 *out = val;
5886 return 0;
5887}
5888
5889static int nl80211_check_u16(const struct nlattr *nla, u16 min, u16 max, u16 *out)
5890{
5891 u16 val = nla_get_u16(nla);
5892 if (val < min || val > max)
5893 return -EINVAL;
5894 *out = val;
5895 return 0;
5896}
5897
5898static int nl80211_check_u32(const struct nlattr *nla, u32 min, u32 max, u32 *out)
5899{
5900 u32 val = nla_get_u32(nla);
5901 if (val < min || val > max)
5902 return -EINVAL;
5903 *out = val;
5904 return 0;
5905}
5906
5907static int nl80211_check_s32(const struct nlattr *nla, s32 min, s32 max, s32 *out)
5908{
5909 s32 val = nla_get_s32(nla);
5910 if (val < min || val > max)
5911 return -EINVAL;
5912 *out = val;
5913 return 0;
5914}
5915
Johannes Bergff9a71a2016-08-11 14:59:53 +02005916static int nl80211_check_power_mode(const struct nlattr *nla,
5917 enum nl80211_mesh_power_mode min,
5918 enum nl80211_mesh_power_mode max,
5919 enum nl80211_mesh_power_mode *out)
5920{
5921 u32 val = nla_get_u32(nla);
5922 if (val < min || val > max)
5923 return -EINVAL;
5924 *out = val;
5925 return 0;
5926}
5927
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005928static int nl80211_parse_mesh_config(struct genl_info *info,
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005929 struct mesh_config *cfg,
5930 u32 *mask_out)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005931{
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005932 struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005933 u32 mask = 0;
Masashi Honma97572352016-08-03 10:07:44 +09005934 u16 ht_opmode;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005935
Marco Porschea54fba2013-01-07 16:04:48 +01005936#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \
5937do { \
5938 if (tb[attr]) { \
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005939 if (fn(tb[attr], min, max, &cfg->param)) \
Marco Porschea54fba2013-01-07 16:04:48 +01005940 return -EINVAL; \
Marco Porschea54fba2013-01-07 16:04:48 +01005941 mask |= (1 << (attr - 1)); \
5942 } \
5943} while (0)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005944
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005945 if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005946 return -EINVAL;
5947 if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005948 info->attrs[NL80211_ATTR_MESH_CONFIG],
Johannes Bergfe521452017-04-12 14:34:08 +02005949 nl80211_meshconf_params_policy, info->extack))
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005950 return -EINVAL;
5951
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005952 /* This makes sure that there aren't more than 32 mesh config
5953 * parameters (otherwise our bitfield scheme would not work.) */
5954 BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
5955
5956 /* Fill in the params struct */
Marco Porschea54fba2013-01-07 16:04:48 +01005957 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005958 mask, NL80211_MESHCONF_RETRY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005959 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005960 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005961 mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005962 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005963 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005964 mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005965 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005966 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005967 mask, NL80211_MESHCONF_MAX_PEER_LINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005968 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005969 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005970 mask, NL80211_MESHCONF_MAX_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005971 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005972 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005973 mask, NL80211_MESHCONF_TTL, nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005974 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005975 mask, NL80211_MESHCONF_ELEMENT_TTL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005976 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005977 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005978 mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005979 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01005980 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
5981 1, 255, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005982 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005983 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005984 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005985 mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005986 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005987 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005988 mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005989 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005990 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005991 mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005992 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005993 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
5994 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005995 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005996 nl80211_check_u32);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005997 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01005998 1, 65535, mask,
5999 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006000 nl80211_check_u16);
Thomas Pedersendca7e942011-11-24 17:15:24 -08006001 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01006002 1, 65535, mask,
6003 NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006004 nl80211_check_u16);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006005 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01006006 dot11MeshHWMPnetDiameterTraversalTime,
6007 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006008 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006009 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01006010 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4,
6011 mask, NL80211_MESHCONF_HWMP_ROOTMODE,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006012 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01006013 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, 1, 65535,
6014 mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006015 nl80211_check_u16);
Rui Paulo63c57232009-11-09 23:46:57 +00006016 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01006017 dot11MeshGateAnnouncementProtocol, 0, 1,
6018 mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006019 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01006020 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006021 mask, NL80211_MESHCONF_FORWARDING,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006022 nl80211_check_bool);
Chun-Yeow Yeoh83374fe2013-07-11 18:24:03 +08006023 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08006024 mask, NL80211_MESHCONF_RSSI_THRESHOLD,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006025 nl80211_check_s32);
Masashi Honma97572352016-08-03 10:07:44 +09006026 /*
6027 * Check HT operation mode based on
6028 * IEEE 802.11 2012 8.4.2.59 HT Operation element.
6029 */
6030 if (tb[NL80211_MESHCONF_HT_OPMODE]) {
6031 ht_opmode = nla_get_u16(tb[NL80211_MESHCONF_HT_OPMODE]);
6032
6033 if (ht_opmode & ~(IEEE80211_HT_OP_MODE_PROTECTION |
6034 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
6035 IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
6036 return -EINVAL;
6037
6038 if ((ht_opmode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) &&
6039 (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
6040 return -EINVAL;
6041
6042 switch (ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION) {
6043 case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
6044 case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
6045 if (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT)
6046 return -EINVAL;
6047 break;
6048 case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
6049 case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
6050 if (!(ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
6051 return -EINVAL;
6052 break;
6053 }
6054 cfg->ht_opmode = ht_opmode;
Masashi Honmafd551ba2017-01-26 08:56:13 +09006055 mask |= (1 << (NL80211_MESHCONF_HT_OPMODE - 1));
Masashi Honma97572352016-08-03 10:07:44 +09006056 }
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08006057 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
Marco Porschea54fba2013-01-07 16:04:48 +01006058 1, 65535, mask,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08006059 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006060 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01006061 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08006062 mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006063 nl80211_check_u16);
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08006064 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01006065 dot11MeshHWMPconfirmationInterval,
6066 1, 65535, mask,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08006067 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006068 nl80211_check_u16);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01006069 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode,
6070 NL80211_MESH_POWER_ACTIVE,
6071 NL80211_MESH_POWER_MAX,
6072 mask, NL80211_MESHCONF_POWER_MODE,
Johannes Bergff9a71a2016-08-11 14:59:53 +02006073 nl80211_check_power_mode);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01006074 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
6075 0, 65535, mask,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006076 NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16);
Masashi Honma31f909a2015-02-24 22:42:16 +09006077 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07006078 mask, NL80211_MESHCONF_PLINK_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006079 nl80211_check_u32);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006080 if (mask_out)
6081 *mask_out = mask;
Javier Cardonac80d5452010-12-16 17:37:49 -08006082
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006083 return 0;
6084
6085#undef FILL_IN_MESH_PARAM_IF_SET
6086}
6087
Javier Cardonac80d5452010-12-16 17:37:49 -08006088static int nl80211_parse_mesh_setup(struct genl_info *info,
6089 struct mesh_setup *setup)
6090{
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006091 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Javier Cardonac80d5452010-12-16 17:37:49 -08006092 struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
6093
6094 if (!info->attrs[NL80211_ATTR_MESH_SETUP])
6095 return -EINVAL;
6096 if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX,
6097 info->attrs[NL80211_ATTR_MESH_SETUP],
Johannes Bergfe521452017-04-12 14:34:08 +02006098 nl80211_mesh_setup_params_policy, info->extack))
Javier Cardonac80d5452010-12-16 17:37:49 -08006099 return -EINVAL;
6100
Javier Cardonad299a1f2012-03-31 11:31:33 -07006101 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
6102 setup->sync_method =
6103 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
6104 IEEE80211_SYNC_METHOD_VENDOR :
6105 IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
6106
Javier Cardonac80d5452010-12-16 17:37:49 -08006107 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
6108 setup->path_sel_proto =
6109 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
6110 IEEE80211_PATH_PROTOCOL_VENDOR :
6111 IEEE80211_PATH_PROTOCOL_HWMP;
6112
6113 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
6114 setup->path_metric =
6115 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
6116 IEEE80211_PATH_METRIC_VENDOR :
6117 IEEE80211_PATH_METRIC_AIRTIME;
6118
Javier Cardona581a8b02011-04-07 15:08:27 -07006119 if (tb[NL80211_MESH_SETUP_IE]) {
Javier Cardonac80d5452010-12-16 17:37:49 -08006120 struct nlattr *ieattr =
Javier Cardona581a8b02011-04-07 15:08:27 -07006121 tb[NL80211_MESH_SETUP_IE];
Javier Cardonac80d5452010-12-16 17:37:49 -08006122 if (!is_valid_ie_attr(ieattr))
6123 return -EINVAL;
Javier Cardona581a8b02011-04-07 15:08:27 -07006124 setup->ie = nla_data(ieattr);
6125 setup->ie_len = nla_len(ieattr);
Javier Cardonac80d5452010-12-16 17:37:49 -08006126 }
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006127 if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
6128 !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
6129 return -EINVAL;
6130 setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
Javier Cardonab130e5c2011-05-03 16:57:07 -07006131 setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
6132 setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006133 if (setup->is_secure)
6134 setup->user_mpm = true;
Javier Cardonac80d5452010-12-16 17:37:49 -08006135
Colleen Twitty6e16d902013-05-08 11:45:59 -07006136 if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) {
6137 if (!setup->user_mpm)
6138 return -EINVAL;
6139 setup->auth_id =
6140 nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]);
6141 }
6142
Javier Cardonac80d5452010-12-16 17:37:49 -08006143 return 0;
6144}
6145
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006146static int nl80211_update_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01006147 struct genl_info *info)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006148{
6149 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6150 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01006151 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006152 struct mesh_config cfg;
6153 u32 mask;
6154 int err;
6155
Johannes Berg29cbe682010-12-03 09:20:44 +01006156 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
6157 return -EOPNOTSUPP;
6158
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006159 if (!rdev->ops->update_mesh_config)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006160 return -EOPNOTSUPP;
6161
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006162 err = nl80211_parse_mesh_config(info, &cfg, &mask);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006163 if (err)
6164 return err;
6165
Johannes Berg29cbe682010-12-03 09:20:44 +01006166 wdev_lock(wdev);
6167 if (!wdev->mesh_id_len)
6168 err = -ENOLINK;
6169
6170 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03006171 err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01006172
6173 wdev_unlock(wdev);
6174
6175 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006176}
6177
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006178static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
6179 struct sk_buff *msg)
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006180{
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006181 struct nlattr *nl_reg_rules;
6182 unsigned int i;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006183
Johannes Berg458f4f92012-12-06 15:47:38 +01006184 if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
6185 (regdom->dfs_region &&
6186 nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006187 goto nla_put_failure;
Johannes Berg458f4f92012-12-06 15:47:38 +01006188
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006189 nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
6190 if (!nl_reg_rules)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006191 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006192
Johannes Berg458f4f92012-12-06 15:47:38 +01006193 for (i = 0; i < regdom->n_reg_rules; i++) {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006194 struct nlattr *nl_reg_rule;
6195 const struct ieee80211_reg_rule *reg_rule;
6196 const struct ieee80211_freq_range *freq_range;
6197 const struct ieee80211_power_rule *power_rule;
Janusz Dziedzic97524822014-01-30 09:52:20 +01006198 unsigned int max_bandwidth_khz;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006199
Johannes Berg458f4f92012-12-06 15:47:38 +01006200 reg_rule = &regdom->reg_rules[i];
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006201 freq_range = &reg_rule->freq_range;
6202 power_rule = &reg_rule->power_rule;
6203
6204 nl_reg_rule = nla_nest_start(msg, i);
6205 if (!nl_reg_rule)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006206 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006207
Janusz Dziedzic97524822014-01-30 09:52:20 +01006208 max_bandwidth_khz = freq_range->max_bandwidth_khz;
6209 if (!max_bandwidth_khz)
6210 max_bandwidth_khz = reg_get_max_bandwidth(regdom,
6211 reg_rule);
6212
David S. Miller9360ffd2012-03-29 04:41:26 -04006213 if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
6214 reg_rule->flags) ||
6215 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
6216 freq_range->start_freq_khz) ||
6217 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
6218 freq_range->end_freq_khz) ||
6219 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
Janusz Dziedzic97524822014-01-30 09:52:20 +01006220 max_bandwidth_khz) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04006221 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
6222 power_rule->max_antenna_gain) ||
6223 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
Janusz Dziedzic089027e2014-02-21 19:46:12 +01006224 power_rule->max_eirp) ||
6225 nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
6226 reg_rule->dfs_cac_ms))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006227 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006228
6229 nla_nest_end(msg, nl_reg_rule);
6230 }
6231
6232 nla_nest_end(msg, nl_reg_rules);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006233 return 0;
6234
6235nla_put_failure:
6236 return -EMSGSIZE;
6237}
6238
6239static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
6240{
6241 const struct ieee80211_regdomain *regdom = NULL;
6242 struct cfg80211_registered_device *rdev;
6243 struct wiphy *wiphy = NULL;
6244 struct sk_buff *msg;
6245 void *hdr;
6246
6247 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6248 if (!msg)
6249 return -ENOBUFS;
6250
6251 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
6252 NL80211_CMD_GET_REG);
6253 if (!hdr)
6254 goto put_failure;
6255
6256 if (info->attrs[NL80211_ATTR_WIPHY]) {
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006257 bool self_managed;
6258
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006259 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
6260 if (IS_ERR(rdev)) {
6261 nlmsg_free(msg);
6262 return PTR_ERR(rdev);
6263 }
6264
6265 wiphy = &rdev->wiphy;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006266 self_managed = wiphy->regulatory_flags &
6267 REGULATORY_WIPHY_SELF_MANAGED;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006268 regdom = get_wiphy_regdom(wiphy);
6269
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006270 /* a self-managed-reg device must have a private regdom */
6271 if (WARN_ON(!regdom && self_managed)) {
6272 nlmsg_free(msg);
6273 return -EINVAL;
6274 }
6275
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006276 if (regdom &&
6277 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6278 goto nla_put_failure;
6279 }
6280
6281 if (!wiphy && reg_last_request_cell_base() &&
6282 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6283 NL80211_USER_REG_HINT_CELL_BASE))
6284 goto nla_put_failure;
6285
6286 rcu_read_lock();
6287
6288 if (!regdom)
6289 regdom = rcu_dereference(cfg80211_regdomain);
6290
6291 if (nl80211_put_regdom(regdom, msg))
6292 goto nla_put_failure_rcu;
6293
6294 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006295
6296 genlmsg_end(msg, hdr);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006297 return genlmsg_reply(msg, info);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006298
Johannes Berg458f4f92012-12-06 15:47:38 +01006299nla_put_failure_rcu:
6300 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006301nla_put_failure:
6302 genlmsg_cancel(msg, hdr);
Julia Lawallefe1cf02011-01-28 15:17:11 +01006303put_failure:
Yuri Ershovd080e272010-06-29 15:08:07 +04006304 nlmsg_free(msg);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006305 return -EMSGSIZE;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006306}
6307
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006308static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
6309 u32 seq, int flags, struct wiphy *wiphy,
6310 const struct ieee80211_regdomain *regdom)
6311{
6312 void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
6313 NL80211_CMD_GET_REG);
6314
6315 if (!hdr)
6316 return -1;
6317
Michal Kubecek0a833c22017-11-15 13:09:32 +01006318 genl_dump_check_consistent(cb, hdr);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006319
6320 if (nl80211_put_regdom(regdom, msg))
6321 goto nla_put_failure;
6322
6323 if (!wiphy && reg_last_request_cell_base() &&
6324 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6325 NL80211_USER_REG_HINT_CELL_BASE))
6326 goto nla_put_failure;
6327
6328 if (wiphy &&
6329 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6330 goto nla_put_failure;
6331
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006332 if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
6333 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
6334 goto nla_put_failure;
6335
Johannes Berg053c0952015-01-16 22:09:00 +01006336 genlmsg_end(msg, hdr);
6337 return 0;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006338
6339nla_put_failure:
6340 genlmsg_cancel(msg, hdr);
6341 return -EMSGSIZE;
6342}
6343
6344static int nl80211_get_reg_dump(struct sk_buff *skb,
6345 struct netlink_callback *cb)
6346{
6347 const struct ieee80211_regdomain *regdom = NULL;
6348 struct cfg80211_registered_device *rdev;
6349 int err, reg_idx, start = cb->args[2];
6350
6351 rtnl_lock();
6352
6353 if (cfg80211_regdomain && start == 0) {
6354 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6355 NLM_F_MULTI, NULL,
6356 rtnl_dereference(cfg80211_regdomain));
6357 if (err < 0)
6358 goto out_err;
6359 }
6360
6361 /* the global regdom is idx 0 */
6362 reg_idx = 1;
6363 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
6364 regdom = get_wiphy_regdom(&rdev->wiphy);
6365 if (!regdom)
6366 continue;
6367
6368 if (++reg_idx <= start)
6369 continue;
6370
6371 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6372 NLM_F_MULTI, &rdev->wiphy, regdom);
6373 if (err < 0) {
6374 reg_idx--;
6375 break;
6376 }
6377 }
6378
6379 cb->args[2] = reg_idx;
6380 err = skb->len;
6381out_err:
6382 rtnl_unlock();
6383 return err;
6384}
6385
Johannes Bergb6863032015-10-15 09:25:18 +02006386#ifdef CONFIG_CFG80211_CRDA_SUPPORT
6387static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
6388 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
6389 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
6390 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
6391 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
6392 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
6393 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
6394 [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
6395};
6396
6397static int parse_reg_rule(struct nlattr *tb[],
6398 struct ieee80211_reg_rule *reg_rule)
6399{
6400 struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
6401 struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
6402
6403 if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
6404 return -EINVAL;
6405 if (!tb[NL80211_ATTR_FREQ_RANGE_START])
6406 return -EINVAL;
6407 if (!tb[NL80211_ATTR_FREQ_RANGE_END])
6408 return -EINVAL;
6409 if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
6410 return -EINVAL;
6411 if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
6412 return -EINVAL;
6413
6414 reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
6415
6416 freq_range->start_freq_khz =
6417 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
6418 freq_range->end_freq_khz =
6419 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
6420 freq_range->max_bandwidth_khz =
6421 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
6422
6423 power_rule->max_eirp =
6424 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
6425
6426 if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
6427 power_rule->max_antenna_gain =
6428 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
6429
6430 if (tb[NL80211_ATTR_DFS_CAC_TIME])
6431 reg_rule->dfs_cac_ms =
6432 nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
6433
6434 return 0;
6435}
6436
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006437static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
6438{
6439 struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
6440 struct nlattr *nl_reg_rule;
Johannes Bergea372c52014-11-28 14:54:31 +01006441 char *alpha2;
6442 int rem_reg_rules, r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006443 u32 num_rules = 0, rule_idx = 0, size_of_regd;
Luis R. Rodriguez4c7d3982013-11-13 18:54:02 +01006444 enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
Johannes Bergea372c52014-11-28 14:54:31 +01006445 struct ieee80211_regdomain *rd;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006446
6447 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
6448 return -EINVAL;
6449
6450 if (!info->attrs[NL80211_ATTR_REG_RULES])
6451 return -EINVAL;
6452
6453 alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
6454
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006455 if (info->attrs[NL80211_ATTR_DFS_REGION])
6456 dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
6457
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006458 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006459 rem_reg_rules) {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006460 num_rules++;
6461 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
Luis R. Rodriguez4776c6e2009-05-13 17:04:39 -04006462 return -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006463 }
6464
Luis R. Rodrigueze4387682013-11-05 09:18:01 -08006465 if (!reg_is_valid_request(alpha2))
6466 return -EINVAL;
6467
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006468 size_of_regd = sizeof(struct ieee80211_regdomain) +
Johannes Berg1a919312012-12-03 17:21:11 +01006469 num_rules * sizeof(struct ieee80211_reg_rule);
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006470
6471 rd = kzalloc(size_of_regd, GFP_KERNEL);
Johannes Berg6913b492012-12-04 00:48:59 +01006472 if (!rd)
6473 return -ENOMEM;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006474
6475 rd->n_reg_rules = num_rules;
6476 rd->alpha2[0] = alpha2[0];
6477 rd->alpha2[1] = alpha2[1];
6478
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006479 /*
6480 * Disable DFS master mode if the DFS region was
6481 * not supported or known on this kernel.
6482 */
6483 if (reg_supported_dfs_region(dfs_region))
6484 rd->dfs_region = dfs_region;
6485
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006486 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006487 rem_reg_rules) {
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006488 r = nla_parse_nested(tb, NL80211_REG_RULE_ATTR_MAX,
Johannes Bergfe521452017-04-12 14:34:08 +02006489 nl_reg_rule, reg_rule_policy,
6490 info->extack);
Johannes Bergae811e22014-01-24 10:17:47 +01006491 if (r)
6492 goto bad_reg;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006493 r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
6494 if (r)
6495 goto bad_reg;
6496
6497 rule_idx++;
6498
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006499 if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
6500 r = -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006501 goto bad_reg;
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006502 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006503 }
6504
Johannes Berg06627992016-06-09 10:40:09 +02006505 /* set_regdom takes ownership of rd */
6506 return set_regdom(rd, REGD_SOURCE_CRDA);
Johannes Bergd2372b32008-10-24 20:32:20 +02006507 bad_reg:
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006508 kfree(rd);
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006509 return r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006510}
Johannes Bergb6863032015-10-15 09:25:18 +02006511#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006512
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006513static int validate_scan_freqs(struct nlattr *freqs)
6514{
6515 struct nlattr *attr1, *attr2;
6516 int n_channels = 0, tmp1, tmp2;
6517
Srinivas Dasarid7f13f72017-07-07 01:43:42 +03006518 nla_for_each_nested(attr1, freqs, tmp1)
6519 if (nla_len(attr1) != sizeof(u32))
6520 return 0;
6521
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006522 nla_for_each_nested(attr1, freqs, tmp1) {
6523 n_channels++;
6524 /*
6525 * Some hardware has a limited channel list for
6526 * scanning, and it is pretty much nonsensical
6527 * to scan for a channel twice, so disallow that
6528 * and don't require drivers to check that the
6529 * channel list they get isn't longer than what
6530 * they can scan, as long as they can scan all
6531 * the channels they registered at once.
6532 */
6533 nla_for_each_nested(attr2, freqs, tmp2)
6534 if (attr1 != attr2 &&
6535 nla_get_u32(attr1) == nla_get_u32(attr2))
6536 return 0;
6537 }
6538
6539 return n_channels;
6540}
6541
Johannes Berg57fbcce2016-04-12 15:56:15 +02006542static bool is_band_valid(struct wiphy *wiphy, enum nl80211_band b)
Arend van Spriel38de03d2016-03-02 20:37:18 +01006543{
Johannes Berg57fbcce2016-04-12 15:56:15 +02006544 return b < NUM_NL80211_BANDS && wiphy->bands[b];
Arend van Spriel38de03d2016-03-02 20:37:18 +01006545}
6546
6547static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
6548 struct cfg80211_bss_selection *bss_select)
6549{
6550 struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
6551 struct nlattr *nest;
6552 int err;
6553 bool found = false;
6554 int i;
6555
6556 /* only process one nested attribute */
6557 nest = nla_data(nla);
6558 if (!nla_ok(nest, nla_len(nest)))
6559 return -EINVAL;
6560
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006561 err = nla_parse_nested(attr, NL80211_BSS_SELECT_ATTR_MAX, nest,
Johannes Bergfceb6432017-04-12 14:34:07 +02006562 nl80211_bss_select_policy, NULL);
Arend van Spriel38de03d2016-03-02 20:37:18 +01006563 if (err)
6564 return err;
6565
6566 /* only one attribute may be given */
6567 for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
6568 if (attr[i]) {
6569 if (found)
6570 return -EINVAL;
6571 found = true;
6572 }
6573 }
6574
6575 bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
6576
6577 if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
6578 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
6579
6580 if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
6581 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
6582 bss_select->param.band_pref =
6583 nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
6584 if (!is_band_valid(wiphy, bss_select->param.band_pref))
6585 return -EINVAL;
6586 }
6587
6588 if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
6589 struct nl80211_bss_select_rssi_adjust *adj_param;
6590
6591 adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
6592 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
6593 bss_select->param.adjust.band = adj_param->band;
6594 bss_select->param.adjust.delta = adj_param->delta;
6595 if (!is_band_valid(wiphy, bss_select->param.adjust.band))
6596 return -EINVAL;
6597 }
6598
6599 /* user-space did not provide behaviour attribute */
6600 if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
6601 return -EINVAL;
6602
6603 if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
6604 return -EINVAL;
6605
6606 return 0;
6607}
6608
Johannes Bergad2b26a2014-06-12 21:39:05 +02006609static int nl80211_parse_random_mac(struct nlattr **attrs,
6610 u8 *mac_addr, u8 *mac_addr_mask)
6611{
6612 int i;
6613
6614 if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
Joe Perchesd2beae12015-03-02 19:54:58 -08006615 eth_zero_addr(mac_addr);
6616 eth_zero_addr(mac_addr_mask);
Johannes Bergad2b26a2014-06-12 21:39:05 +02006617 mac_addr[0] = 0x2;
6618 mac_addr_mask[0] = 0x3;
6619
6620 return 0;
6621 }
6622
6623 /* need both or none */
6624 if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
6625 return -EINVAL;
6626
6627 memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
6628 memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
6629
6630 /* don't allow or configure an mcast address */
6631 if (!is_multicast_ether_addr(mac_addr_mask) ||
6632 is_multicast_ether_addr(mac_addr))
6633 return -EINVAL;
6634
6635 /*
6636 * allow users to pass a MAC address that has bits set outside
6637 * of the mask, but don't bother drivers with having to deal
6638 * with such bits
6639 */
6640 for (i = 0; i < ETH_ALEN; i++)
6641 mac_addr[i] &= mac_addr_mask[i];
6642
6643 return 0;
6644}
6645
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05306646static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
6647{
6648 ASSERT_WDEV_LOCK(wdev);
6649
6650 if (!cfg80211_beaconing_iface_active(wdev))
6651 return true;
6652
6653 if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
6654 return true;
6655
6656 return regulatory_pre_cac_allowed(wdev->wiphy);
6657}
6658
Roee Zamir2d23d072017-08-06 11:38:22 +03006659static int
6660nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
6661 void *request, struct nlattr **attrs,
6662 bool is_sched_scan)
6663{
6664 u8 *mac_addr, *mac_addr_mask;
6665 u32 *flags;
6666 enum nl80211_feature_flags randomness_flag;
6667
6668 if (!attrs[NL80211_ATTR_SCAN_FLAGS])
6669 return 0;
6670
6671 if (is_sched_scan) {
6672 struct cfg80211_sched_scan_request *req = request;
6673
6674 randomness_flag = wdev ?
6675 NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR :
6676 NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6677 flags = &req->flags;
6678 mac_addr = req->mac_addr;
6679 mac_addr_mask = req->mac_addr_mask;
6680 } else {
6681 struct cfg80211_scan_request *req = request;
6682
6683 randomness_flag = NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
6684 flags = &req->flags;
6685 mac_addr = req->mac_addr;
6686 mac_addr_mask = req->mac_addr_mask;
6687 }
6688
6689 *flags = nla_get_u32(attrs[NL80211_ATTR_SCAN_FLAGS]);
6690
6691 if ((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
6692 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN))
6693 return -EOPNOTSUPP;
6694
6695 if (*flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
6696 int err;
6697
6698 if (!(wiphy->features & randomness_flag) ||
6699 (wdev && wdev->current_bss))
6700 return -EOPNOTSUPP;
6701
6702 err = nl80211_parse_random_mac(attrs, mac_addr, mac_addr_mask);
6703 if (err)
6704 return err;
6705 }
6706
6707 if ((*flags & NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME) &&
6708 !wiphy_ext_feature_isset(wiphy,
6709 NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME))
6710 return -EOPNOTSUPP;
6711
6712 if ((*flags & NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP) &&
6713 !wiphy_ext_feature_isset(wiphy,
6714 NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP))
6715 return -EOPNOTSUPP;
6716
6717 if ((*flags & NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) &&
6718 !wiphy_ext_feature_isset(wiphy,
6719 NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION))
6720 return -EOPNOTSUPP;
6721
6722 if ((*flags & NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE) &&
6723 !wiphy_ext_feature_isset(wiphy,
6724 NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE))
6725 return -EOPNOTSUPP;
6726
6727 return 0;
6728}
6729
Johannes Berg2a519312009-02-10 21:25:55 +01006730static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
6731{
Johannes Berg4c476992010-10-04 21:36:35 +02006732 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfd014282012-06-18 19:17:03 +02006733 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2a519312009-02-10 21:25:55 +01006734 struct cfg80211_scan_request *request;
Johannes Berg2a519312009-02-10 21:25:55 +01006735 struct nlattr *attr;
6736 struct wiphy *wiphy;
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006737 int err, tmp, n_ssids = 0, n_channels, i;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006738 size_t ie_len;
Johannes Berg2a519312009-02-10 21:25:55 +01006739
Johannes Bergf4a11bb2009-03-27 12:40:28 +01006740 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
6741 return -EINVAL;
6742
Johannes Berg79c97e92009-07-07 03:56:12 +02006743 wiphy = &rdev->wiphy;
Johannes Berg2a519312009-02-10 21:25:55 +01006744
Ayala Bekercb3b7d82016-09-20 17:31:13 +03006745 if (wdev->iftype == NL80211_IFTYPE_NAN)
6746 return -EOPNOTSUPP;
6747
Johannes Berg4c476992010-10-04 21:36:35 +02006748 if (!rdev->ops->scan)
6749 return -EOPNOTSUPP;
Johannes Berg2a519312009-02-10 21:25:55 +01006750
Johannes Bergf9d15d12014-01-22 11:14:19 +02006751 if (rdev->scan_req || rdev->scan_msg) {
Johannes Bergf9f47522013-03-19 15:04:07 +01006752 err = -EBUSY;
6753 goto unlock;
6754 }
Johannes Berg2a519312009-02-10 21:25:55 +01006755
6756 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006757 n_channels = validate_scan_freqs(
6758 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Johannes Bergf9f47522013-03-19 15:04:07 +01006759 if (!n_channels) {
6760 err = -EINVAL;
6761 goto unlock;
6762 }
Johannes Berg2a519312009-02-10 21:25:55 +01006763 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02006764 n_channels = ieee80211_get_num_supported_channels(wiphy);
Johannes Berg2a519312009-02-10 21:25:55 +01006765 }
6766
6767 if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
6768 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
6769 n_ssids++;
6770
Johannes Bergf9f47522013-03-19 15:04:07 +01006771 if (n_ssids > wiphy->max_scan_ssids) {
6772 err = -EINVAL;
6773 goto unlock;
6774 }
Johannes Berg2a519312009-02-10 21:25:55 +01006775
Jouni Malinen70692ad2009-02-16 19:39:13 +02006776 if (info->attrs[NL80211_ATTR_IE])
6777 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
6778 else
6779 ie_len = 0;
6780
Johannes Bergf9f47522013-03-19 15:04:07 +01006781 if (ie_len > wiphy->max_scan_ie_len) {
6782 err = -EINVAL;
6783 goto unlock;
6784 }
Johannes Berg18a83652009-03-31 12:12:05 +02006785
Johannes Berg2a519312009-02-10 21:25:55 +01006786 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03006787 + sizeof(*request->ssids) * n_ssids
6788 + sizeof(*request->channels) * n_channels
Jouni Malinen70692ad2009-02-16 19:39:13 +02006789 + ie_len, GFP_KERNEL);
Johannes Bergf9f47522013-03-19 15:04:07 +01006790 if (!request) {
6791 err = -ENOMEM;
6792 goto unlock;
6793 }
Johannes Berg2a519312009-02-10 21:25:55 +01006794
Johannes Berg2a519312009-02-10 21:25:55 +01006795 if (n_ssids)
Johannes Berg5ba63532009-08-07 17:54:07 +02006796 request->ssids = (void *)&request->channels[n_channels];
Johannes Berg2a519312009-02-10 21:25:55 +01006797 request->n_ssids = n_ssids;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006798 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01006799 if (n_ssids)
Jouni Malinen70692ad2009-02-16 19:39:13 +02006800 request->ie = (void *)(request->ssids + n_ssids);
6801 else
6802 request->ie = (void *)(request->channels + n_channels);
6803 }
Johannes Berg2a519312009-02-10 21:25:55 +01006804
Johannes Berg584991d2009-11-02 13:32:03 +01006805 i = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01006806 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
6807 /* user specified, bail out if channel not found */
Johannes Berg2a519312009-02-10 21:25:55 +01006808 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
Johannes Berg584991d2009-11-02 13:32:03 +01006809 struct ieee80211_channel *chan;
6810
6811 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
6812
6813 if (!chan) {
Johannes Berg2a519312009-02-10 21:25:55 +01006814 err = -EINVAL;
6815 goto out_free;
6816 }
Johannes Berg584991d2009-11-02 13:32:03 +01006817
6818 /* ignore disabled channels */
6819 if (chan->flags & IEEE80211_CHAN_DISABLED)
6820 continue;
6821
6822 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006823 i++;
6824 }
6825 } else {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006826 enum nl80211_band band;
Johannes Berg34850ab2011-07-18 18:08:35 +02006827
Johannes Berg2a519312009-02-10 21:25:55 +01006828 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006829 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Johannes Berg2a519312009-02-10 21:25:55 +01006830 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07006831
Johannes Berg2a519312009-02-10 21:25:55 +01006832 if (!wiphy->bands[band])
6833 continue;
6834 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
Johannes Berg584991d2009-11-02 13:32:03 +01006835 struct ieee80211_channel *chan;
6836
6837 chan = &wiphy->bands[band]->channels[j];
6838
6839 if (chan->flags & IEEE80211_CHAN_DISABLED)
6840 continue;
6841
6842 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006843 i++;
6844 }
6845 }
6846 }
6847
Johannes Berg584991d2009-11-02 13:32:03 +01006848 if (!i) {
6849 err = -EINVAL;
6850 goto out_free;
6851 }
6852
6853 request->n_channels = i;
6854
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05306855 wdev_lock(wdev);
6856 if (!cfg80211_off_channel_oper_allowed(wdev)) {
6857 struct ieee80211_channel *chan;
6858
6859 if (request->n_channels != 1) {
6860 wdev_unlock(wdev);
6861 err = -EBUSY;
6862 goto out_free;
6863 }
6864
6865 chan = request->channels[0];
6866 if (chan->center_freq != wdev->chandef.chan->center_freq) {
6867 wdev_unlock(wdev);
6868 err = -EBUSY;
6869 goto out_free;
6870 }
6871 }
6872 wdev_unlock(wdev);
6873
Johannes Berg2a519312009-02-10 21:25:55 +01006874 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01006875 if (n_ssids) {
Johannes Berg2a519312009-02-10 21:25:55 +01006876 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03006877 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Johannes Berg2a519312009-02-10 21:25:55 +01006878 err = -EINVAL;
6879 goto out_free;
6880 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03006881 request->ssids[i].ssid_len = nla_len(attr);
Johannes Berg2a519312009-02-10 21:25:55 +01006882 memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
Johannes Berg2a519312009-02-10 21:25:55 +01006883 i++;
6884 }
6885 }
6886
Jouni Malinen70692ad2009-02-16 19:39:13 +02006887 if (info->attrs[NL80211_ATTR_IE]) {
6888 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Johannes Bergde95a542009-04-01 11:58:36 +02006889 memcpy((void *)request->ie,
6890 nla_data(info->attrs[NL80211_ATTR_IE]),
Jouni Malinen70692ad2009-02-16 19:39:13 +02006891 request->ie_len);
6892 }
6893
Johannes Berg57fbcce2016-04-12 15:56:15 +02006894 for (i = 0; i < NUM_NL80211_BANDS; i++)
Johannes Berga401d2b2011-07-20 00:52:16 +02006895 if (wiphy->bands[i])
6896 request->rates[i] =
6897 (1 << wiphy->bands[i]->n_bitrates) - 1;
Johannes Berg34850ab2011-07-18 18:08:35 +02006898
6899 if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
6900 nla_for_each_nested(attr,
6901 info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
6902 tmp) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006903 enum nl80211_band band = nla_type(attr);
Johannes Berg34850ab2011-07-18 18:08:35 +02006904
Johannes Berg57fbcce2016-04-12 15:56:15 +02006905 if (band < 0 || band >= NUM_NL80211_BANDS) {
Johannes Berg34850ab2011-07-18 18:08:35 +02006906 err = -EINVAL;
6907 goto out_free;
6908 }
Felix Fietkau1b09cd82013-11-20 19:40:41 +01006909
6910 if (!wiphy->bands[band])
6911 continue;
6912
Johannes Berg34850ab2011-07-18 18:08:35 +02006913 err = ieee80211_get_ratemask(wiphy->bands[band],
6914 nla_data(attr),
6915 nla_len(attr),
6916 &request->rates[band]);
6917 if (err)
6918 goto out_free;
6919 }
6920 }
6921
Avraham Stern1d762502016-07-05 17:10:13 +03006922 if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
6923 if (!wiphy_ext_feature_isset(wiphy,
6924 NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
6925 err = -EOPNOTSUPP;
6926 goto out_free;
6927 }
6928
6929 request->duration =
6930 nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
6931 request->duration_mandatory =
6932 nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
6933 }
6934
Roee Zamir2d23d072017-08-06 11:38:22 +03006935 err = nl80211_check_scan_flags(wiphy, wdev, request, info->attrs,
6936 false);
6937 if (err)
6938 goto out_free;
Sam Lefflered4737712012-10-11 21:03:31 -07006939
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05306940 request->no_cck =
6941 nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
6942
Vamsi Krishna2fa436b2016-12-02 23:59:08 +02006943 /* Initial implementation used NL80211_ATTR_MAC to set the specific
6944 * BSSID to scan for. This was problematic because that same attribute
6945 * was already used for another purpose (local random MAC address). The
6946 * NL80211_ATTR_BSSID attribute was added to fix this. For backwards
6947 * compatibility with older userspace components, also use the
6948 * NL80211_ATTR_MAC value here if it can be determined to be used for
6949 * the specific BSSID use case instead of the random MAC address
6950 * (NL80211_ATTR_SCAN_FLAGS is used to enable random MAC address use).
6951 */
6952 if (info->attrs[NL80211_ATTR_BSSID])
6953 memcpy(request->bssid,
6954 nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
6955 else if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
6956 info->attrs[NL80211_ATTR_MAC])
Jouni Malinen818965d2016-02-26 22:12:47 +02006957 memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
6958 ETH_ALEN);
6959 else
6960 eth_broadcast_addr(request->bssid);
6961
Johannes Bergfd014282012-06-18 19:17:03 +02006962 request->wdev = wdev;
Johannes Berg79c97e92009-07-07 03:56:12 +02006963 request->wiphy = &rdev->wiphy;
Sam Leffler15d60302012-10-11 21:03:34 -07006964 request->scan_start = jiffies;
Johannes Berg2a519312009-02-10 21:25:55 +01006965
Johannes Berg79c97e92009-07-07 03:56:12 +02006966 rdev->scan_req = request;
Hila Gonene35e4d22012-06-27 17:19:42 +03006967 err = rdev_scan(rdev, request);
Johannes Berg2a519312009-02-10 21:25:55 +01006968
Johannes Berg463d0182009-07-14 00:33:35 +02006969 if (!err) {
Johannes Bergfd014282012-06-18 19:17:03 +02006970 nl80211_send_scan_start(rdev, wdev);
6971 if (wdev->netdev)
6972 dev_hold(wdev->netdev);
Johannes Berg4c476992010-10-04 21:36:35 +02006973 } else {
Johannes Berg2a519312009-02-10 21:25:55 +01006974 out_free:
Johannes Berg79c97e92009-07-07 03:56:12 +02006975 rdev->scan_req = NULL;
Johannes Berg2a519312009-02-10 21:25:55 +01006976 kfree(request);
6977 }
Johannes Berg3b858752009-03-12 09:55:09 +01006978
Johannes Bergf9f47522013-03-19 15:04:07 +01006979 unlock:
Johannes Berg2a519312009-02-10 21:25:55 +01006980 return err;
6981}
6982
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +05306983static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
6984{
6985 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6986 struct wireless_dev *wdev = info->user_ptr[1];
6987
6988 if (!rdev->ops->abort_scan)
6989 return -EOPNOTSUPP;
6990
6991 if (rdev->scan_msg)
6992 return 0;
6993
6994 if (!rdev->scan_req)
6995 return -ENOENT;
6996
6997 rdev_abort_scan(rdev, wdev);
6998 return 0;
6999}
7000
Avraham Stern3b06d272015-10-12 09:51:34 +03007001static int
7002nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
7003 struct cfg80211_sched_scan_request *request,
7004 struct nlattr **attrs)
7005{
7006 int tmp, err, i = 0;
7007 struct nlattr *attr;
7008
7009 if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
7010 u32 interval;
7011
7012 /*
7013 * If scan plans are not specified,
Arend Van Spriel5a88de52016-11-17 09:02:40 +00007014 * %NL80211_ATTR_SCHED_SCAN_INTERVAL will be specified. In this
Avraham Stern3b06d272015-10-12 09:51:34 +03007015 * case one scan plan will be set with the specified scan
7016 * interval and infinite number of iterations.
7017 */
Avraham Stern3b06d272015-10-12 09:51:34 +03007018 interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
7019 if (!interval)
7020 return -EINVAL;
7021
7022 request->scan_plans[0].interval =
7023 DIV_ROUND_UP(interval, MSEC_PER_SEC);
7024 if (!request->scan_plans[0].interval)
7025 return -EINVAL;
7026
7027 if (request->scan_plans[0].interval >
7028 wiphy->max_sched_scan_plan_interval)
7029 request->scan_plans[0].interval =
7030 wiphy->max_sched_scan_plan_interval;
7031
7032 return 0;
7033 }
7034
7035 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
7036 struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
7037
7038 if (WARN_ON(i >= n_plans))
7039 return -EINVAL;
7040
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02007041 err = nla_parse_nested(plan, NL80211_SCHED_SCAN_PLAN_MAX,
Johannes Bergfceb6432017-04-12 14:34:07 +02007042 attr, nl80211_plan_policy, NULL);
Avraham Stern3b06d272015-10-12 09:51:34 +03007043 if (err)
7044 return err;
7045
7046 if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
7047 return -EINVAL;
7048
7049 request->scan_plans[i].interval =
7050 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
7051 if (!request->scan_plans[i].interval ||
7052 request->scan_plans[i].interval >
7053 wiphy->max_sched_scan_plan_interval)
7054 return -EINVAL;
7055
7056 if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
7057 request->scan_plans[i].iterations =
7058 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
7059 if (!request->scan_plans[i].iterations ||
7060 (request->scan_plans[i].iterations >
7061 wiphy->max_sched_scan_plan_iterations))
7062 return -EINVAL;
7063 } else if (i < n_plans - 1) {
7064 /*
7065 * All scan plans but the last one must specify
7066 * a finite number of iterations
7067 */
7068 return -EINVAL;
7069 }
7070
7071 i++;
7072 }
7073
7074 /*
7075 * The last scan plan must not specify the number of
7076 * iterations, it is supposed to run infinitely
7077 */
7078 if (request->scan_plans[n_plans - 1].iterations)
7079 return -EINVAL;
7080
7081 return 0;
7082}
7083
Luciano Coelho256da022014-11-10 16:13:46 +02007084static struct cfg80211_sched_scan_request *
Johannes Bergad2b26a2014-06-12 21:39:05 +02007085nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00007086 struct nlattr **attrs, int max_match_sets)
Luciano Coelho807f8a82011-05-11 17:09:35 +03007087{
7088 struct cfg80211_sched_scan_request *request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007089 struct nlattr *attr;
Avraham Stern3b06d272015-10-12 09:51:34 +03007090 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
Johannes Berg57fbcce2016-04-12 15:56:15 +02007091 enum nl80211_band band;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007092 size_t ie_len;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007093 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
Johannes Bergea73cbc2014-01-24 10:53:53 +01007094 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007095
Luciano Coelho256da022014-11-10 16:13:46 +02007096 if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE]))
7097 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007098
Luciano Coelho256da022014-11-10 16:13:46 +02007099 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007100 n_channels = validate_scan_freqs(
Luciano Coelho256da022014-11-10 16:13:46 +02007101 attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007102 if (!n_channels)
Luciano Coelho256da022014-11-10 16:13:46 +02007103 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007104 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02007105 n_channels = ieee80211_get_num_supported_channels(wiphy);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007106 }
7107
Luciano Coelho256da022014-11-10 16:13:46 +02007108 if (attrs[NL80211_ATTR_SCAN_SSIDS])
7109 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007110 tmp)
7111 n_ssids++;
7112
Luciano Coelho93b6aa62011-07-13 14:57:28 +03007113 if (n_ssids > wiphy->max_sched_scan_ssids)
Luciano Coelho256da022014-11-10 16:13:46 +02007114 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007115
Johannes Bergea73cbc2014-01-24 10:53:53 +01007116 /*
7117 * First, count the number of 'real' matchsets. Due to an issue with
7118 * the old implementation, matchsets containing only the RSSI attribute
7119 * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
7120 * RSSI for all matchsets, rather than their own matchset for reporting
7121 * all APs with a strong RSSI. This is needed to be compatible with
7122 * older userspace that treated a matchset with only the RSSI as the
7123 * global RSSI for all other matchsets - if there are other matchsets.
7124 */
Luciano Coelho256da022014-11-10 16:13:46 +02007125 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007126 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007127 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Johannes Bergea73cbc2014-01-24 10:53:53 +01007128 tmp) {
7129 struct nlattr *rssi;
7130
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02007131 err = nla_parse_nested(tb,
7132 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
Johannes Bergfceb6432017-04-12 14:34:07 +02007133 attr, nl80211_match_policy,
7134 NULL);
Johannes Bergea73cbc2014-01-24 10:53:53 +01007135 if (err)
Luciano Coelho256da022014-11-10 16:13:46 +02007136 return ERR_PTR(err);
Arend Van Spriel3007e352017-04-21 13:05:01 +01007137
7138 /* SSID and BSSID are mutually exclusive */
7139 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] &&
7140 tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID])
7141 return ERR_PTR(-EINVAL);
7142
Johannes Bergea73cbc2014-01-24 10:53:53 +01007143 /* add other standalone attributes here */
Arend Van Spriel3007e352017-04-21 13:05:01 +01007144 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] ||
7145 tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID]) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01007146 n_match_sets++;
7147 continue;
7148 }
7149 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
7150 if (rssi)
7151 default_match_rssi = nla_get_s32(rssi);
7152 }
7153 }
7154
7155 /* However, if there's no other matchset, add the RSSI one */
7156 if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
7157 n_match_sets = 1;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007158
Arend Van Sprielaad1e812017-01-27 12:27:44 +00007159 if (n_match_sets > max_match_sets)
Luciano Coelho256da022014-11-10 16:13:46 +02007160 return ERR_PTR(-EINVAL);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007161
Luciano Coelho256da022014-11-10 16:13:46 +02007162 if (attrs[NL80211_ATTR_IE])
7163 ie_len = nla_len(attrs[NL80211_ATTR_IE]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007164 else
7165 ie_len = 0;
7166
Luciano Coelho5a865ba2011-07-13 14:57:29 +03007167 if (ie_len > wiphy->max_sched_scan_ie_len)
Luciano Coelho256da022014-11-10 16:13:46 +02007168 return ERR_PTR(-EINVAL);
Luciano Coelhoc10841c2011-06-30 08:32:41 +03007169
Avraham Stern3b06d272015-10-12 09:51:34 +03007170 if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
7171 /*
7172 * NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
7173 * each scan plan already specifies its own interval
7174 */
7175 if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
7176 return ERR_PTR(-EINVAL);
7177
7178 nla_for_each_nested(attr,
7179 attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
7180 n_plans++;
7181 } else {
7182 /*
7183 * The scan interval attribute is kept for backward
7184 * compatibility. If no scan plans are specified and sched scan
7185 * interval is specified, one scan plan will be set with this
7186 * scan interval and infinite number of iterations.
7187 */
7188 if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
7189 return ERR_PTR(-EINVAL);
7190
7191 n_plans = 1;
7192 }
7193
7194 if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
7195 return ERR_PTR(-EINVAL);
7196
vamsi krishnabf95ecd2017-01-13 01:12:20 +02007197 if (!wiphy_ext_feature_isset(
7198 wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
7199 (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
7200 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
7201 return ERR_PTR(-EINVAL);
7202
Luciano Coelho807f8a82011-05-11 17:09:35 +03007203 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007204 + sizeof(*request->ssids) * n_ssids
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007205 + sizeof(*request->match_sets) * n_match_sets
Avraham Stern3b06d272015-10-12 09:51:34 +03007206 + sizeof(*request->scan_plans) * n_plans
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007207 + sizeof(*request->channels) * n_channels
Luciano Coelho807f8a82011-05-11 17:09:35 +03007208 + ie_len, GFP_KERNEL);
Luciano Coelho256da022014-11-10 16:13:46 +02007209 if (!request)
7210 return ERR_PTR(-ENOMEM);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007211
7212 if (n_ssids)
7213 request->ssids = (void *)&request->channels[n_channels];
7214 request->n_ssids = n_ssids;
7215 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01007216 if (n_ssids)
Luciano Coelho807f8a82011-05-11 17:09:35 +03007217 request->ie = (void *)(request->ssids + n_ssids);
7218 else
7219 request->ie = (void *)(request->channels + n_channels);
7220 }
7221
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007222 if (n_match_sets) {
7223 if (request->ie)
7224 request->match_sets = (void *)(request->ie + ie_len);
Johannes Berg13874e42015-01-23 11:25:20 +01007225 else if (n_ssids)
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007226 request->match_sets =
7227 (void *)(request->ssids + n_ssids);
7228 else
7229 request->match_sets =
7230 (void *)(request->channels + n_channels);
7231 }
7232 request->n_match_sets = n_match_sets;
7233
Avraham Stern3b06d272015-10-12 09:51:34 +03007234 if (n_match_sets)
7235 request->scan_plans = (void *)(request->match_sets +
7236 n_match_sets);
7237 else if (request->ie)
7238 request->scan_plans = (void *)(request->ie + ie_len);
7239 else if (n_ssids)
7240 request->scan_plans = (void *)(request->ssids + n_ssids);
7241 else
7242 request->scan_plans = (void *)(request->channels + n_channels);
7243
7244 request->n_scan_plans = n_plans;
7245
Luciano Coelho807f8a82011-05-11 17:09:35 +03007246 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007247 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007248 /* user specified, bail out if channel not found */
7249 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007250 attrs[NL80211_ATTR_SCAN_FREQUENCIES],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007251 tmp) {
7252 struct ieee80211_channel *chan;
7253
7254 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
7255
7256 if (!chan) {
7257 err = -EINVAL;
7258 goto out_free;
7259 }
7260
7261 /* ignore disabled channels */
7262 if (chan->flags & IEEE80211_CHAN_DISABLED)
7263 continue;
7264
7265 request->channels[i] = chan;
7266 i++;
7267 }
7268 } else {
7269 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02007270 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007271 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007272
Luciano Coelho807f8a82011-05-11 17:09:35 +03007273 if (!wiphy->bands[band])
7274 continue;
7275 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
7276 struct ieee80211_channel *chan;
7277
7278 chan = &wiphy->bands[band]->channels[j];
7279
7280 if (chan->flags & IEEE80211_CHAN_DISABLED)
7281 continue;
7282
7283 request->channels[i] = chan;
7284 i++;
7285 }
7286 }
7287 }
7288
7289 if (!i) {
7290 err = -EINVAL;
7291 goto out_free;
7292 }
7293
7294 request->n_channels = i;
7295
7296 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01007297 if (n_ssids) {
Luciano Coelho256da022014-11-10 16:13:46 +02007298 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007299 tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03007300 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007301 err = -EINVAL;
7302 goto out_free;
7303 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03007304 request->ssids[i].ssid_len = nla_len(attr);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007305 memcpy(request->ssids[i].ssid, nla_data(attr),
7306 nla_len(attr));
Luciano Coelho807f8a82011-05-11 17:09:35 +03007307 i++;
7308 }
7309 }
7310
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007311 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007312 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007313 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007314 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007315 tmp) {
Arend Van Spriel3007e352017-04-21 13:05:01 +01007316 struct nlattr *ssid, *bssid, *rssi;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007317
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02007318 err = nla_parse_nested(tb,
7319 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
Johannes Bergfceb6432017-04-12 14:34:07 +02007320 attr, nl80211_match_policy,
7321 NULL);
Johannes Bergae811e22014-01-24 10:17:47 +01007322 if (err)
7323 goto out_free;
Johannes Berg4a4ab0d2012-06-13 11:17:11 +02007324 ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
Arend Van Spriel3007e352017-04-21 13:05:01 +01007325 bssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID];
7326 if (ssid || bssid) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01007327 if (WARN_ON(i >= n_match_sets)) {
7328 /* this indicates a programming error,
7329 * the loop above should have verified
7330 * things properly
7331 */
7332 err = -EINVAL;
7333 goto out_free;
7334 }
7335
Arend Van Spriel3007e352017-04-21 13:05:01 +01007336 if (ssid) {
7337 if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
7338 err = -EINVAL;
7339 goto out_free;
7340 }
7341 memcpy(request->match_sets[i].ssid.ssid,
7342 nla_data(ssid), nla_len(ssid));
7343 request->match_sets[i].ssid.ssid_len =
7344 nla_len(ssid);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007345 }
Arend Van Spriel3007e352017-04-21 13:05:01 +01007346 if (bssid) {
7347 if (nla_len(bssid) != ETH_ALEN) {
7348 err = -EINVAL;
7349 goto out_free;
7350 }
7351 memcpy(request->match_sets[i].bssid,
7352 nla_data(bssid), ETH_ALEN);
7353 }
7354
Kirtika Ruchandani56ab3642016-05-29 19:54:10 -07007355 /* special attribute - old implementation w/a */
Johannes Bergea73cbc2014-01-24 10:53:53 +01007356 request->match_sets[i].rssi_thold =
7357 default_match_rssi;
7358 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
7359 if (rssi)
7360 request->match_sets[i].rssi_thold =
7361 nla_get_s32(rssi);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007362 }
7363 i++;
7364 }
Johannes Bergea73cbc2014-01-24 10:53:53 +01007365
7366 /* there was no other matchset, so the RSSI one is alone */
Luciano Coelhof89f46c2014-12-01 11:32:09 +02007367 if (i == 0 && n_match_sets)
Johannes Bergea73cbc2014-01-24 10:53:53 +01007368 request->match_sets[0].rssi_thold = default_match_rssi;
7369
7370 request->min_rssi_thold = INT_MAX;
7371 for (i = 0; i < n_match_sets; i++)
7372 request->min_rssi_thold =
7373 min(request->match_sets[i].rssi_thold,
7374 request->min_rssi_thold);
7375 } else {
7376 request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007377 }
7378
Johannes Berg9900e482014-02-04 21:01:25 +01007379 if (ie_len) {
7380 request->ie_len = ie_len;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007381 memcpy((void *)request->ie,
Luciano Coelho256da022014-11-10 16:13:46 +02007382 nla_data(attrs[NL80211_ATTR_IE]),
Luciano Coelho807f8a82011-05-11 17:09:35 +03007383 request->ie_len);
7384 }
7385
Roee Zamir2d23d072017-08-06 11:38:22 +03007386 err = nl80211_check_scan_flags(wiphy, wdev, request, attrs, true);
7387 if (err)
7388 goto out_free;
Sam Lefflered4737712012-10-11 21:03:31 -07007389
Luciano Coelho9c748932015-01-16 16:04:09 +02007390 if (attrs[NL80211_ATTR_SCHED_SCAN_DELAY])
7391 request->delay =
7392 nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
7393
vamsi krishnabf95ecd2017-01-13 01:12:20 +02007394 if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
7395 request->relative_rssi = nla_get_s8(
7396 attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
7397 request->relative_rssi_set = true;
7398 }
7399
7400 if (request->relative_rssi_set &&
7401 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
7402 struct nl80211_bss_select_rssi_adjust *rssi_adjust;
7403
7404 rssi_adjust = nla_data(
7405 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
7406 request->rssi_adjust.band = rssi_adjust->band;
7407 request->rssi_adjust.delta = rssi_adjust->delta;
7408 if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
7409 err = -EINVAL;
7410 goto out_free;
7411 }
7412 }
7413
Avraham Stern3b06d272015-10-12 09:51:34 +03007414 err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
7415 if (err)
7416 goto out_free;
7417
Sam Leffler15d60302012-10-11 21:03:34 -07007418 request->scan_start = jiffies;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007419
Luciano Coelho256da022014-11-10 16:13:46 +02007420 return request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007421
7422out_free:
7423 kfree(request);
Luciano Coelho256da022014-11-10 16:13:46 +02007424 return ERR_PTR(err);
7425}
7426
7427static int nl80211_start_sched_scan(struct sk_buff *skb,
7428 struct genl_info *info)
7429{
7430 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7431 struct net_device *dev = info->user_ptr[1];
Johannes Bergad2b26a2014-06-12 21:39:05 +02007432 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007433 struct cfg80211_sched_scan_request *sched_scan_req;
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007434 bool want_multi;
Luciano Coelho256da022014-11-10 16:13:46 +02007435 int err;
7436
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007437 if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_start)
Luciano Coelho256da022014-11-10 16:13:46 +02007438 return -EOPNOTSUPP;
7439
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007440 want_multi = info->attrs[NL80211_ATTR_SCHED_SCAN_MULTI];
7441 err = cfg80211_sched_scan_req_possible(rdev, want_multi);
7442 if (err)
7443 return err;
Luciano Coelho256da022014-11-10 16:13:46 +02007444
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007445 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00007446 info->attrs,
7447 rdev->wiphy.max_match_sets);
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007448
7449 err = PTR_ERR_OR_ZERO(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007450 if (err)
7451 goto out_err;
7452
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007453 /* leave request id zero for legacy request
7454 * or if driver does not support multi-scheduled scan
7455 */
7456 if (want_multi && rdev->wiphy.max_sched_scan_reqs > 1) {
7457 while (!sched_scan_req->reqid)
7458 sched_scan_req->reqid = rdev->wiphy.cookie_counter++;
7459 }
7460
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007461 err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007462 if (err)
7463 goto out_free;
7464
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007465 sched_scan_req->dev = dev;
7466 sched_scan_req->wiphy = &rdev->wiphy;
7467
Jukka Rissanen93a1e862014-12-15 13:25:39 +02007468 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
7469 sched_scan_req->owner_nlportid = info->snd_portid;
7470
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007471 cfg80211_add_sched_scan_req(rdev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007472
Arend Van Spriel96b08fd2017-04-13 13:06:27 +01007473 nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN);
Luciano Coelho256da022014-11-10 16:13:46 +02007474 return 0;
7475
7476out_free:
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007477 kfree(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007478out_err:
Luciano Coelho807f8a82011-05-11 17:09:35 +03007479 return err;
7480}
7481
7482static int nl80211_stop_sched_scan(struct sk_buff *skb,
7483 struct genl_info *info)
7484{
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007485 struct cfg80211_sched_scan_request *req;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007486 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007487 u64 cookie;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007488
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007489 if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_stop)
Luciano Coelho807f8a82011-05-11 17:09:35 +03007490 return -EOPNOTSUPP;
7491
Arend Van Sprielca986ad2017-04-21 13:05:00 +01007492 if (info->attrs[NL80211_ATTR_COOKIE]) {
7493 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
7494 return __cfg80211_stop_sched_scan(rdev, cookie, false);
7495 }
7496
7497 req = list_first_or_null_rcu(&rdev->sched_scan_req_list,
7498 struct cfg80211_sched_scan_request,
7499 list);
7500 if (!req || req->reqid ||
7501 (req->owner_nlportid &&
7502 req->owner_nlportid != info->snd_portid))
7503 return -ENOENT;
7504
7505 return cfg80211_stop_sched_scan_req(rdev, req, false);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007506}
7507
Simon Wunderlich04f39042013-02-08 18:16:19 +01007508static int nl80211_start_radar_detection(struct sk_buff *skb,
7509 struct genl_info *info)
7510{
7511 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7512 struct net_device *dev = info->user_ptr[1];
7513 struct wireless_dev *wdev = dev->ieee80211_ptr;
7514 struct cfg80211_chan_def chandef;
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007515 enum nl80211_dfs_regions dfs_region;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007516 unsigned int cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007517 int err;
7518
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007519 dfs_region = reg_get_dfs_region(wdev->wiphy);
7520 if (dfs_region == NL80211_DFS_UNSET)
7521 return -EINVAL;
7522
Simon Wunderlich04f39042013-02-08 18:16:19 +01007523 err = nl80211_parse_chandef(rdev, info, &chandef);
7524 if (err)
7525 return err;
7526
Simon Wunderlichff311bc2013-09-03 19:43:18 +02007527 if (netif_carrier_ok(dev))
7528 return -EBUSY;
7529
Simon Wunderlich04f39042013-02-08 18:16:19 +01007530 if (wdev->cac_started)
7531 return -EBUSY;
7532
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007533 err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
Luciano Coelho00ec75f2014-05-15 13:05:39 +03007534 wdev->iftype);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007535 if (err < 0)
7536 return err;
7537
7538 if (err == 0)
7539 return -EINVAL;
7540
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +01007541 if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
Simon Wunderlich04f39042013-02-08 18:16:19 +01007542 return -EINVAL;
7543
7544 if (!rdev->ops->start_radar_detection)
7545 return -EOPNOTSUPP;
7546
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007547 cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
7548 if (WARN_ON(!cac_time_ms))
7549 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
7550
Ilan Peera1056b1b2015-10-22 22:27:46 +03007551 err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007552 if (!err) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01007553 wdev->chandef = chandef;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007554 wdev->cac_started = true;
7555 wdev->cac_start_time = jiffies;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007556 wdev->cac_time_ms = cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007557 }
Simon Wunderlich04f39042013-02-08 18:16:19 +01007558 return err;
7559}
7560
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007561static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
7562{
7563 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7564 struct net_device *dev = info->user_ptr[1];
7565 struct wireless_dev *wdev = dev->ieee80211_ptr;
7566 struct cfg80211_csa_settings params;
7567 /* csa_attrs is defined static to avoid waste of stack size - this
7568 * function is called under RTNL lock, so this should not be a problem.
7569 */
7570 static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007571 int err;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007572 bool need_new_beacon = false;
Benjamin Berg8d9de162017-05-16 11:23:12 +02007573 bool need_handle_dfs_flag = true;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007574 int len, i;
Luciano Coelho252e07c2014-10-08 09:48:34 +03007575 u32 cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007576
7577 if (!rdev->ops->channel_switch ||
7578 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
7579 return -EOPNOTSUPP;
7580
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007581 switch (dev->ieee80211_ptr->iftype) {
7582 case NL80211_IFTYPE_AP:
7583 case NL80211_IFTYPE_P2P_GO:
7584 need_new_beacon = true;
Benjamin Berg8d9de162017-05-16 11:23:12 +02007585 /* For all modes except AP the handle_dfs flag needs to be
7586 * supplied to tell the kernel that userspace will handle radar
7587 * events when they happen. Otherwise a switch to a channel
7588 * requiring DFS will be rejected.
7589 */
7590 need_handle_dfs_flag = false;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007591
7592 /* useless if AP is not running */
7593 if (!wdev->beacon_interval)
Johannes Berg1ff79df2014-01-22 10:05:27 +01007594 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007595 break;
7596 case NL80211_IFTYPE_ADHOC:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007597 if (!wdev->ssid_len)
7598 return -ENOTCONN;
7599 break;
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07007600 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007601 if (!wdev->mesh_id_len)
7602 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007603 break;
7604 default:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007605 return -EOPNOTSUPP;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007606 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007607
7608 memset(&params, 0, sizeof(params));
7609
7610 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
7611 !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
7612 return -EINVAL;
7613
7614 /* only important for AP, IBSS and mesh create IEs internally */
Andrei Otcheretianskid0a361a2013-10-17 10:52:17 +02007615 if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007616 return -EINVAL;
7617
Luciano Coelho252e07c2014-10-08 09:48:34 +03007618 /* Even though the attribute is u32, the specification says
7619 * u8, so let's make sure we don't overflow.
7620 */
7621 cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
7622 if (cs_count > 255)
7623 return -EINVAL;
7624
7625 params.count = cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007626
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007627 if (!need_new_beacon)
7628 goto skip_beacons;
7629
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007630 err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
7631 if (err)
7632 return err;
7633
7634 err = nla_parse_nested(csa_attrs, NL80211_ATTR_MAX,
7635 info->attrs[NL80211_ATTR_CSA_IES],
Johannes Bergfe521452017-04-12 14:34:08 +02007636 nl80211_policy, info->extack);
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007637 if (err)
7638 return err;
7639
7640 err = nl80211_parse_beacon(csa_attrs, &params.beacon_csa);
7641 if (err)
7642 return err;
7643
7644 if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
7645 return -EINVAL;
7646
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007647 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7648 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007649 return -EINVAL;
7650
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007651 params.n_counter_offsets_beacon = len / sizeof(u16);
7652 if (rdev->wiphy.max_num_csa_counters &&
7653 (params.n_counter_offsets_beacon >
7654 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007655 return -EINVAL;
7656
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007657 params.counter_offsets_beacon =
7658 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7659
7660 /* sanity checks - counters should fit and be the same */
7661 for (i = 0; i < params.n_counter_offsets_beacon; i++) {
7662 u16 offset = params.counter_offsets_beacon[i];
7663
7664 if (offset >= params.beacon_csa.tail_len)
7665 return -EINVAL;
7666
7667 if (params.beacon_csa.tail[offset] != params.count)
7668 return -EINVAL;
7669 }
7670
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007671 if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007672 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7673 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007674 return -EINVAL;
7675
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007676 params.n_counter_offsets_presp = len / sizeof(u16);
7677 if (rdev->wiphy.max_num_csa_counters &&
Johannes Bergad5987b2016-09-13 15:53:55 +02007678 (params.n_counter_offsets_presp >
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007679 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007680 return -EINVAL;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007681
7682 params.counter_offsets_presp =
7683 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7684
7685 /* sanity checks - counters should fit and be the same */
7686 for (i = 0; i < params.n_counter_offsets_presp; i++) {
7687 u16 offset = params.counter_offsets_presp[i];
7688
7689 if (offset >= params.beacon_csa.probe_resp_len)
7690 return -EINVAL;
7691
7692 if (params.beacon_csa.probe_resp[offset] !=
7693 params.count)
7694 return -EINVAL;
7695 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007696 }
7697
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007698skip_beacons:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007699 err = nl80211_parse_chandef(rdev, info, &params.chandef);
7700 if (err)
7701 return err;
7702
Arik Nemtsov923b3522015-07-08 15:41:44 +03007703 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
7704 wdev->iftype))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007705 return -EINVAL;
7706
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007707 err = cfg80211_chandef_dfs_required(wdev->wiphy,
7708 &params.chandef,
7709 wdev->iftype);
7710 if (err < 0)
7711 return err;
7712
Benjamin Berg8d9de162017-05-16 11:23:12 +02007713 if (err > 0) {
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007714 params.radar_required = true;
Benjamin Berg8d9de162017-05-16 11:23:12 +02007715 if (need_handle_dfs_flag &&
7716 !nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) {
7717 return -EINVAL;
7718 }
7719 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007720
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007721 if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
7722 params.block_tx = true;
7723
Simon Wunderlichc56589e2013-11-21 18:19:49 +01007724 wdev_lock(wdev);
7725 err = rdev_channel_switch(rdev, dev, &params);
7726 wdev_unlock(wdev);
7727
7728 return err;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007729}
7730
Johannes Berg9720bb32011-06-21 09:45:33 +02007731static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
7732 u32 seq, int flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007733 struct cfg80211_registered_device *rdev,
Johannes Berg48ab9052009-07-10 18:42:31 +02007734 struct wireless_dev *wdev,
7735 struct cfg80211_internal_bss *intbss)
Johannes Berg2a519312009-02-10 21:25:55 +01007736{
Johannes Berg48ab9052009-07-10 18:42:31 +02007737 struct cfg80211_bss *res = &intbss->pub;
Johannes Berg9caf0362012-11-29 01:25:20 +01007738 const struct cfg80211_bss_ies *ies;
Johannes Berg2a519312009-02-10 21:25:55 +01007739 void *hdr;
7740 struct nlattr *bss;
Johannes Berg48ab9052009-07-10 18:42:31 +02007741
7742 ASSERT_WDEV_LOCK(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007743
Eric W. Biederman15e47302012-09-07 20:12:54 +00007744 hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007745 NL80211_CMD_NEW_SCAN_RESULTS);
7746 if (!hdr)
7747 return -1;
7748
Michal Kubecek0a833c22017-11-15 13:09:32 +01007749 genl_dump_check_consistent(cb, hdr);
Johannes Berg9720bb32011-06-21 09:45:33 +02007750
Johannes Berg97990a02013-04-19 01:02:55 +02007751 if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
7752 goto nla_put_failure;
7753 if (wdev->netdev &&
David S. Miller9360ffd2012-03-29 04:41:26 -04007754 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
7755 goto nla_put_failure;
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007756 if (nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
7757 NL80211_ATTR_PAD))
Johannes Berg97990a02013-04-19 01:02:55 +02007758 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007759
7760 bss = nla_nest_start(msg, NL80211_ATTR_BSS);
7761 if (!bss)
7762 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04007763 if ((!is_zero_ether_addr(res->bssid) &&
Johannes Berg9caf0362012-11-29 01:25:20 +01007764 nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
David S. Miller9360ffd2012-03-29 04:41:26 -04007765 goto nla_put_failure;
Johannes Berg9caf0362012-11-29 01:25:20 +01007766
7767 rcu_read_lock();
Johannes Berg0e227082014-08-12 20:34:30 +02007768 /* indicate whether we have probe response data or not */
7769 if (rcu_access_pointer(res->proberesp_ies) &&
7770 nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
7771 goto fail_unlock_rcu;
7772
7773 /* this pointer prefers to be pointed to probe response data
7774 * but is always valid
7775 */
Johannes Berg9caf0362012-11-29 01:25:20 +01007776 ies = rcu_dereference(res->ies);
Johannes Berg8cef2c92013-02-05 16:54:31 +01007777 if (ies) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007778 if (nla_put_u64_64bit(msg, NL80211_BSS_TSF, ies->tsf,
7779 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007780 goto fail_unlock_rcu;
Johannes Berg8cef2c92013-02-05 16:54:31 +01007781 if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
7782 ies->len, ies->data))
7783 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007784 }
Johannes Berg0e227082014-08-12 20:34:30 +02007785
7786 /* and this pointer is always (unless driver didn't know) beacon data */
Johannes Berg9caf0362012-11-29 01:25:20 +01007787 ies = rcu_dereference(res->beacon_ies);
Johannes Berg0e227082014-08-12 20:34:30 +02007788 if (ies && ies->from_beacon) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007789 if (nla_put_u64_64bit(msg, NL80211_BSS_BEACON_TSF, ies->tsf,
7790 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007791 goto fail_unlock_rcu;
7792 if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
7793 ies->len, ies->data))
7794 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007795 }
7796 rcu_read_unlock();
7797
David S. Miller9360ffd2012-03-29 04:41:26 -04007798 if (res->beacon_interval &&
7799 nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
7800 goto nla_put_failure;
7801 if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
7802 nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
Simon Wunderlichdcd6eac2013-07-08 16:55:49 +02007803 nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04007804 nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
7805 jiffies_to_msecs(jiffies - intbss->ts)))
7806 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007807
Avraham Stern1d762502016-07-05 17:10:13 +03007808 if (intbss->parent_tsf &&
7809 (nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
7810 intbss->parent_tsf, NL80211_BSS_PAD) ||
7811 nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
7812 intbss->parent_bssid)))
7813 goto nla_put_failure;
7814
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007815 if (intbss->ts_boottime &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007816 nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
7817 intbss->ts_boottime, NL80211_BSS_PAD))
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007818 goto nla_put_failure;
7819
Johannes Berg77965c92009-02-18 18:45:06 +01007820 switch (rdev->wiphy.signal_type) {
Johannes Berg2a519312009-02-10 21:25:55 +01007821 case CFG80211_SIGNAL_TYPE_MBM:
David S. Miller9360ffd2012-03-29 04:41:26 -04007822 if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
7823 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007824 break;
7825 case CFG80211_SIGNAL_TYPE_UNSPEC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007826 if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
7827 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007828 break;
7829 default:
7830 break;
7831 }
7832
Johannes Berg48ab9052009-07-10 18:42:31 +02007833 switch (wdev->iftype) {
Johannes Berg074ac8d2010-09-16 14:58:22 +02007834 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg48ab9052009-07-10 18:42:31 +02007835 case NL80211_IFTYPE_STATION:
David S. Miller9360ffd2012-03-29 04:41:26 -04007836 if (intbss == wdev->current_bss &&
7837 nla_put_u32(msg, NL80211_BSS_STATUS,
7838 NL80211_BSS_STATUS_ASSOCIATED))
7839 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007840 break;
7841 case NL80211_IFTYPE_ADHOC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007842 if (intbss == wdev->current_bss &&
7843 nla_put_u32(msg, NL80211_BSS_STATUS,
7844 NL80211_BSS_STATUS_IBSS_JOINED))
7845 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007846 break;
7847 default:
7848 break;
7849 }
7850
Johannes Berg2a519312009-02-10 21:25:55 +01007851 nla_nest_end(msg, bss);
7852
Johannes Berg053c0952015-01-16 22:09:00 +01007853 genlmsg_end(msg, hdr);
7854 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007855
Johannes Berg8cef2c92013-02-05 16:54:31 +01007856 fail_unlock_rcu:
7857 rcu_read_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01007858 nla_put_failure:
7859 genlmsg_cancel(msg, hdr);
7860 return -EMSGSIZE;
7861}
7862
Johannes Berg97990a02013-04-19 01:02:55 +02007863static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
Johannes Berg2a519312009-02-10 21:25:55 +01007864{
Johannes Berg48ab9052009-07-10 18:42:31 +02007865 struct cfg80211_registered_device *rdev;
Johannes Berg2a519312009-02-10 21:25:55 +01007866 struct cfg80211_internal_bss *scan;
Johannes Berg48ab9052009-07-10 18:42:31 +02007867 struct wireless_dev *wdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007868 int start = cb->args[2], idx = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007869 int err;
7870
Johannes Bergea90e0d2017-03-15 14:26:04 +01007871 rtnl_lock();
Johannes Berg97990a02013-04-19 01:02:55 +02007872 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Bergea90e0d2017-03-15 14:26:04 +01007873 if (err) {
7874 rtnl_unlock();
Johannes Berg67748892010-10-04 21:14:06 +02007875 return err;
Johannes Bergea90e0d2017-03-15 14:26:04 +01007876 }
Johannes Berg2a519312009-02-10 21:25:55 +01007877
Johannes Berg48ab9052009-07-10 18:42:31 +02007878 wdev_lock(wdev);
7879 spin_lock_bh(&rdev->bss_lock);
7880 cfg80211_bss_expire(rdev);
7881
Johannes Berg9720bb32011-06-21 09:45:33 +02007882 cb->seq = rdev->bss_generation;
7883
Johannes Berg48ab9052009-07-10 18:42:31 +02007884 list_for_each_entry(scan, &rdev->bss_list, list) {
Johannes Berg2a519312009-02-10 21:25:55 +01007885 if (++idx <= start)
7886 continue;
Johannes Berg9720bb32011-06-21 09:45:33 +02007887 if (nl80211_send_bss(skb, cb,
Johannes Berg2a519312009-02-10 21:25:55 +01007888 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg48ab9052009-07-10 18:42:31 +02007889 rdev, wdev, scan) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +01007890 idx--;
Johannes Berg67748892010-10-04 21:14:06 +02007891 break;
Johannes Berg2a519312009-02-10 21:25:55 +01007892 }
7893 }
7894
Johannes Berg48ab9052009-07-10 18:42:31 +02007895 spin_unlock_bh(&rdev->bss_lock);
7896 wdev_unlock(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007897
Johannes Berg97990a02013-04-19 01:02:55 +02007898 cb->args[2] = idx;
Johannes Bergea90e0d2017-03-15 14:26:04 +01007899 rtnl_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01007900
Johannes Berg67748892010-10-04 21:14:06 +02007901 return skb->len;
Johannes Berg2a519312009-02-10 21:25:55 +01007902}
7903
Eric W. Biederman15e47302012-09-07 20:12:54 +00007904static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg11f78ac2014-11-14 16:43:50 +01007905 int flags, struct net_device *dev,
7906 bool allow_radio_stats,
7907 struct survey_info *survey)
Holger Schurig61fa7132009-11-11 12:25:40 +01007908{
7909 void *hdr;
7910 struct nlattr *infoattr;
7911
Johannes Berg11f78ac2014-11-14 16:43:50 +01007912 /* skip radio stats if userspace didn't request them */
7913 if (!survey->channel && !allow_radio_stats)
7914 return 0;
7915
Eric W. Biederman15e47302012-09-07 20:12:54 +00007916 hdr = nl80211hdr_put(msg, portid, seq, flags,
Holger Schurig61fa7132009-11-11 12:25:40 +01007917 NL80211_CMD_NEW_SURVEY_RESULTS);
7918 if (!hdr)
7919 return -ENOMEM;
7920
David S. Miller9360ffd2012-03-29 04:41:26 -04007921 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
7922 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01007923
7924 infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
7925 if (!infoattr)
7926 goto nla_put_failure;
7927
Johannes Berg11f78ac2014-11-14 16:43:50 +01007928 if (survey->channel &&
7929 nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
David S. Miller9360ffd2012-03-29 04:41:26 -04007930 survey->channel->center_freq))
7931 goto nla_put_failure;
7932
7933 if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
7934 nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
7935 goto nla_put_failure;
7936 if ((survey->filled & SURVEY_INFO_IN_USE) &&
7937 nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
7938 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007939 if ((survey->filled & SURVEY_INFO_TIME) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007940 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME,
7941 survey->time, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007942 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007943 if ((survey->filled & SURVEY_INFO_TIME_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007944 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BUSY,
7945 survey->time_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007946 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007947 if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007948 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
7949 survey->time_ext_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007950 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007951 if ((survey->filled & SURVEY_INFO_TIME_RX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007952 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_RX,
7953 survey->time_rx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007954 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007955 if ((survey->filled & SURVEY_INFO_TIME_TX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007956 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_TX,
7957 survey->time_tx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007958 goto nla_put_failure;
Johannes Berg052536a2014-11-14 16:44:11 +01007959 if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007960 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_SCAN,
7961 survey->time_scan, NL80211_SURVEY_INFO_PAD))
Johannes Berg052536a2014-11-14 16:44:11 +01007962 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01007963
7964 nla_nest_end(msg, infoattr);
7965
Johannes Berg053c0952015-01-16 22:09:00 +01007966 genlmsg_end(msg, hdr);
7967 return 0;
Holger Schurig61fa7132009-11-11 12:25:40 +01007968
7969 nla_put_failure:
7970 genlmsg_cancel(msg, hdr);
7971 return -EMSGSIZE;
7972}
7973
Johannes Berg11f78ac2014-11-14 16:43:50 +01007974static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
Holger Schurig61fa7132009-11-11 12:25:40 +01007975{
Johannes Bergc90c39d2016-10-24 14:40:01 +02007976 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
Holger Schurig61fa7132009-11-11 12:25:40 +01007977 struct survey_info survey;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007978 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007979 struct wireless_dev *wdev;
7980 int survey_idx = cb->args[2];
Holger Schurig61fa7132009-11-11 12:25:40 +01007981 int res;
Johannes Berg11f78ac2014-11-14 16:43:50 +01007982 bool radio_stats;
Holger Schurig61fa7132009-11-11 12:25:40 +01007983
Johannes Bergea90e0d2017-03-15 14:26:04 +01007984 rtnl_lock();
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007985 res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02007986 if (res)
Johannes Bergea90e0d2017-03-15 14:26:04 +01007987 goto out_err;
Holger Schurig61fa7132009-11-11 12:25:40 +01007988
Johannes Berg11f78ac2014-11-14 16:43:50 +01007989 /* prepare_wdev_dump parsed the attributes */
Johannes Bergc90c39d2016-10-24 14:40:01 +02007990 radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
Johannes Berg11f78ac2014-11-14 16:43:50 +01007991
Johannes Berg97990a02013-04-19 01:02:55 +02007992 if (!wdev->netdev) {
7993 res = -EINVAL;
7994 goto out_err;
7995 }
7996
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007997 if (!rdev->ops->dump_survey) {
Holger Schurig61fa7132009-11-11 12:25:40 +01007998 res = -EOPNOTSUPP;
7999 goto out_err;
8000 }
8001
8002 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08008003 res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
Holger Schurig61fa7132009-11-11 12:25:40 +01008004 if (res == -ENOENT)
8005 break;
8006 if (res)
8007 goto out_err;
8008
Johannes Berg11f78ac2014-11-14 16:43:50 +01008009 /* don't send disabled channels, but do send non-channel data */
8010 if (survey.channel &&
8011 survey.channel->flags & IEEE80211_CHAN_DISABLED) {
Luis R. Rodriguez180cdc72011-05-27 07:24:02 -07008012 survey_idx++;
8013 continue;
8014 }
8015
Holger Schurig61fa7132009-11-11 12:25:40 +01008016 if (nl80211_send_survey(skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00008017 NETLINK_CB(cb->skb).portid,
Holger Schurig61fa7132009-11-11 12:25:40 +01008018 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg11f78ac2014-11-14 16:43:50 +01008019 wdev->netdev, radio_stats, &survey) < 0)
Holger Schurig61fa7132009-11-11 12:25:40 +01008020 goto out;
8021 survey_idx++;
8022 }
8023
8024 out:
Johannes Berg97990a02013-04-19 01:02:55 +02008025 cb->args[2] = survey_idx;
Holger Schurig61fa7132009-11-11 12:25:40 +01008026 res = skb->len;
8027 out_err:
Johannes Bergea90e0d2017-03-15 14:26:04 +01008028 rtnl_unlock();
Holger Schurig61fa7132009-11-11 12:25:40 +01008029 return res;
8030}
8031
Samuel Ortizb23aa672009-07-01 21:26:54 +02008032static bool nl80211_valid_wpa_versions(u32 wpa_versions)
8033{
8034 return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
8035 NL80211_WPA_VERSION_2));
8036}
8037
Jouni Malinen636a5d32009-03-19 13:39:22 +02008038static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
8039{
Johannes Berg4c476992010-10-04 21:36:35 +02008040 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8041 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008042 struct ieee80211_channel *chan;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008043 const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
8044 int err, ssid_len, ie_len = 0, auth_data_len = 0;
Johannes Berg19957bb2009-07-02 17:20:43 +02008045 enum nl80211_auth_type auth_type;
Johannes Bergfffd0932009-07-08 14:22:54 +02008046 struct key_parse key;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008047 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008048
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008049 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8050 return -EINVAL;
8051
8052 if (!info->attrs[NL80211_ATTR_MAC])
8053 return -EINVAL;
8054
Jouni Malinen17780922009-03-27 20:52:47 +02008055 if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
8056 return -EINVAL;
8057
Johannes Berg19957bb2009-07-02 17:20:43 +02008058 if (!info->attrs[NL80211_ATTR_SSID])
8059 return -EINVAL;
8060
8061 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
8062 return -EINVAL;
8063
Johannes Bergfffd0932009-07-08 14:22:54 +02008064 err = nl80211_parse_key(info, &key);
8065 if (err)
8066 return err;
8067
8068 if (key.idx >= 0) {
Johannes Berge31b8212010-10-05 19:39:30 +02008069 if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
8070 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02008071 if (!key.p.key || !key.p.key_len)
8072 return -EINVAL;
8073 if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
8074 key.p.key_len != WLAN_KEY_LEN_WEP40) &&
8075 (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
8076 key.p.key_len != WLAN_KEY_LEN_WEP104))
8077 return -EINVAL;
Johannes Bergb6b55552016-09-13 16:25:58 +02008078 if (key.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +02008079 return -EINVAL;
8080 } else {
8081 key.p.key_len = 0;
8082 key.p.key = NULL;
8083 }
8084
Johannes Bergafea0b72010-08-10 09:46:42 +02008085 if (key.idx >= 0) {
8086 int i;
8087 bool ok = false;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07008088
Johannes Bergafea0b72010-08-10 09:46:42 +02008089 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
8090 if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
8091 ok = true;
8092 break;
8093 }
8094 }
Johannes Berg4c476992010-10-04 21:36:35 +02008095 if (!ok)
8096 return -EINVAL;
Johannes Bergafea0b72010-08-10 09:46:42 +02008097 }
8098
Johannes Berg4c476992010-10-04 21:36:35 +02008099 if (!rdev->ops->auth)
8100 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008101
Johannes Berg074ac8d2010-09-16 14:58:22 +02008102 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008103 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8104 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008105
Johannes Berg19957bb2009-07-02 17:20:43 +02008106 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen664834d2014-01-15 00:01:44 +02008107 chan = nl80211_get_valid_chan(&rdev->wiphy,
8108 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8109 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02008110 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008111
Johannes Berg19957bb2009-07-02 17:20:43 +02008112 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8113 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8114
8115 if (info->attrs[NL80211_ATTR_IE]) {
8116 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8117 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8118 }
8119
8120 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03008121 if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
Johannes Berg4c476992010-10-04 21:36:35 +02008122 return -EINVAL;
Johannes Berg19957bb2009-07-02 17:20:43 +02008123
Jouni Malinen63181062016-10-27 00:42:02 +03008124 if ((auth_type == NL80211_AUTHTYPE_SAE ||
8125 auth_type == NL80211_AUTHTYPE_FILS_SK ||
8126 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
8127 auth_type == NL80211_AUTHTYPE_FILS_PK) &&
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008128 !info->attrs[NL80211_ATTR_AUTH_DATA])
Jouni Malinene39e5b52012-09-30 19:29:39 +03008129 return -EINVAL;
8130
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008131 if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
Jouni Malinen63181062016-10-27 00:42:02 +03008132 if (auth_type != NL80211_AUTHTYPE_SAE &&
8133 auth_type != NL80211_AUTHTYPE_FILS_SK &&
8134 auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
8135 auth_type != NL80211_AUTHTYPE_FILS_PK)
Jouni Malinene39e5b52012-09-30 19:29:39 +03008136 return -EINVAL;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008137 auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
8138 auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03008139 /* need to include at least Auth Transaction and Status Code */
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008140 if (auth_data_len < 4)
Jouni Malinene39e5b52012-09-30 19:29:39 +03008141 return -EINVAL;
8142 }
8143
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008144 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8145
Johannes Berg95de8172012-01-20 13:55:25 +01008146 /*
8147 * Since we no longer track auth state, ignore
8148 * requests to only change local state.
8149 */
8150 if (local_state_change)
8151 return 0;
8152
Johannes Berg91bf9b22013-05-15 17:44:01 +02008153 wdev_lock(dev->ieee80211_ptr);
8154 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
8155 ssid, ssid_len, ie, ie_len,
8156 key.p.key, key.p.key_len, key.idx,
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008157 auth_data, auth_data_len);
Johannes Berg91bf9b22013-05-15 17:44:01 +02008158 wdev_unlock(dev->ieee80211_ptr);
8159 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008160}
8161
Johannes Bergc0692b82010-08-27 14:26:53 +03008162static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
8163 struct genl_info *info,
Johannes Berg3dc27d22009-07-02 21:36:37 +02008164 struct cfg80211_crypto_settings *settings,
8165 int cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02008166{
Johannes Bergc0b2bbd2009-07-25 16:54:36 +02008167 memset(settings, 0, sizeof(*settings));
8168
Samuel Ortizb23aa672009-07-01 21:26:54 +02008169 settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
8170
Johannes Bergc0692b82010-08-27 14:26:53 +03008171 if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
8172 u16 proto;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07008173
Johannes Bergc0692b82010-08-27 14:26:53 +03008174 proto = nla_get_u16(
8175 info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
8176 settings->control_port_ethertype = cpu_to_be16(proto);
8177 if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
8178 proto != ETH_P_PAE)
8179 return -EINVAL;
8180 if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
8181 settings->control_port_no_encrypt = true;
8182 } else
8183 settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
8184
Samuel Ortizb23aa672009-07-01 21:26:54 +02008185 if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
8186 void *data;
8187 int len, i;
8188
8189 data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
8190 len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
8191 settings->n_ciphers_pairwise = len / sizeof(u32);
8192
8193 if (len % sizeof(u32))
8194 return -EINVAL;
8195
Johannes Berg3dc27d22009-07-02 21:36:37 +02008196 if (settings->n_ciphers_pairwise > cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02008197 return -EINVAL;
8198
8199 memcpy(settings->ciphers_pairwise, data, len);
8200
8201 for (i = 0; i < settings->n_ciphers_pairwise; i++)
Jouni Malinen38ba3c52011-09-21 18:14:56 +03008202 if (!cfg80211_supported_cipher_suite(
8203 &rdev->wiphy,
Samuel Ortizb23aa672009-07-01 21:26:54 +02008204 settings->ciphers_pairwise[i]))
8205 return -EINVAL;
8206 }
8207
8208 if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
8209 settings->cipher_group =
8210 nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
Jouni Malinen38ba3c52011-09-21 18:14:56 +03008211 if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
8212 settings->cipher_group))
Samuel Ortizb23aa672009-07-01 21:26:54 +02008213 return -EINVAL;
8214 }
8215
8216 if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
8217 settings->wpa_versions =
8218 nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
8219 if (!nl80211_valid_wpa_versions(settings->wpa_versions))
8220 return -EINVAL;
8221 }
8222
8223 if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
8224 void *data;
Jouni Malinen6d302402011-09-21 18:11:33 +03008225 int len;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008226
8227 data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
8228 len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
8229 settings->n_akm_suites = len / sizeof(u32);
8230
8231 if (len % sizeof(u32))
8232 return -EINVAL;
8233
Jouni Malinen1b9ca022011-09-21 16:13:07 +03008234 if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
8235 return -EINVAL;
8236
Samuel Ortizb23aa672009-07-01 21:26:54 +02008237 memcpy(settings->akm_suites, data, len);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008238 }
8239
Eliad Peller91b5ab62017-06-09 13:08:42 +01008240 if (info->attrs[NL80211_ATTR_PMK]) {
8241 if (nla_len(info->attrs[NL80211_ATTR_PMK]) != WLAN_PMK_LEN)
8242 return -EINVAL;
8243 if (!wiphy_ext_feature_isset(&rdev->wiphy,
8244 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK))
8245 return -EINVAL;
8246 settings->psk = nla_data(info->attrs[NL80211_ATTR_PMK]);
8247 }
8248
Samuel Ortizb23aa672009-07-01 21:26:54 +02008249 return 0;
8250}
8251
Jouni Malinen636a5d32009-03-19 13:39:22 +02008252static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
8253{
Johannes Berg4c476992010-10-04 21:36:35 +02008254 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8255 struct net_device *dev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02008256 struct ieee80211_channel *chan;
Johannes Bergf62fab72013-02-21 20:09:09 +01008257 struct cfg80211_assoc_request req = {};
8258 const u8 *bssid, *ssid;
8259 int err, ssid_len = 0;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008260
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008261 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8262 return -EINVAL;
8263
8264 if (!info->attrs[NL80211_ATTR_MAC] ||
Johannes Berg19957bb2009-07-02 17:20:43 +02008265 !info->attrs[NL80211_ATTR_SSID] ||
8266 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008267 return -EINVAL;
8268
Johannes Berg4c476992010-10-04 21:36:35 +02008269 if (!rdev->ops->assoc)
8270 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008271
Johannes Berg074ac8d2010-09-16 14:58:22 +02008272 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008273 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8274 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008275
Johannes Berg19957bb2009-07-02 17:20:43 +02008276 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008277
Jouni Malinen664834d2014-01-15 00:01:44 +02008278 chan = nl80211_get_valid_chan(&rdev->wiphy,
8279 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8280 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02008281 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008282
Johannes Berg19957bb2009-07-02 17:20:43 +02008283 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8284 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008285
8286 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008287 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8288 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008289 }
8290
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008291 if (info->attrs[NL80211_ATTR_USE_MFP]) {
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008292 enum nl80211_mfp mfp =
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008293 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008294 if (mfp == NL80211_MFP_REQUIRED)
Johannes Bergf62fab72013-02-21 20:09:09 +01008295 req.use_mfp = true;
Johannes Berg4c476992010-10-04 21:36:35 +02008296 else if (mfp != NL80211_MFP_NO)
8297 return -EINVAL;
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008298 }
8299
Johannes Berg3e5d7642009-07-07 14:37:26 +02008300 if (info->attrs[NL80211_ATTR_PREV_BSSID])
Johannes Bergf62fab72013-02-21 20:09:09 +01008301 req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
Johannes Berg3e5d7642009-07-07 14:37:26 +02008302
Ben Greear7e7c8922011-11-18 11:31:59 -08008303 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008304 req.flags |= ASSOC_REQ_DISABLE_HT;
Ben Greear7e7c8922011-11-18 11:31:59 -08008305
8306 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008307 memcpy(&req.ht_capa_mask,
8308 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8309 sizeof(req.ht_capa_mask));
Ben Greear7e7c8922011-11-18 11:31:59 -08008310
8311 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008312 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Ben Greear7e7c8922011-11-18 11:31:59 -08008313 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008314 memcpy(&req.ht_capa,
8315 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8316 sizeof(req.ht_capa));
Ben Greear7e7c8922011-11-18 11:31:59 -08008317 }
8318
Johannes Bergee2aca32013-02-21 17:36:01 +01008319 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008320 req.flags |= ASSOC_REQ_DISABLE_VHT;
Johannes Bergee2aca32013-02-21 17:36:01 +01008321
8322 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008323 memcpy(&req.vht_capa_mask,
8324 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
8325 sizeof(req.vht_capa_mask));
Johannes Bergee2aca32013-02-21 17:36:01 +01008326
8327 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008328 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergee2aca32013-02-21 17:36:01 +01008329 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008330 memcpy(&req.vht_capa,
8331 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
8332 sizeof(req.vht_capa));
Johannes Bergee2aca32013-02-21 17:36:01 +01008333 }
8334
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008335 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02008336 if (!((rdev->wiphy.features &
8337 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
8338 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
8339 !wiphy_ext_feature_isset(&rdev->wiphy,
8340 NL80211_EXT_FEATURE_RRM))
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008341 return -EINVAL;
8342 req.flags |= ASSOC_REQ_USE_RRM;
8343 }
8344
Jouni Malinen348bd452016-10-27 00:42:03 +03008345 if (info->attrs[NL80211_ATTR_FILS_KEK]) {
8346 req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
8347 req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
8348 if (!info->attrs[NL80211_ATTR_FILS_NONCES])
8349 return -EINVAL;
8350 req.fils_nonces =
8351 nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
8352 }
8353
Johannes Bergf62fab72013-02-21 20:09:09 +01008354 err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
Johannes Berg91bf9b22013-05-15 17:44:01 +02008355 if (!err) {
8356 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008357
Johannes Bergf62fab72013-02-21 20:09:09 +01008358 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
8359 ssid, ssid_len, &req);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008360
8361 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8362 dev->ieee80211_ptr->conn_owner_nlportid =
8363 info->snd_portid;
8364 memcpy(dev->ieee80211_ptr->disconnect_bssid,
8365 bssid, ETH_ALEN);
8366 }
8367
Johannes Berg91bf9b22013-05-15 17:44:01 +02008368 wdev_unlock(dev->ieee80211_ptr);
8369 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008370
Jouni Malinen636a5d32009-03-19 13:39:22 +02008371 return err;
8372}
8373
8374static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
8375{
Johannes Berg4c476992010-10-04 21:36:35 +02008376 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8377 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008378 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008379 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008380 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008381 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008382
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008383 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8384 return -EINVAL;
8385
8386 if (!info->attrs[NL80211_ATTR_MAC])
8387 return -EINVAL;
8388
8389 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8390 return -EINVAL;
8391
Johannes Berg4c476992010-10-04 21:36:35 +02008392 if (!rdev->ops->deauth)
8393 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008394
Johannes Berg074ac8d2010-09-16 14:58:22 +02008395 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008396 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8397 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008398
Johannes Berg19957bb2009-07-02 17:20:43 +02008399 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008400
Johannes Berg19957bb2009-07-02 17:20:43 +02008401 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8402 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008403 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008404 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008405 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008406
8407 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008408 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8409 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008410 }
8411
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008412 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8413
Johannes Berg91bf9b22013-05-15 17:44:01 +02008414 wdev_lock(dev->ieee80211_ptr);
8415 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
8416 local_state_change);
8417 wdev_unlock(dev->ieee80211_ptr);
8418 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008419}
8420
8421static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
8422{
Johannes Berg4c476992010-10-04 21:36:35 +02008423 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8424 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008425 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008426 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008427 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008428 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008429
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008430 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8431 return -EINVAL;
8432
8433 if (!info->attrs[NL80211_ATTR_MAC])
8434 return -EINVAL;
8435
8436 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8437 return -EINVAL;
8438
Johannes Berg4c476992010-10-04 21:36:35 +02008439 if (!rdev->ops->disassoc)
8440 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008441
Johannes Berg074ac8d2010-09-16 14:58:22 +02008442 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008443 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8444 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008445
Johannes Berg19957bb2009-07-02 17:20:43 +02008446 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008447
Johannes Berg19957bb2009-07-02 17:20:43 +02008448 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8449 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008450 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008451 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008452 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008453
8454 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008455 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8456 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008457 }
8458
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008459 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8460
Johannes Berg91bf9b22013-05-15 17:44:01 +02008461 wdev_lock(dev->ieee80211_ptr);
8462 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
8463 local_state_change);
8464 wdev_unlock(dev->ieee80211_ptr);
8465 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008466}
8467
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008468static bool
8469nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
Johannes Berg57fbcce2016-04-12 15:56:15 +02008470 int mcast_rate[NUM_NL80211_BANDS],
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008471 int rateval)
8472{
8473 struct wiphy *wiphy = &rdev->wiphy;
8474 bool found = false;
8475 int band, i;
8476
Johannes Berg57fbcce2016-04-12 15:56:15 +02008477 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008478 struct ieee80211_supported_band *sband;
8479
8480 sband = wiphy->bands[band];
8481 if (!sband)
8482 continue;
8483
8484 for (i = 0; i < sband->n_bitrates; i++) {
8485 if (sband->bitrates[i].bitrate == rateval) {
8486 mcast_rate[band] = i + 1;
8487 found = true;
8488 break;
8489 }
8490 }
8491 }
8492
8493 return found;
8494}
8495
Johannes Berg04a773a2009-04-19 21:24:32 +02008496static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
8497{
Johannes Berg4c476992010-10-04 21:36:35 +02008498 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8499 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008500 struct cfg80211_ibss_params ibss;
8501 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008502 struct cfg80211_cached_keys *connkeys = NULL;
Johannes Berg04a773a2009-04-19 21:24:32 +02008503 int err;
8504
Johannes Berg8e30bc52009-04-22 17:45:38 +02008505 memset(&ibss, 0, sizeof(ibss));
8506
Johannes Berg04a773a2009-04-19 21:24:32 +02008507 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8508 return -EINVAL;
8509
Johannes Berg683b6d32012-11-08 21:25:48 +01008510 if (!info->attrs[NL80211_ATTR_SSID] ||
Johannes Berg04a773a2009-04-19 21:24:32 +02008511 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8512 return -EINVAL;
8513
Johannes Berg8e30bc52009-04-22 17:45:38 +02008514 ibss.beacon_interval = 100;
8515
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308516 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
Johannes Berg8e30bc52009-04-22 17:45:38 +02008517 ibss.beacon_interval =
8518 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308519
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05308520 err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
8521 ibss.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308522 if (err)
8523 return err;
Johannes Berg8e30bc52009-04-22 17:45:38 +02008524
Johannes Berg4c476992010-10-04 21:36:35 +02008525 if (!rdev->ops->join_ibss)
8526 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008527
Johannes Berg4c476992010-10-04 21:36:35 +02008528 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8529 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008530
Johannes Berg79c97e92009-07-07 03:56:12 +02008531 wiphy = &rdev->wiphy;
Johannes Berg04a773a2009-04-19 21:24:32 +02008532
Johannes Berg39193492011-09-16 13:45:25 +02008533 if (info->attrs[NL80211_ATTR_MAC]) {
Johannes Berg04a773a2009-04-19 21:24:32 +02008534 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg39193492011-09-16 13:45:25 +02008535
8536 if (!is_valid_ether_addr(ibss.bssid))
8537 return -EINVAL;
8538 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008539 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8540 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8541
8542 if (info->attrs[NL80211_ATTR_IE]) {
8543 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8544 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8545 }
8546
Johannes Berg683b6d32012-11-08 21:25:48 +01008547 err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
8548 if (err)
8549 return err;
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008550
Ilan Peer174e0cd2014-02-23 09:13:01 +02008551 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
8552 NL80211_IFTYPE_ADHOC))
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008553 return -EINVAL;
8554
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008555 switch (ibss.chandef.width) {
Simon Wunderlichbf372642013-07-08 16:55:58 +02008556 case NL80211_CHAN_WIDTH_5:
8557 case NL80211_CHAN_WIDTH_10:
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008558 case NL80211_CHAN_WIDTH_20_NOHT:
8559 break;
8560 case NL80211_CHAN_WIDTH_20:
8561 case NL80211_CHAN_WIDTH_40:
Janusz.Dziedzic@tieto.comffc11992015-02-21 16:52:39 +01008562 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8563 return -EINVAL;
8564 break;
8565 case NL80211_CHAN_WIDTH_80:
8566 case NL80211_CHAN_WIDTH_80P80:
8567 case NL80211_CHAN_WIDTH_160:
8568 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8569 return -EINVAL;
8570 if (!wiphy_ext_feature_isset(&rdev->wiphy,
8571 NL80211_EXT_FEATURE_VHT_IBSS))
8572 return -EINVAL;
8573 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008574 default:
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008575 return -EINVAL;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008576 }
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008577
Johannes Berg04a773a2009-04-19 21:24:32 +02008578 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
Johannes Bergfffd0932009-07-08 14:22:54 +02008579 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
Johannes Berg04a773a2009-04-19 21:24:32 +02008580
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008581 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
8582 u8 *rates =
8583 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8584 int n_rates =
8585 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8586 struct ieee80211_supported_band *sband =
Johannes Berg683b6d32012-11-08 21:25:48 +01008587 wiphy->bands[ibss.chandef.chan->band];
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008588
Johannes Berg34850ab2011-07-18 18:08:35 +02008589 err = ieee80211_get_ratemask(sband, rates, n_rates,
8590 &ibss.basic_rates);
8591 if (err)
8592 return err;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008593 }
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008594
Simon Wunderlich803768f2013-06-28 10:39:58 +02008595 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8596 memcpy(&ibss.ht_capa_mask,
8597 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8598 sizeof(ibss.ht_capa_mask));
8599
8600 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
8601 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8602 return -EINVAL;
8603 memcpy(&ibss.ht_capa,
8604 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8605 sizeof(ibss.ht_capa));
8606 }
8607
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008608 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
8609 !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
8610 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
8611 return -EINVAL;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008612
Johannes Berg4c476992010-10-04 21:36:35 +02008613 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Sujith Manoharande7044e2012-10-18 10:19:28 +05308614 bool no_ht = false;
8615
Johannes Berg4c476992010-10-04 21:36:35 +02008616 connkeys = nl80211_parse_connkeys(rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +05308617 info->attrs[NL80211_ATTR_KEYS],
8618 &no_ht);
Johannes Berg4c476992010-10-04 21:36:35 +02008619 if (IS_ERR(connkeys))
8620 return PTR_ERR(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308621
Johannes Berg3d9d1d62012-11-08 23:14:50 +01008622 if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
8623 no_ht) {
Ola Olsson5e950a72016-02-11 01:00:22 +01008624 kzfree(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308625 return -EINVAL;
8626 }
Johannes Berg4c476992010-10-04 21:36:35 +02008627 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008628
Antonio Quartulli267335d2012-01-31 20:25:47 +01008629 ibss.control_port =
8630 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
8631
Simon Wunderlich5336fa82013-10-07 18:41:05 +02008632 ibss.userspace_handles_dfs =
8633 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
8634
Johannes Berg4c476992010-10-04 21:36:35 +02008635 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02008636 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03008637 kzfree(connkeys);
Johannes Berg04a773a2009-04-19 21:24:32 +02008638 return err;
8639}
8640
8641static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
8642{
Johannes Berg4c476992010-10-04 21:36:35 +02008643 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8644 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008645
Johannes Berg4c476992010-10-04 21:36:35 +02008646 if (!rdev->ops->leave_ibss)
8647 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008648
Johannes Berg4c476992010-10-04 21:36:35 +02008649 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8650 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008651
Johannes Berg4c476992010-10-04 21:36:35 +02008652 return cfg80211_leave_ibss(rdev, dev, false);
Johannes Berg04a773a2009-04-19 21:24:32 +02008653}
8654
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008655static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
8656{
8657 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8658 struct net_device *dev = info->user_ptr[1];
Johannes Berg57fbcce2016-04-12 15:56:15 +02008659 int mcast_rate[NUM_NL80211_BANDS];
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008660 u32 nla_rate;
8661 int err;
8662
8663 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
Bertold Van den Bergh876dc932015-08-05 16:02:21 +02008664 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
8665 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008666 return -EOPNOTSUPP;
8667
8668 if (!rdev->ops->set_mcast_rate)
8669 return -EOPNOTSUPP;
8670
8671 memset(mcast_rate, 0, sizeof(mcast_rate));
8672
8673 if (!info->attrs[NL80211_ATTR_MCAST_RATE])
8674 return -EINVAL;
8675
8676 nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
8677 if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
8678 return -EINVAL;
8679
Ilan Peera1056b1b2015-10-22 22:27:46 +03008680 err = rdev_set_mcast_rate(rdev, dev, mcast_rate);
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008681
8682 return err;
8683}
8684
Johannes Bergad7e7182013-11-13 13:37:47 +01008685static struct sk_buff *
8686__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008687 struct wireless_dev *wdev, int approxlen,
8688 u32 portid, u32 seq, enum nl80211_commands cmd,
Johannes Berg567ffc32013-12-18 14:43:31 +01008689 enum nl80211_attrs attr,
8690 const struct nl80211_vendor_cmd_info *info,
8691 gfp_t gfp)
Johannes Bergad7e7182013-11-13 13:37:47 +01008692{
8693 struct sk_buff *skb;
8694 void *hdr;
8695 struct nlattr *data;
8696
8697 skb = nlmsg_new(approxlen + 100, gfp);
8698 if (!skb)
8699 return NULL;
8700
8701 hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
8702 if (!hdr) {
8703 kfree_skb(skb);
8704 return NULL;
8705 }
8706
8707 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
8708 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01008709
8710 if (info) {
8711 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
8712 info->vendor_id))
8713 goto nla_put_failure;
8714 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
8715 info->subcmd))
8716 goto nla_put_failure;
8717 }
8718
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008719 if (wdev) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008720 if (nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
8721 wdev_id(wdev), NL80211_ATTR_PAD))
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008722 goto nla_put_failure;
8723 if (wdev->netdev &&
8724 nla_put_u32(skb, NL80211_ATTR_IFINDEX,
8725 wdev->netdev->ifindex))
8726 goto nla_put_failure;
8727 }
8728
Johannes Bergad7e7182013-11-13 13:37:47 +01008729 data = nla_nest_start(skb, attr);
Johannes Berg76e1fb42016-09-14 09:55:57 +02008730 if (!data)
8731 goto nla_put_failure;
Johannes Bergad7e7182013-11-13 13:37:47 +01008732
8733 ((void **)skb->cb)[0] = rdev;
8734 ((void **)skb->cb)[1] = hdr;
8735 ((void **)skb->cb)[2] = data;
8736
8737 return skb;
8738
8739 nla_put_failure:
8740 kfree_skb(skb);
8741 return NULL;
8742}
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008743
Johannes Berge03ad6e2014-01-01 17:22:30 +01008744struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008745 struct wireless_dev *wdev,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008746 enum nl80211_commands cmd,
8747 enum nl80211_attrs attr,
8748 int vendor_event_idx,
8749 int approxlen, gfp_t gfp)
8750{
Zhao, Gangf26cbf42014-04-21 12:53:03 +08008751 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berge03ad6e2014-01-01 17:22:30 +01008752 const struct nl80211_vendor_cmd_info *info;
8753
8754 switch (cmd) {
8755 case NL80211_CMD_TESTMODE:
8756 if (WARN_ON(vendor_event_idx != -1))
8757 return NULL;
8758 info = NULL;
8759 break;
8760 case NL80211_CMD_VENDOR:
8761 if (WARN_ON(vendor_event_idx < 0 ||
8762 vendor_event_idx >= wiphy->n_vendor_events))
8763 return NULL;
8764 info = &wiphy->vendor_events[vendor_event_idx];
8765 break;
8766 default:
8767 WARN_ON(1);
8768 return NULL;
8769 }
8770
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008771 return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008772 cmd, attr, info, gfp);
8773}
8774EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
8775
8776void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
8777{
8778 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
8779 void *hdr = ((void **)skb->cb)[1];
8780 struct nlattr *data = ((void **)skb->cb)[2];
8781 enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
8782
Johannes Bergbd8c78e2014-07-30 14:55:26 +02008783 /* clear CB data for netlink core to own from now on */
8784 memset(skb->cb, 0, sizeof(skb->cb));
8785
Johannes Berge03ad6e2014-01-01 17:22:30 +01008786 nla_nest_end(skb, data);
8787 genlmsg_end(skb, hdr);
8788
8789 if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
8790 mcgrp = NL80211_MCGRP_VENDOR;
8791
8792 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
8793 mcgrp, gfp);
8794}
8795EXPORT_SYMBOL(__cfg80211_send_event_skb);
8796
Johannes Bergaff89a92009-07-01 21:26:51 +02008797#ifdef CONFIG_NL80211_TESTMODE
Johannes Bergaff89a92009-07-01 21:26:51 +02008798static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
8799{
Johannes Berg4c476992010-10-04 21:36:35 +02008800 struct cfg80211_registered_device *rdev = info->user_ptr[0];
David Spinadelfc73f112013-07-31 18:04:15 +03008801 struct wireless_dev *wdev =
8802 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
Johannes Bergaff89a92009-07-01 21:26:51 +02008803 int err;
8804
David Spinadelfc73f112013-07-31 18:04:15 +03008805 if (!rdev->ops->testmode_cmd)
8806 return -EOPNOTSUPP;
8807
8808 if (IS_ERR(wdev)) {
8809 err = PTR_ERR(wdev);
8810 if (err != -EINVAL)
8811 return err;
8812 wdev = NULL;
8813 } else if (wdev->wiphy != &rdev->wiphy) {
8814 return -EINVAL;
8815 }
8816
Johannes Bergaff89a92009-07-01 21:26:51 +02008817 if (!info->attrs[NL80211_ATTR_TESTDATA])
8818 return -EINVAL;
8819
Johannes Bergad7e7182013-11-13 13:37:47 +01008820 rdev->cur_cmd_info = info;
David Spinadelfc73f112013-07-31 18:04:15 +03008821 err = rdev_testmode_cmd(rdev, wdev,
Johannes Bergaff89a92009-07-01 21:26:51 +02008822 nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
8823 nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
Johannes Bergad7e7182013-11-13 13:37:47 +01008824 rdev->cur_cmd_info = NULL;
Johannes Bergaff89a92009-07-01 21:26:51 +02008825
Johannes Bergaff89a92009-07-01 21:26:51 +02008826 return err;
8827}
8828
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008829static int nl80211_testmode_dump(struct sk_buff *skb,
8830 struct netlink_callback *cb)
8831{
Johannes Berg00918d32011-12-13 17:22:05 +01008832 struct cfg80211_registered_device *rdev;
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008833 int err;
8834 long phy_idx;
8835 void *data = NULL;
8836 int data_len = 0;
8837
Johannes Berg5fe231e2013-05-08 21:45:15 +02008838 rtnl_lock();
8839
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008840 if (cb->args[0]) {
8841 /*
8842 * 0 is a valid index, but not valid for args[0],
8843 * so we need to offset by 1.
8844 */
8845 phy_idx = cb->args[0] - 1;
Luca Coelhoa4956dc2017-02-07 22:13:56 +02008846
8847 rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
8848 if (!rdev) {
8849 err = -ENOENT;
8850 goto out_err;
8851 }
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008852 } else {
Johannes Bergc90c39d2016-10-24 14:40:01 +02008853 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
8854
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008855 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergfceb6432017-04-12 14:34:07 +02008856 attrbuf, nl80211_fam.maxattr,
8857 nl80211_policy, NULL);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008858 if (err)
Johannes Berg5fe231e2013-05-08 21:45:15 +02008859 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01008860
Johannes Bergc90c39d2016-10-24 14:40:01 +02008861 rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg2bd7e352012-06-15 14:23:16 +02008862 if (IS_ERR(rdev)) {
Johannes Berg5fe231e2013-05-08 21:45:15 +02008863 err = PTR_ERR(rdev);
8864 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01008865 }
Johannes Berg2bd7e352012-06-15 14:23:16 +02008866 phy_idx = rdev->wiphy_idx;
Johannes Berg2bd7e352012-06-15 14:23:16 +02008867
Johannes Bergc90c39d2016-10-24 14:40:01 +02008868 if (attrbuf[NL80211_ATTR_TESTDATA])
8869 cb->args[1] = (long)attrbuf[NL80211_ATTR_TESTDATA];
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008870 }
8871
8872 if (cb->args[1]) {
8873 data = nla_data((void *)cb->args[1]);
8874 data_len = nla_len((void *)cb->args[1]);
8875 }
8876
Johannes Berg00918d32011-12-13 17:22:05 +01008877 if (!rdev->ops->testmode_dump) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008878 err = -EOPNOTSUPP;
8879 goto out_err;
8880 }
8881
8882 while (1) {
Eric W. Biederman15e47302012-09-07 20:12:54 +00008883 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008884 cb->nlh->nlmsg_seq, NLM_F_MULTI,
8885 NL80211_CMD_TESTMODE);
8886 struct nlattr *tmdata;
8887
Dan Carpentercb35fba2013-08-14 14:50:01 +03008888 if (!hdr)
8889 break;
8890
David S. Miller9360ffd2012-03-29 04:41:26 -04008891 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008892 genlmsg_cancel(skb, hdr);
8893 break;
8894 }
8895
8896 tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
8897 if (!tmdata) {
8898 genlmsg_cancel(skb, hdr);
8899 break;
8900 }
Hila Gonene35e4d22012-06-27 17:19:42 +03008901 err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008902 nla_nest_end(skb, tmdata);
8903
8904 if (err == -ENOBUFS || err == -ENOENT) {
8905 genlmsg_cancel(skb, hdr);
8906 break;
8907 } else if (err) {
8908 genlmsg_cancel(skb, hdr);
8909 goto out_err;
8910 }
8911
8912 genlmsg_end(skb, hdr);
8913 }
8914
8915 err = skb->len;
8916 /* see above */
8917 cb->args[0] = phy_idx + 1;
8918 out_err:
Johannes Berg5fe231e2013-05-08 21:45:15 +02008919 rtnl_unlock();
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008920 return err;
8921}
Johannes Bergaff89a92009-07-01 21:26:51 +02008922#endif
8923
Samuel Ortizb23aa672009-07-01 21:26:54 +02008924static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
8925{
Johannes Berg4c476992010-10-04 21:36:35 +02008926 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8927 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02008928 struct cfg80211_connect_params connect;
8929 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008930 struct cfg80211_cached_keys *connkeys = NULL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008931 int err;
8932
8933 memset(&connect, 0, sizeof(connect));
8934
8935 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8936 return -EINVAL;
8937
8938 if (!info->attrs[NL80211_ATTR_SSID] ||
8939 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8940 return -EINVAL;
8941
8942 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
8943 connect.auth_type =
8944 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03008945 if (!nl80211_valid_auth_type(rdev, connect.auth_type,
8946 NL80211_CMD_CONNECT))
Samuel Ortizb23aa672009-07-01 21:26:54 +02008947 return -EINVAL;
8948 } else
8949 connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
8950
8951 connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
8952
Avraham Stern3a00df52017-06-09 13:08:43 +01008953 if (info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS] &&
8954 !wiphy_ext_feature_isset(&rdev->wiphy,
8955 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
8956 return -EINVAL;
8957 connect.want_1x = info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS];
8958
Johannes Bergc0692b82010-08-27 14:26:53 +03008959 err = nl80211_crypto_settings(rdev, info, &connect.crypto,
Johannes Berg3dc27d22009-07-02 21:36:37 +02008960 NL80211_MAX_NR_CIPHER_SUITES);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008961 if (err)
8962 return err;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008963
Johannes Berg074ac8d2010-09-16 14:58:22 +02008964 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008965 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8966 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008967
Johannes Berg79c97e92009-07-07 03:56:12 +02008968 wiphy = &rdev->wiphy;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008969
Bala Shanmugam4486ea92012-03-07 17:27:12 +05308970 connect.bg_scan_period = -1;
8971 if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
8972 (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
8973 connect.bg_scan_period =
8974 nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
8975 }
8976
Samuel Ortizb23aa672009-07-01 21:26:54 +02008977 if (info->attrs[NL80211_ATTR_MAC])
8978 connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen1df4a512014-01-15 00:00:47 +02008979 else if (info->attrs[NL80211_ATTR_MAC_HINT])
8980 connect.bssid_hint =
8981 nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008982 connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8983 connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8984
8985 if (info->attrs[NL80211_ATTR_IE]) {
8986 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8987 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8988 }
8989
Jouni Malinencee00a92013-01-15 17:15:57 +02008990 if (info->attrs[NL80211_ATTR_USE_MFP]) {
8991 connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Emmanuel Grumbach65026002017-08-18 15:31:41 +03008992 if (connect.mfp == NL80211_MFP_OPTIONAL &&
8993 !wiphy_ext_feature_isset(&rdev->wiphy,
8994 NL80211_EXT_FEATURE_MFP_OPTIONAL))
8995 return -EOPNOTSUPP;
8996
Jouni Malinencee00a92013-01-15 17:15:57 +02008997 if (connect.mfp != NL80211_MFP_REQUIRED &&
Emmanuel Grumbach65026002017-08-18 15:31:41 +03008998 connect.mfp != NL80211_MFP_NO &&
8999 connect.mfp != NL80211_MFP_OPTIONAL)
Jouni Malinencee00a92013-01-15 17:15:57 +02009000 return -EINVAL;
9001 } else {
9002 connect.mfp = NL80211_MFP_NO;
9003 }
9004
Jouni Malinenba6fbac2016-03-29 13:53:27 +03009005 if (info->attrs[NL80211_ATTR_PREV_BSSID])
9006 connect.prev_bssid =
9007 nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
9008
Samuel Ortizb23aa672009-07-01 21:26:54 +02009009 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02009010 connect.channel = nl80211_get_valid_chan(
9011 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
9012 if (!connect.channel)
Johannes Berg4c476992010-10-04 21:36:35 +02009013 return -EINVAL;
Jouni Malinen1df4a512014-01-15 00:00:47 +02009014 } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02009015 connect.channel_hint = nl80211_get_valid_chan(
9016 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
9017 if (!connect.channel_hint)
Jouni Malinen1df4a512014-01-15 00:00:47 +02009018 return -EINVAL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009019 }
9020
Johannes Bergfffd0932009-07-08 14:22:54 +02009021 if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
9022 connkeys = nl80211_parse_connkeys(rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +05309023 info->attrs[NL80211_ATTR_KEYS], NULL);
Johannes Berg4c476992010-10-04 21:36:35 +02009024 if (IS_ERR(connkeys))
9025 return PTR_ERR(connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02009026 }
9027
Ben Greear7e7c8922011-11-18 11:31:59 -08009028 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
9029 connect.flags |= ASSOC_REQ_DISABLE_HT;
9030
9031 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
9032 memcpy(&connect.ht_capa_mask,
9033 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
9034 sizeof(connect.ht_capa_mask));
9035
9036 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Wei Yongjunb4e4f472012-09-02 21:41:04 +08009037 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03009038 kzfree(connkeys);
Ben Greear7e7c8922011-11-18 11:31:59 -08009039 return -EINVAL;
Wei Yongjunb4e4f472012-09-02 21:41:04 +08009040 }
Ben Greear7e7c8922011-11-18 11:31:59 -08009041 memcpy(&connect.ht_capa,
9042 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
9043 sizeof(connect.ht_capa));
9044 }
9045
Johannes Bergee2aca32013-02-21 17:36:01 +01009046 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
9047 connect.flags |= ASSOC_REQ_DISABLE_VHT;
9048
9049 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
9050 memcpy(&connect.vht_capa_mask,
9051 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
9052 sizeof(connect.vht_capa_mask));
9053
9054 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
9055 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03009056 kzfree(connkeys);
Johannes Bergee2aca32013-02-21 17:36:01 +01009057 return -EINVAL;
9058 }
9059 memcpy(&connect.vht_capa,
9060 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
9061 sizeof(connect.vht_capa));
9062 }
9063
Assaf Kraussbab5ab72014-09-03 15:25:01 +03009064 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02009065 if (!((rdev->wiphy.features &
9066 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
9067 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
9068 !wiphy_ext_feature_isset(&rdev->wiphy,
9069 NL80211_EXT_FEATURE_RRM)) {
Ola Olsson707554b2015-12-11 21:04:52 +01009070 kzfree(connkeys);
Assaf Kraussbab5ab72014-09-03 15:25:01 +03009071 return -EINVAL;
Ola Olsson707554b2015-12-11 21:04:52 +01009072 }
Assaf Kraussbab5ab72014-09-03 15:25:01 +03009073 connect.flags |= ASSOC_REQ_USE_RRM;
9074 }
9075
Lior David34d50512016-01-28 10:58:25 +02009076 connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
Johannes Berg57fbcce2016-04-12 15:56:15 +02009077 if (connect.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
Lior David34d50512016-01-28 10:58:25 +02009078 kzfree(connkeys);
9079 return -EOPNOTSUPP;
9080 }
9081
Arend van Spriel38de03d2016-03-02 20:37:18 +01009082 if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
9083 /* bss selection makes no sense if bssid is set */
9084 if (connect.bssid) {
9085 kzfree(connkeys);
9086 return -EINVAL;
9087 }
9088
9089 err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
9090 wiphy, &connect.bss_select);
9091 if (err) {
9092 kzfree(connkeys);
9093 return err;
9094 }
9095 }
9096
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03009097 if (wiphy_ext_feature_isset(&rdev->wiphy,
9098 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
9099 info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
9100 info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
9101 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
9102 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
9103 connect.fils_erp_username =
9104 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
9105 connect.fils_erp_username_len =
9106 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
9107 connect.fils_erp_realm =
9108 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
9109 connect.fils_erp_realm_len =
9110 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
9111 connect.fils_erp_next_seq_num =
9112 nla_get_u16(
9113 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
9114 connect.fils_erp_rrk =
9115 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
9116 connect.fils_erp_rrk_len =
9117 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
9118 } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
9119 info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
9120 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
9121 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
9122 kzfree(connkeys);
9123 return -EINVAL;
9124 }
9125
Johannes Berg83739b02013-05-15 17:44:01 +02009126 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05009127
Jouni Malinen4ce2bd9c42016-03-29 13:53:28 +03009128 err = cfg80211_connect(rdev, dev, &connect, connkeys,
9129 connect.prev_bssid);
Johannes Bergfffd0932009-07-08 14:22:54 +02009130 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03009131 kzfree(connkeys);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05009132
9133 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
9134 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
9135 if (connect.bssid)
9136 memcpy(dev->ieee80211_ptr->disconnect_bssid,
9137 connect.bssid, ETH_ALEN);
9138 else
9139 memset(dev->ieee80211_ptr->disconnect_bssid,
9140 0, ETH_ALEN);
9141 }
9142
9143 wdev_unlock(dev->ieee80211_ptr);
9144
Samuel Ortizb23aa672009-07-01 21:26:54 +02009145 return err;
9146}
9147
vamsi krishna088e8df2016-10-27 16:51:11 +03009148static int nl80211_update_connect_params(struct sk_buff *skb,
9149 struct genl_info *info)
9150{
9151 struct cfg80211_connect_params connect = {};
9152 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9153 struct net_device *dev = info->user_ptr[1];
9154 struct wireless_dev *wdev = dev->ieee80211_ptr;
9155 u32 changed = 0;
9156 int ret;
9157
9158 if (!rdev->ops->update_connect_params)
9159 return -EOPNOTSUPP;
9160
9161 if (info->attrs[NL80211_ATTR_IE]) {
9162 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
9163 return -EINVAL;
9164 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
9165 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9166 changed |= UPDATE_ASSOC_IES;
9167 }
9168
9169 wdev_lock(dev->ieee80211_ptr);
9170 if (!wdev->current_bss)
9171 ret = -ENOLINK;
9172 else
9173 ret = rdev_update_connect_params(rdev, dev, &connect, changed);
9174 wdev_unlock(dev->ieee80211_ptr);
9175
9176 return ret;
9177}
9178
Samuel Ortizb23aa672009-07-01 21:26:54 +02009179static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
9180{
Johannes Berg4c476992010-10-04 21:36:35 +02009181 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9182 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02009183 u16 reason;
Johannes Berg83739b02013-05-15 17:44:01 +02009184 int ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009185
9186 if (!info->attrs[NL80211_ATTR_REASON_CODE])
9187 reason = WLAN_REASON_DEAUTH_LEAVING;
9188 else
9189 reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
9190
9191 if (reason == 0)
9192 return -EINVAL;
9193
Johannes Berg074ac8d2010-09-16 14:58:22 +02009194 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009195 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9196 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009197
Johannes Berg83739b02013-05-15 17:44:01 +02009198 wdev_lock(dev->ieee80211_ptr);
9199 ret = cfg80211_disconnect(rdev, dev, reason, true);
9200 wdev_unlock(dev->ieee80211_ptr);
9201 return ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009202}
9203
Johannes Berg463d0182009-07-14 00:33:35 +02009204static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
9205{
Johannes Berg4c476992010-10-04 21:36:35 +02009206 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg463d0182009-07-14 00:33:35 +02009207 struct net *net;
9208 int err;
Johannes Berg463d0182009-07-14 00:33:35 +02009209
Vadim Kochan4b681c82015-01-12 16:34:05 +02009210 if (info->attrs[NL80211_ATTR_PID]) {
9211 u32 pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
9212
9213 net = get_net_ns_by_pid(pid);
9214 } else if (info->attrs[NL80211_ATTR_NETNS_FD]) {
9215 u32 fd = nla_get_u32(info->attrs[NL80211_ATTR_NETNS_FD]);
9216
9217 net = get_net_ns_by_fd(fd);
9218 } else {
Johannes Berg463d0182009-07-14 00:33:35 +02009219 return -EINVAL;
Vadim Kochan4b681c82015-01-12 16:34:05 +02009220 }
Johannes Berg463d0182009-07-14 00:33:35 +02009221
Johannes Berg4c476992010-10-04 21:36:35 +02009222 if (IS_ERR(net))
9223 return PTR_ERR(net);
Johannes Berg463d0182009-07-14 00:33:35 +02009224
9225 err = 0;
9226
9227 /* check if anything to do */
Johannes Berg4c476992010-10-04 21:36:35 +02009228 if (!net_eq(wiphy_net(&rdev->wiphy), net))
9229 err = cfg80211_switch_netns(rdev, net);
Johannes Berg463d0182009-07-14 00:33:35 +02009230
Johannes Berg463d0182009-07-14 00:33:35 +02009231 put_net(net);
Johannes Berg463d0182009-07-14 00:33:35 +02009232 return err;
9233}
9234
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009235static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
9236{
Johannes Berg4c476992010-10-04 21:36:35 +02009237 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009238 int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
9239 struct cfg80211_pmksa *pmksa) = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02009240 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009241 struct cfg80211_pmksa pmksa;
9242
9243 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
9244
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009245 if (!info->attrs[NL80211_ATTR_PMKID])
9246 return -EINVAL;
9247
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009248 pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03009249
9250 if (info->attrs[NL80211_ATTR_MAC]) {
9251 pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9252 } else if (info->attrs[NL80211_ATTR_SSID] &&
9253 info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
9254 (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
9255 info->attrs[NL80211_ATTR_PMK])) {
9256 pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9257 pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9258 pmksa.cache_id =
9259 nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
9260 } else {
9261 return -EINVAL;
9262 }
9263 if (info->attrs[NL80211_ATTR_PMK]) {
9264 pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
9265 pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
9266 }
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009267
Johannes Berg074ac8d2010-09-16 14:58:22 +02009268 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009269 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9270 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009271
9272 switch (info->genlhdr->cmd) {
9273 case NL80211_CMD_SET_PMKSA:
9274 rdev_ops = rdev->ops->set_pmksa;
9275 break;
9276 case NL80211_CMD_DEL_PMKSA:
9277 rdev_ops = rdev->ops->del_pmksa;
9278 break;
9279 default:
9280 WARN_ON(1);
9281 break;
9282 }
9283
Johannes Berg4c476992010-10-04 21:36:35 +02009284 if (!rdev_ops)
9285 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009286
Johannes Berg4c476992010-10-04 21:36:35 +02009287 return rdev_ops(&rdev->wiphy, dev, &pmksa);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009288}
9289
9290static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
9291{
Johannes Berg4c476992010-10-04 21:36:35 +02009292 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9293 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009294
Johannes Berg074ac8d2010-09-16 14:58:22 +02009295 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009296 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9297 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009298
Johannes Berg4c476992010-10-04 21:36:35 +02009299 if (!rdev->ops->flush_pmksa)
9300 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009301
Hila Gonene35e4d22012-06-27 17:19:42 +03009302 return rdev_flush_pmksa(rdev, dev);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009303}
9304
Arik Nemtsov109086c2011-09-28 14:12:50 +03009305static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
9306{
9307 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9308 struct net_device *dev = info->user_ptr[1];
9309 u8 action_code, dialog_token;
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309310 u32 peer_capability = 0;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009311 u16 status_code;
9312 u8 *peer;
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009313 bool initiator;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009314
9315 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9316 !rdev->ops->tdls_mgmt)
9317 return -EOPNOTSUPP;
9318
9319 if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
9320 !info->attrs[NL80211_ATTR_STATUS_CODE] ||
9321 !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
9322 !info->attrs[NL80211_ATTR_IE] ||
9323 !info->attrs[NL80211_ATTR_MAC])
9324 return -EINVAL;
9325
9326 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9327 action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
9328 status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
9329 dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009330 initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]);
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309331 if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
9332 peer_capability =
9333 nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009334
Hila Gonene35e4d22012-06-27 17:19:42 +03009335 return rdev_tdls_mgmt(rdev, dev, peer, action_code,
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309336 dialog_token, status_code, peer_capability,
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009337 initiator,
Hila Gonene35e4d22012-06-27 17:19:42 +03009338 nla_data(info->attrs[NL80211_ATTR_IE]),
9339 nla_len(info->attrs[NL80211_ATTR_IE]));
Arik Nemtsov109086c2011-09-28 14:12:50 +03009340}
9341
9342static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
9343{
9344 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9345 struct net_device *dev = info->user_ptr[1];
9346 enum nl80211_tdls_operation operation;
9347 u8 *peer;
9348
9349 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9350 !rdev->ops->tdls_oper)
9351 return -EOPNOTSUPP;
9352
9353 if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
9354 !info->attrs[NL80211_ATTR_MAC])
9355 return -EINVAL;
9356
9357 operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
9358 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9359
Hila Gonene35e4d22012-06-27 17:19:42 +03009360 return rdev_tdls_oper(rdev, dev, peer, operation);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009361}
9362
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009363static int nl80211_remain_on_channel(struct sk_buff *skb,
9364 struct genl_info *info)
9365{
Johannes Berg4c476992010-10-04 21:36:35 +02009366 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009367 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009368 struct cfg80211_chan_def chandef;
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05309369 const struct cfg80211_chan_def *compat_chandef;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009370 struct sk_buff *msg;
9371 void *hdr;
9372 u64 cookie;
Johannes Berg683b6d32012-11-08 21:25:48 +01009373 u32 duration;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009374 int err;
9375
9376 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
9377 !info->attrs[NL80211_ATTR_DURATION])
9378 return -EINVAL;
9379
9380 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
9381
Johannes Berg7c4ef712011-11-18 15:33:48 +01009382 if (!rdev->ops->remain_on_channel ||
9383 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
Johannes Berg4c476992010-10-04 21:36:35 +02009384 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009385
Johannes Bergebf348f2012-06-01 12:50:54 +02009386 /*
9387 * We should be on that channel for at least a minimum amount of
9388 * time (10ms) but no longer than the driver supports.
9389 */
9390 if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9391 duration > rdev->wiphy.max_remain_on_channel_duration)
9392 return -EINVAL;
9393
Johannes Berg683b6d32012-11-08 21:25:48 +01009394 err = nl80211_parse_chandef(rdev, info, &chandef);
9395 if (err)
9396 return err;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009397
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05309398 wdev_lock(wdev);
9399 if (!cfg80211_off_channel_oper_allowed(wdev) &&
9400 !cfg80211_chandef_identical(&wdev->chandef, &chandef)) {
9401 compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
9402 &chandef);
9403 if (compat_chandef != &chandef) {
9404 wdev_unlock(wdev);
9405 return -EBUSY;
9406 }
9407 }
9408 wdev_unlock(wdev);
9409
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009410 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009411 if (!msg)
9412 return -ENOMEM;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009413
Eric W. Biederman15e47302012-09-07 20:12:54 +00009414 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009415 NL80211_CMD_REMAIN_ON_CHANNEL);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009416 if (!hdr) {
9417 err = -ENOBUFS;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009418 goto free_msg;
9419 }
9420
Johannes Berg683b6d32012-11-08 21:25:48 +01009421 err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
9422 duration, &cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009423
9424 if (err)
9425 goto free_msg;
9426
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009427 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9428 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009429 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009430
9431 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009432
9433 return genlmsg_reply(msg, info);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009434
9435 nla_put_failure:
9436 err = -ENOBUFS;
9437 free_msg:
9438 nlmsg_free(msg);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009439 return err;
9440}
9441
9442static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
9443 struct genl_info *info)
9444{
Johannes Berg4c476992010-10-04 21:36:35 +02009445 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009446 struct wireless_dev *wdev = info->user_ptr[1];
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009447 u64 cookie;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009448
9449 if (!info->attrs[NL80211_ATTR_COOKIE])
9450 return -EINVAL;
9451
Johannes Berg4c476992010-10-04 21:36:35 +02009452 if (!rdev->ops->cancel_remain_on_channel)
9453 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009454
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009455 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9456
Hila Gonene35e4d22012-06-27 17:19:42 +03009457 return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009458}
9459
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009460static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
9461 struct genl_info *info)
9462{
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009463 struct cfg80211_bitrate_mask mask;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309464 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009465 struct net_device *dev = info->user_ptr[1];
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309466 int err;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009467
Johannes Berg4c476992010-10-04 21:36:35 +02009468 if (!rdev->ops->set_bitrate_mask)
9469 return -EOPNOTSUPP;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009470
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309471 err = nl80211_parse_tx_bitrate_mask(info, &mask);
9472 if (err)
9473 return err;
Janusz Dziedzic78693032013-12-03 09:50:44 +01009474
Hila Gonene35e4d22012-06-27 17:19:42 +03009475 return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009476}
9477
Johannes Berg2e161f72010-08-12 15:38:38 +02009478static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009479{
Johannes Berg4c476992010-10-04 21:36:35 +02009480 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009481 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2e161f72010-08-12 15:38:38 +02009482 u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
Jouni Malinen026331c2010-02-15 12:53:10 +02009483
9484 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
9485 return -EINVAL;
9486
Johannes Berg2e161f72010-08-12 15:38:38 +02009487 if (info->attrs[NL80211_ATTR_FRAME_TYPE])
9488 frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
Jouni Malinen026331c2010-02-15 12:53:10 +02009489
Johannes Berg71bbc992012-06-15 15:30:18 +02009490 switch (wdev->iftype) {
9491 case NL80211_IFTYPE_STATION:
9492 case NL80211_IFTYPE_ADHOC:
9493 case NL80211_IFTYPE_P2P_CLIENT:
9494 case NL80211_IFTYPE_AP:
9495 case NL80211_IFTYPE_AP_VLAN:
9496 case NL80211_IFTYPE_MESH_POINT:
9497 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009498 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009499 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009500 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009501 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009502 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009503 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009504
9505 /* not much point in registering if we can't reply */
Johannes Berg4c476992010-10-04 21:36:35 +02009506 if (!rdev->ops->mgmt_tx)
9507 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009508
Eric W. Biederman15e47302012-09-07 20:12:54 +00009509 return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
Jouni Malinen026331c2010-02-15 12:53:10 +02009510 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
9511 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
Jouni Malinen026331c2010-02-15 12:53:10 +02009512}
9513
Johannes Berg2e161f72010-08-12 15:38:38 +02009514static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009515{
Johannes Berg4c476992010-10-04 21:36:35 +02009516 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009517 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009518 struct cfg80211_chan_def chandef;
Jouni Malinen026331c2010-02-15 12:53:10 +02009519 int err;
Johannes Bergd64d3732011-11-10 09:44:46 +01009520 void *hdr = NULL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009521 u64 cookie;
Johannes Berge247bd902011-11-04 11:18:21 +01009522 struct sk_buff *msg = NULL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009523 struct cfg80211_mgmt_tx_params params = {
9524 .dont_wait_for_ack =
9525 info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
9526 };
Jouni Malinen026331c2010-02-15 12:53:10 +02009527
Johannes Berg683b6d32012-11-08 21:25:48 +01009528 if (!info->attrs[NL80211_ATTR_FRAME])
Jouni Malinen026331c2010-02-15 12:53:10 +02009529 return -EINVAL;
9530
Johannes Berg4c476992010-10-04 21:36:35 +02009531 if (!rdev->ops->mgmt_tx)
9532 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009533
Johannes Berg71bbc992012-06-15 15:30:18 +02009534 switch (wdev->iftype) {
Antonio Quartulliea141b752013-06-11 14:20:03 +02009535 case NL80211_IFTYPE_P2P_DEVICE:
9536 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
9537 return -EINVAL;
Johannes Berg71bbc992012-06-15 15:30:18 +02009538 case NL80211_IFTYPE_STATION:
9539 case NL80211_IFTYPE_ADHOC:
9540 case NL80211_IFTYPE_P2P_CLIENT:
9541 case NL80211_IFTYPE_AP:
9542 case NL80211_IFTYPE_AP_VLAN:
9543 case NL80211_IFTYPE_MESH_POINT:
9544 case NL80211_IFTYPE_P2P_GO:
9545 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009546 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009547 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009548 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009549 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009550
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009551 if (info->attrs[NL80211_ATTR_DURATION]) {
Johannes Berg7c4ef712011-11-18 15:33:48 +01009552 if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009553 return -EINVAL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009554 params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
Johannes Bergebf348f2012-06-01 12:50:54 +02009555
9556 /*
9557 * We should wait on the channel for at least a minimum amount
9558 * of time (10ms) but no longer than the driver supports.
9559 */
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009560 if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9561 params.wait > rdev->wiphy.max_remain_on_channel_duration)
Johannes Bergebf348f2012-06-01 12:50:54 +02009562 return -EINVAL;
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009563 }
9564
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009565 params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009566
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009567 if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Berg7c4ef712011-11-18 15:33:48 +01009568 return -EINVAL;
9569
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009570 params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05309571
Antonio Quartulliea141b752013-06-11 14:20:03 +02009572 /* get the channel if any has been specified, otherwise pass NULL to
9573 * the driver. The latter will use the current one
9574 */
9575 chandef.chan = NULL;
9576 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
9577 err = nl80211_parse_chandef(rdev, info, &chandef);
9578 if (err)
9579 return err;
9580 }
9581
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009582 if (!chandef.chan && params.offchan)
Antonio Quartulliea141b752013-06-11 14:20:03 +02009583 return -EINVAL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009584
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05309585 wdev_lock(wdev);
9586 if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) {
9587 wdev_unlock(wdev);
9588 return -EBUSY;
9589 }
9590 wdev_unlock(wdev);
9591
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +03009592 params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
9593 params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
9594
9595 if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
9596 int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9597 int i;
9598
9599 if (len % sizeof(u16))
9600 return -EINVAL;
9601
9602 params.n_csa_offsets = len / sizeof(u16);
9603 params.csa_offsets =
9604 nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9605
9606 /* check that all the offsets fit the frame */
9607 for (i = 0; i < params.n_csa_offsets; i++) {
9608 if (params.csa_offsets[i] >= params.len)
9609 return -EINVAL;
9610 }
9611 }
9612
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009613 if (!params.dont_wait_for_ack) {
Johannes Berge247bd902011-11-04 11:18:21 +01009614 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9615 if (!msg)
9616 return -ENOMEM;
Jouni Malinen026331c2010-02-15 12:53:10 +02009617
Eric W. Biederman15e47302012-09-07 20:12:54 +00009618 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berge247bd902011-11-04 11:18:21 +01009619 NL80211_CMD_FRAME);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009620 if (!hdr) {
9621 err = -ENOBUFS;
Johannes Berge247bd902011-11-04 11:18:21 +01009622 goto free_msg;
9623 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009624 }
Johannes Berge247bd902011-11-04 11:18:21 +01009625
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009626 params.chan = chandef.chan;
9627 err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
Jouni Malinen026331c2010-02-15 12:53:10 +02009628 if (err)
9629 goto free_msg;
9630
Johannes Berge247bd902011-11-04 11:18:21 +01009631 if (msg) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009632 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9633 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009634 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +02009635
Johannes Berge247bd902011-11-04 11:18:21 +01009636 genlmsg_end(msg, hdr);
9637 return genlmsg_reply(msg, info);
9638 }
9639
9640 return 0;
Jouni Malinen026331c2010-02-15 12:53:10 +02009641
9642 nla_put_failure:
9643 err = -ENOBUFS;
9644 free_msg:
9645 nlmsg_free(msg);
Jouni Malinen026331c2010-02-15 12:53:10 +02009646 return err;
9647}
9648
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009649static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
9650{
9651 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009652 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009653 u64 cookie;
9654
9655 if (!info->attrs[NL80211_ATTR_COOKIE])
9656 return -EINVAL;
9657
9658 if (!rdev->ops->mgmt_tx_cancel_wait)
9659 return -EOPNOTSUPP;
9660
Johannes Berg71bbc992012-06-15 15:30:18 +02009661 switch (wdev->iftype) {
9662 case NL80211_IFTYPE_STATION:
9663 case NL80211_IFTYPE_ADHOC:
9664 case NL80211_IFTYPE_P2P_CLIENT:
9665 case NL80211_IFTYPE_AP:
9666 case NL80211_IFTYPE_AP_VLAN:
9667 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009668 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009669 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009670 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009671 default:
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009672 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009673 }
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009674
9675 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9676
Hila Gonene35e4d22012-06-27 17:19:42 +03009677 return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009678}
9679
Kalle Valoffb9eb32010-02-17 17:58:10 +02009680static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
9681{
Johannes Berg4c476992010-10-04 21:36:35 +02009682 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009683 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009684 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009685 u8 ps_state;
9686 bool state;
9687 int err;
9688
Johannes Berg4c476992010-10-04 21:36:35 +02009689 if (!info->attrs[NL80211_ATTR_PS_STATE])
9690 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009691
9692 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
9693
Johannes Berg4c476992010-10-04 21:36:35 +02009694 if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
9695 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009696
9697 wdev = dev->ieee80211_ptr;
9698
Johannes Berg4c476992010-10-04 21:36:35 +02009699 if (!rdev->ops->set_power_mgmt)
9700 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009701
9702 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
9703
9704 if (state == wdev->ps)
Johannes Berg4c476992010-10-04 21:36:35 +02009705 return 0;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009706
Hila Gonene35e4d22012-06-27 17:19:42 +03009707 err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
Johannes Berg4c476992010-10-04 21:36:35 +02009708 if (!err)
9709 wdev->ps = state;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009710 return err;
9711}
9712
9713static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
9714{
Johannes Berg4c476992010-10-04 21:36:35 +02009715 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009716 enum nl80211_ps_state ps_state;
9717 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009718 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009719 struct sk_buff *msg;
9720 void *hdr;
9721 int err;
9722
Kalle Valoffb9eb32010-02-17 17:58:10 +02009723 wdev = dev->ieee80211_ptr;
9724
Johannes Berg4c476992010-10-04 21:36:35 +02009725 if (!rdev->ops->set_power_mgmt)
9726 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009727
9728 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009729 if (!msg)
9730 return -ENOMEM;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009731
Eric W. Biederman15e47302012-09-07 20:12:54 +00009732 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Kalle Valoffb9eb32010-02-17 17:58:10 +02009733 NL80211_CMD_GET_POWER_SAVE);
9734 if (!hdr) {
Johannes Berg4c476992010-10-04 21:36:35 +02009735 err = -ENOBUFS;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009736 goto free_msg;
9737 }
9738
9739 if (wdev->ps)
9740 ps_state = NL80211_PS_ENABLED;
9741 else
9742 ps_state = NL80211_PS_DISABLED;
9743
David S. Miller9360ffd2012-03-29 04:41:26 -04009744 if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
9745 goto nla_put_failure;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009746
9747 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009748 return genlmsg_reply(msg, info);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009749
Johannes Berg4c476992010-10-04 21:36:35 +02009750 nla_put_failure:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009751 err = -ENOBUFS;
Johannes Berg4c476992010-10-04 21:36:35 +02009752 free_msg:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009753 nlmsg_free(msg);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009754 return err;
9755}
9756
Johannes Berg94e860f2014-01-20 23:58:15 +01009757static const struct nla_policy
9758nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009759 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009760 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
9761 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
Thomas Pedersen84f10702012-07-12 16:17:33 -07009762 [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
9763 [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
9764 [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +01009765 [NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009766};
9767
Thomas Pedersen84f10702012-07-12 16:17:33 -07009768static int nl80211_set_cqm_txe(struct genl_info *info,
Johannes Bergd9d8b012012-11-26 12:51:52 +01009769 u32 rate, u32 pkts, u32 intvl)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009770{
9771 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Thomas Pedersen84f10702012-07-12 16:17:33 -07009772 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009773 struct wireless_dev *wdev = dev->ieee80211_ptr;
Thomas Pedersen84f10702012-07-12 16:17:33 -07009774
Johannes Bergd9d8b012012-11-26 12:51:52 +01009775 if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009776 return -EINVAL;
9777
Thomas Pedersen84f10702012-07-12 16:17:33 -07009778 if (!rdev->ops->set_cqm_txe_config)
9779 return -EOPNOTSUPP;
9780
9781 if (wdev->iftype != NL80211_IFTYPE_STATION &&
9782 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9783 return -EOPNOTSUPP;
9784
Hila Gonene35e4d22012-06-27 17:19:42 +03009785 return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
Thomas Pedersen84f10702012-07-12 16:17:33 -07009786}
9787
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009788static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
9789 struct net_device *dev)
9790{
9791 struct wireless_dev *wdev = dev->ieee80211_ptr;
9792 s32 last, low, high;
9793 u32 hyst;
9794 int i, n;
9795 int err;
9796
9797 /* RSSI reporting disabled? */
9798 if (!wdev->cqm_config)
9799 return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
9800
9801 /*
9802 * Obtain current RSSI value if possible, if not and no RSSI threshold
9803 * event has been received yet, we should receive an event after a
9804 * connection is established and enough beacons received to calculate
9805 * the average.
9806 */
9807 if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
9808 rdev->ops->get_station) {
9809 struct station_info sinfo;
9810 u8 *mac_addr;
9811
9812 mac_addr = wdev->current_bss->pub.bssid;
9813
9814 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
9815 if (err)
9816 return err;
9817
9818 if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
9819 wdev->cqm_config->last_rssi_event_value =
9820 (s8) sinfo.rx_beacon_signal_avg;
9821 }
9822
9823 last = wdev->cqm_config->last_rssi_event_value;
9824 hyst = wdev->cqm_config->rssi_hyst;
9825 n = wdev->cqm_config->n_rssi_thresholds;
9826
9827 for (i = 0; i < n; i++)
9828 if (last < wdev->cqm_config->rssi_thresholds[i])
9829 break;
9830
9831 low = i > 0 ?
9832 (wdev->cqm_config->rssi_thresholds[i - 1] - hyst) : S32_MIN;
9833 high = i < n ?
9834 (wdev->cqm_config->rssi_thresholds[i] + hyst - 1) : S32_MAX;
9835
9836 return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
9837}
9838
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009839static int nl80211_set_cqm_rssi(struct genl_info *info,
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009840 const s32 *thresholds, int n_thresholds,
9841 u32 hysteresis)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009842{
Johannes Berg4c476992010-10-04 21:36:35 +02009843 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009844 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009845 struct wireless_dev *wdev = dev->ieee80211_ptr;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009846 int i, err;
9847 s32 prev = S32_MIN;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009848
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009849 /* Check all values negative and sorted */
9850 for (i = 0; i < n_thresholds; i++) {
9851 if (thresholds[i] > 0 || thresholds[i] <= prev)
9852 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009853
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009854 prev = thresholds[i];
9855 }
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009856
Johannes Berg074ac8d2010-09-16 14:58:22 +02009857 if (wdev->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009858 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9859 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009860
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009861 wdev_lock(wdev);
9862 cfg80211_cqm_config_free(wdev);
9863 wdev_unlock(wdev);
9864
9865 if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
9866 if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
9867 return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
9868
9869 return rdev_set_cqm_rssi_config(rdev, dev,
9870 thresholds[0], hysteresis);
9871 }
9872
9873 if (!wiphy_ext_feature_isset(&rdev->wiphy,
9874 NL80211_EXT_FEATURE_CQM_RSSI_LIST))
9875 return -EOPNOTSUPP;
9876
9877 if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */
9878 n_thresholds = 0;
9879
9880 wdev_lock(wdev);
9881 if (n_thresholds) {
9882 struct cfg80211_cqm_config *cqm_config;
9883
9884 cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
9885 n_thresholds * sizeof(s32), GFP_KERNEL);
9886 if (!cqm_config) {
9887 err = -ENOMEM;
9888 goto unlock;
9889 }
9890
9891 cqm_config->rssi_hyst = hysteresis;
9892 cqm_config->n_rssi_thresholds = n_thresholds;
9893 memcpy(cqm_config->rssi_thresholds, thresholds,
9894 n_thresholds * sizeof(s32));
9895
9896 wdev->cqm_config = cqm_config;
9897 }
9898
9899 err = cfg80211_cqm_rssi_update(rdev, dev);
9900
9901unlock:
9902 wdev_unlock(wdev);
9903
9904 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009905}
9906
9907static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
9908{
9909 struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
9910 struct nlattr *cqm;
9911 int err;
9912
9913 cqm = info->attrs[NL80211_ATTR_CQM];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009914 if (!cqm)
9915 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009916
9917 err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
Johannes Bergfe521452017-04-12 14:34:08 +02009918 nl80211_attr_cqm_policy, info->extack);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009919 if (err)
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009920 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009921
9922 if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
9923 attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009924 const s32 *thresholds =
9925 nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
9926 int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009927 u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009928
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009929 if (len % 4)
9930 return -EINVAL;
9931
9932 return nl80211_set_cqm_rssi(info, thresholds, len / 4,
9933 hysteresis);
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009934 }
9935
9936 if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
9937 attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
9938 attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
9939 u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
9940 u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
9941 u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
9942
9943 return nl80211_set_cqm_txe(info, rate, pkts, intvl);
9944 }
9945
9946 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009947}
9948
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01009949static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
9950{
9951 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9952 struct net_device *dev = info->user_ptr[1];
9953 struct ocb_setup setup = {};
9954 int err;
9955
9956 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
9957 if (err)
9958 return err;
9959
9960 return cfg80211_join_ocb(rdev, dev, &setup);
9961}
9962
9963static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
9964{
9965 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9966 struct net_device *dev = info->user_ptr[1];
9967
9968 return cfg80211_leave_ocb(rdev, dev);
9969}
9970
Johannes Berg29cbe682010-12-03 09:20:44 +01009971static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
9972{
9973 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9974 struct net_device *dev = info->user_ptr[1];
9975 struct mesh_config cfg;
Javier Cardonac80d5452010-12-16 17:37:49 -08009976 struct mesh_setup setup;
Johannes Berg29cbe682010-12-03 09:20:44 +01009977 int err;
9978
9979 /* start with default */
9980 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
Javier Cardonac80d5452010-12-16 17:37:49 -08009981 memcpy(&setup, &default_mesh_setup, sizeof(setup));
Johannes Berg29cbe682010-12-03 09:20:44 +01009982
Javier Cardona24bdd9f2010-12-16 17:37:48 -08009983 if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01009984 /* and parse parameters if given */
Javier Cardona24bdd9f2010-12-16 17:37:48 -08009985 err = nl80211_parse_mesh_config(info, &cfg, NULL);
Johannes Berg29cbe682010-12-03 09:20:44 +01009986 if (err)
9987 return err;
9988 }
9989
9990 if (!info->attrs[NL80211_ATTR_MESH_ID] ||
9991 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
9992 return -EINVAL;
9993
Javier Cardonac80d5452010-12-16 17:37:49 -08009994 setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
9995 setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
9996
Chun-Yeow Yeoh4bb62342011-11-24 17:15:20 -08009997 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
9998 !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
9999 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
10000 return -EINVAL;
10001
Marco Porsch9bdbf042013-01-07 16:04:51 +010010002 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
10003 setup.beacon_interval =
10004 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053010005
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +053010006 err = cfg80211_validate_beacon_int(rdev,
10007 NL80211_IFTYPE_MESH_POINT,
10008 setup.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +053010009 if (err)
10010 return err;
Marco Porsch9bdbf042013-01-07 16:04:51 +010010011 }
10012
10013 if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
10014 setup.dtim_period =
10015 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
10016 if (setup.dtim_period < 1 || setup.dtim_period > 100)
10017 return -EINVAL;
10018 }
10019
Javier Cardonac80d5452010-12-16 17:37:49 -080010020 if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
10021 /* parse additional setup parameters if given */
10022 err = nl80211_parse_mesh_setup(info, &setup);
10023 if (err)
10024 return err;
10025 }
10026
Thomas Pedersend37bb182013-03-04 13:06:13 -080010027 if (setup.user_mpm)
10028 cfg.auto_open_plinks = false;
10029
Johannes Bergcc1d2802012-05-16 23:50:20 +020010030 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +010010031 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
10032 if (err)
10033 return err;
Johannes Bergcc1d2802012-05-16 23:50:20 +020010034 } else {
10035 /* cfg80211_join_mesh() will sort it out */
Johannes Berg683b6d32012-11-08 21:25:48 +010010036 setup.chandef.chan = NULL;
Johannes Bergcc1d2802012-05-16 23:50:20 +020010037 }
10038
Ashok Nagarajanffb3cf32013-06-03 10:33:36 -070010039 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
10040 u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
10041 int n_rates =
10042 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
10043 struct ieee80211_supported_band *sband;
10044
10045 if (!setup.chandef.chan)
10046 return -EINVAL;
10047
10048 sband = rdev->wiphy.bands[setup.chandef.chan->band];
10049
10050 err = ieee80211_get_ratemask(sband, rates, n_rates,
10051 &setup.basic_rates);
10052 if (err)
10053 return err;
10054 }
10055
Johannes Berg8564e382016-09-19 09:44:44 +020010056 if (info->attrs[NL80211_ATTR_TX_RATES]) {
10057 err = nl80211_parse_tx_bitrate_mask(info, &setup.beacon_rate);
10058 if (err)
10059 return err;
10060
Johannes Berg265698d2017-09-18 22:46:36 +020010061 if (!setup.chandef.chan)
10062 return -EINVAL;
10063
Johannes Berg8564e382016-09-19 09:44:44 +020010064 err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band,
10065 &setup.beacon_rate);
10066 if (err)
10067 return err;
10068 }
10069
Benjamin Bergd37d49c2017-05-16 11:23:11 +020010070 setup.userspace_handles_dfs =
10071 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
10072
Javier Cardonac80d5452010-12-16 17:37:49 -080010073 return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +010010074}
10075
10076static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
10077{
10078 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10079 struct net_device *dev = info->user_ptr[1];
10080
10081 return cfg80211_leave_mesh(rdev, dev);
10082}
10083
Johannes Bergdfb89c52012-06-27 09:23:48 +020010084#ifdef CONFIG_PM
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010085static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
10086 struct cfg80211_registered_device *rdev)
10087{
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010088 struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010089 struct nlattr *nl_pats, *nl_pat;
10090 int i, pat_len;
10091
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010092 if (!wowlan->n_patterns)
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010093 return 0;
10094
10095 nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
10096 if (!nl_pats)
10097 return -ENOBUFS;
10098
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010099 for (i = 0; i < wowlan->n_patterns; i++) {
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010100 nl_pat = nla_nest_start(msg, i + 1);
10101 if (!nl_pat)
10102 return -ENOBUFS;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010103 pat_len = wowlan->patterns[i].pattern_len;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010104 if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010105 wowlan->patterns[i].mask) ||
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010106 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
10107 wowlan->patterns[i].pattern) ||
10108 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010109 wowlan->patterns[i].pkt_offset))
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010110 return -ENOBUFS;
10111 nla_nest_end(msg, nl_pat);
10112 }
10113 nla_nest_end(msg, nl_pats);
10114
10115 return 0;
10116}
10117
Johannes Berg2a0e0472013-01-23 22:57:40 +010010118static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
10119 struct cfg80211_wowlan_tcp *tcp)
10120{
10121 struct nlattr *nl_tcp;
10122
10123 if (!tcp)
10124 return 0;
10125
10126 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
10127 if (!nl_tcp)
10128 return -ENOBUFS;
10129
Jiri Benc930345e2015-03-29 16:59:25 +020010130 if (nla_put_in_addr(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
10131 nla_put_in_addr(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
Johannes Berg2a0e0472013-01-23 22:57:40 +010010132 nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
10133 nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
10134 nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
10135 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
10136 tcp->payload_len, tcp->payload) ||
10137 nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
10138 tcp->data_interval) ||
10139 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
10140 tcp->wake_len, tcp->wake_data) ||
10141 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK,
10142 DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask))
10143 return -ENOBUFS;
10144
10145 if (tcp->payload_seq.len &&
10146 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
10147 sizeof(tcp->payload_seq), &tcp->payload_seq))
10148 return -ENOBUFS;
10149
10150 if (tcp->payload_tok.len &&
10151 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
10152 sizeof(tcp->payload_tok) + tcp->tokens_size,
10153 &tcp->payload_tok))
10154 return -ENOBUFS;
10155
Johannes Berge248ad32013-05-16 10:24:28 +020010156 nla_nest_end(msg, nl_tcp);
10157
Johannes Berg2a0e0472013-01-23 22:57:40 +010010158 return 0;
10159}
10160
Luciano Coelho75453cc2015-01-09 14:06:37 +020010161static int nl80211_send_wowlan_nd(struct sk_buff *msg,
10162 struct cfg80211_sched_scan_request *req)
10163{
Avraham Stern3b06d272015-10-12 09:51:34 +030010164 struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
Luciano Coelho75453cc2015-01-09 14:06:37 +020010165 int i;
10166
10167 if (!req)
10168 return 0;
10169
10170 nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
10171 if (!nd)
10172 return -ENOBUFS;
10173
Avraham Stern3b06d272015-10-12 09:51:34 +030010174 if (req->n_scan_plans == 1 &&
10175 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
10176 req->scan_plans[0].interval * 1000))
Luciano Coelho75453cc2015-01-09 14:06:37 +020010177 return -ENOBUFS;
10178
Luciano Coelho21fea562015-03-17 16:36:01 +020010179 if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
10180 return -ENOBUFS;
10181
vamsi krishnabf95ecd2017-01-13 01:12:20 +020010182 if (req->relative_rssi_set) {
10183 struct nl80211_bss_select_rssi_adjust rssi_adjust;
10184
10185 if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
10186 req->relative_rssi))
10187 return -ENOBUFS;
10188
10189 rssi_adjust.band = req->rssi_adjust.band;
10190 rssi_adjust.delta = req->rssi_adjust.delta;
10191 if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
10192 sizeof(rssi_adjust), &rssi_adjust))
10193 return -ENOBUFS;
10194 }
10195
Luciano Coelho75453cc2015-01-09 14:06:37 +020010196 freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
10197 if (!freqs)
10198 return -ENOBUFS;
10199
Johannes Berg53b18982016-09-14 09:59:21 +020010200 for (i = 0; i < req->n_channels; i++) {
10201 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
10202 return -ENOBUFS;
10203 }
Luciano Coelho75453cc2015-01-09 14:06:37 +020010204
10205 nla_nest_end(msg, freqs);
10206
10207 if (req->n_match_sets) {
10208 matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
Johannes Berg76e1fb42016-09-14 09:55:57 +020010209 if (!matches)
10210 return -ENOBUFS;
10211
Luciano Coelho75453cc2015-01-09 14:06:37 +020010212 for (i = 0; i < req->n_match_sets; i++) {
10213 match = nla_nest_start(msg, i);
Johannes Berg76e1fb42016-09-14 09:55:57 +020010214 if (!match)
10215 return -ENOBUFS;
10216
Johannes Berg53b18982016-09-14 09:59:21 +020010217 if (nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
10218 req->match_sets[i].ssid.ssid_len,
10219 req->match_sets[i].ssid.ssid))
10220 return -ENOBUFS;
Luciano Coelho75453cc2015-01-09 14:06:37 +020010221 nla_nest_end(msg, match);
10222 }
10223 nla_nest_end(msg, matches);
10224 }
10225
Avraham Stern3b06d272015-10-12 09:51:34 +030010226 scan_plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
10227 if (!scan_plans)
10228 return -ENOBUFS;
10229
10230 for (i = 0; i < req->n_scan_plans; i++) {
10231 scan_plan = nla_nest_start(msg, i + 1);
Johannes Berg76e1fb42016-09-14 09:55:57 +020010232 if (!scan_plan)
10233 return -ENOBUFS;
10234
Avraham Stern3b06d272015-10-12 09:51:34 +030010235 if (!scan_plan ||
10236 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
10237 req->scan_plans[i].interval) ||
10238 (req->scan_plans[i].iterations &&
10239 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
10240 req->scan_plans[i].iterations)))
10241 return -ENOBUFS;
10242 nla_nest_end(msg, scan_plan);
10243 }
10244 nla_nest_end(msg, scan_plans);
10245
Luciano Coelho75453cc2015-01-09 14:06:37 +020010246 nla_nest_end(msg, nd);
10247
10248 return 0;
10249}
10250
Johannes Bergff1b6e62011-05-04 15:37:28 +020010251static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
10252{
10253 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10254 struct sk_buff *msg;
10255 void *hdr;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010256 u32 size = NLMSG_DEFAULT_SIZE;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010257
Johannes Berg964dc9e2013-06-03 17:25:34 +020010258 if (!rdev->wiphy.wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010259 return -EOPNOTSUPP;
10260
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010261 if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
Johannes Berg2a0e0472013-01-23 22:57:40 +010010262 /* adjust size to have room for all the data */
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010263 size += rdev->wiphy.wowlan_config->tcp->tokens_size +
10264 rdev->wiphy.wowlan_config->tcp->payload_len +
10265 rdev->wiphy.wowlan_config->tcp->wake_len +
10266 rdev->wiphy.wowlan_config->tcp->wake_len / 8;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010267 }
10268
10269 msg = nlmsg_new(size, GFP_KERNEL);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010270 if (!msg)
10271 return -ENOMEM;
10272
Eric W. Biederman15e47302012-09-07 20:12:54 +000010273 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Bergff1b6e62011-05-04 15:37:28 +020010274 NL80211_CMD_GET_WOWLAN);
10275 if (!hdr)
10276 goto nla_put_failure;
10277
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010278 if (rdev->wiphy.wowlan_config) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020010279 struct nlattr *nl_wowlan;
10280
10281 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
10282 if (!nl_wowlan)
10283 goto nla_put_failure;
10284
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010285 if ((rdev->wiphy.wowlan_config->any &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010286 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010287 (rdev->wiphy.wowlan_config->disconnect &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010288 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010289 (rdev->wiphy.wowlan_config->magic_pkt &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010290 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010291 (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010292 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010293 (rdev->wiphy.wowlan_config->eap_identity_req &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010294 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010295 (rdev->wiphy.wowlan_config->four_way_handshake &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010296 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010297 (rdev->wiphy.wowlan_config->rfkill_release &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010298 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
10299 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010300
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010301 if (nl80211_send_wowlan_patterns(msg, rdev))
10302 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010303
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010304 if (nl80211_send_wowlan_tcp(msg,
10305 rdev->wiphy.wowlan_config->tcp))
Johannes Berg2a0e0472013-01-23 22:57:40 +010010306 goto nla_put_failure;
10307
Luciano Coelho75453cc2015-01-09 14:06:37 +020010308 if (nl80211_send_wowlan_nd(
10309 msg,
10310 rdev->wiphy.wowlan_config->nd_config))
10311 goto nla_put_failure;
10312
Johannes Bergff1b6e62011-05-04 15:37:28 +020010313 nla_nest_end(msg, nl_wowlan);
10314 }
10315
10316 genlmsg_end(msg, hdr);
10317 return genlmsg_reply(msg, info);
10318
10319nla_put_failure:
10320 nlmsg_free(msg);
10321 return -ENOBUFS;
10322}
10323
Johannes Berg2a0e0472013-01-23 22:57:40 +010010324static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
10325 struct nlattr *attr,
10326 struct cfg80211_wowlan *trig)
10327{
10328 struct nlattr *tb[NUM_NL80211_WOWLAN_TCP];
10329 struct cfg80211_wowlan_tcp *cfg;
10330 struct nl80211_wowlan_tcp_data_token *tok = NULL;
10331 struct nl80211_wowlan_tcp_data_seq *seq = NULL;
10332 u32 size;
10333 u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
10334 int err, port;
10335
Johannes Berg964dc9e2013-06-03 17:25:34 +020010336 if (!rdev->wiphy.wowlan->tcp)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010337 return -EINVAL;
10338
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010339 err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TCP, attr,
Johannes Bergfceb6432017-04-12 14:34:07 +020010340 nl80211_wowlan_tcp_policy, NULL);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010341 if (err)
10342 return err;
10343
10344 if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] ||
10345 !tb[NL80211_WOWLAN_TCP_DST_IPV4] ||
10346 !tb[NL80211_WOWLAN_TCP_DST_MAC] ||
10347 !tb[NL80211_WOWLAN_TCP_DST_PORT] ||
10348 !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] ||
10349 !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] ||
10350 !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] ||
10351 !tb[NL80211_WOWLAN_TCP_WAKE_MASK])
10352 return -EINVAL;
10353
10354 data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010355 if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010356 return -EINVAL;
10357
10358 if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
Johannes Berg964dc9e2013-06-03 17:25:34 +020010359 rdev->wiphy.wowlan->tcp->data_interval_max ||
Johannes Berg723d5682013-02-26 13:56:40 +010010360 nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010361 return -EINVAL;
10362
10363 wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010364 if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010365 return -EINVAL;
10366
10367 wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
10368 if (wake_mask_size != DIV_ROUND_UP(wake_size, 8))
10369 return -EINVAL;
10370
10371 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) {
10372 u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
10373
10374 tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
10375 tokens_size = tokln - sizeof(*tok);
10376
10377 if (!tok->len || tokens_size % tok->len)
10378 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010379 if (!rdev->wiphy.wowlan->tcp->tok)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010380 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010381 if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010382 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010383 if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010384 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010385 if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010386 return -EINVAL;
10387 if (tok->offset + tok->len > data_size)
10388 return -EINVAL;
10389 }
10390
10391 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
10392 seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010393 if (!rdev->wiphy.wowlan->tcp->seq)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010394 return -EINVAL;
10395 if (seq->len == 0 || seq->len > 4)
10396 return -EINVAL;
10397 if (seq->len + seq->offset > data_size)
10398 return -EINVAL;
10399 }
10400
10401 size = sizeof(*cfg);
10402 size += data_size;
10403 size += wake_size + wake_mask_size;
10404 size += tokens_size;
10405
10406 cfg = kzalloc(size, GFP_KERNEL);
10407 if (!cfg)
10408 return -ENOMEM;
Jiri Benc67b61f62015-03-29 16:59:26 +020010409 cfg->src = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
10410 cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010411 memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
10412 ETH_ALEN);
10413 if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
10414 port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
10415 else
10416 port = 0;
10417#ifdef CONFIG_INET
10418 /* allocate a socket and port for it and use it */
10419 err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
10420 IPPROTO_TCP, &cfg->sock, 1);
10421 if (err) {
10422 kfree(cfg);
10423 return err;
10424 }
10425 if (inet_csk_get_port(cfg->sock->sk, port)) {
10426 sock_release(cfg->sock);
10427 kfree(cfg);
10428 return -EADDRINUSE;
10429 }
10430 cfg->src_port = inet_sk(cfg->sock->sk)->inet_num;
10431#else
10432 if (!port) {
10433 kfree(cfg);
10434 return -EINVAL;
10435 }
10436 cfg->src_port = port;
10437#endif
10438
10439 cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]);
10440 cfg->payload_len = data_size;
10441 cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size;
10442 memcpy((void *)cfg->payload,
10443 nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]),
10444 data_size);
10445 if (seq)
10446 cfg->payload_seq = *seq;
10447 cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]);
10448 cfg->wake_len = wake_size;
10449 cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size;
10450 memcpy((void *)cfg->wake_data,
10451 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]),
10452 wake_size);
10453 cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size +
10454 data_size + wake_size;
10455 memcpy((void *)cfg->wake_mask,
10456 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]),
10457 wake_mask_size);
10458 if (tok) {
10459 cfg->tokens_size = tokens_size;
10460 memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size);
10461 }
10462
10463 trig->tcp = cfg;
10464
10465 return 0;
10466}
10467
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010468static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
10469 const struct wiphy_wowlan_support *wowlan,
10470 struct nlattr *attr,
10471 struct cfg80211_wowlan *trig)
10472{
10473 struct nlattr **tb;
10474 int err;
10475
10476 tb = kzalloc(NUM_NL80211_ATTR * sizeof(*tb), GFP_KERNEL);
10477 if (!tb)
10478 return -ENOMEM;
10479
10480 if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) {
10481 err = -EOPNOTSUPP;
10482 goto out;
10483 }
10484
Johannes Bergfceb6432017-04-12 14:34:07 +020010485 err = nla_parse_nested(tb, NL80211_ATTR_MAX, attr, nl80211_policy,
10486 NULL);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010487 if (err)
10488 goto out;
10489
Arend Van Sprielaad1e812017-01-27 12:27:44 +000010490 trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb,
10491 wowlan->max_nd_match_sets);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010492 err = PTR_ERR_OR_ZERO(trig->nd_config);
10493 if (err)
10494 trig->nd_config = NULL;
10495
10496out:
10497 kfree(tb);
10498 return err;
10499}
10500
Johannes Bergff1b6e62011-05-04 15:37:28 +020010501static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
10502{
10503 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10504 struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010505 struct cfg80211_wowlan new_triggers = {};
Johannes Bergae33bd82012-07-12 16:25:02 +020010506 struct cfg80211_wowlan *ntrig;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010507 const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010508 int err, i;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010509 bool prev_enabled = rdev->wiphy.wowlan_config;
Johannes Berg98fc4382015-03-01 09:10:13 +020010510 bool regular = false;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010511
Johannes Berg964dc9e2013-06-03 17:25:34 +020010512 if (!wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010513 return -EOPNOTSUPP;
10514
Johannes Bergae33bd82012-07-12 16:25:02 +020010515 if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
10516 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010517 rdev->wiphy.wowlan_config = NULL;
Johannes Bergae33bd82012-07-12 16:25:02 +020010518 goto set_wakeup;
10519 }
Johannes Bergff1b6e62011-05-04 15:37:28 +020010520
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010521 err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TRIG,
10522 info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS],
Johannes Bergfe521452017-04-12 14:34:08 +020010523 nl80211_wowlan_policy, info->extack);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010524 if (err)
10525 return err;
10526
10527 if (tb[NL80211_WOWLAN_TRIG_ANY]) {
10528 if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
10529 return -EINVAL;
10530 new_triggers.any = true;
10531 }
10532
10533 if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
10534 if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
10535 return -EINVAL;
10536 new_triggers.disconnect = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010537 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010538 }
10539
10540 if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
10541 if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
10542 return -EINVAL;
10543 new_triggers.magic_pkt = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010544 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010545 }
10546
Johannes Berg77dbbb12011-07-13 10:48:55 +020010547 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
10548 return -EINVAL;
10549
10550 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) {
10551 if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
10552 return -EINVAL;
10553 new_triggers.gtk_rekey_failure = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010554 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010555 }
10556
10557 if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
10558 if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
10559 return -EINVAL;
10560 new_triggers.eap_identity_req = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010561 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010562 }
10563
10564 if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
10565 if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
10566 return -EINVAL;
10567 new_triggers.four_way_handshake = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010568 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010569 }
10570
10571 if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
10572 if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
10573 return -EINVAL;
10574 new_triggers.rfkill_release = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010575 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010576 }
10577
Johannes Bergff1b6e62011-05-04 15:37:28 +020010578 if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
10579 struct nlattr *pat;
10580 int n_patterns = 0;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010581 int rem, pat_len, mask_len, pkt_offset;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010582 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010583
Johannes Berg98fc4382015-03-01 09:10:13 +020010584 regular = true;
10585
Johannes Bergff1b6e62011-05-04 15:37:28 +020010586 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10587 rem)
10588 n_patterns++;
10589 if (n_patterns > wowlan->n_patterns)
10590 return -EINVAL;
10591
10592 new_triggers.patterns = kcalloc(n_patterns,
10593 sizeof(new_triggers.patterns[0]),
10594 GFP_KERNEL);
10595 if (!new_triggers.patterns)
10596 return -ENOMEM;
10597
10598 new_triggers.n_patterns = n_patterns;
10599 i = 0;
10600
10601 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10602 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010603 u8 *mask_pat;
10604
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010605 nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat,
Peng Xuad670232017-10-03 23:21:51 +030010606 nl80211_packet_pattern_policy,
10607 info->extack);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010608 err = -EINVAL;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010609 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10610 !pat_tb[NL80211_PKTPAT_PATTERN])
Johannes Bergff1b6e62011-05-04 15:37:28 +020010611 goto error;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010612 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010613 mask_len = DIV_ROUND_UP(pat_len, 8);
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010614 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010615 goto error;
10616 if (pat_len > wowlan->pattern_max_len ||
10617 pat_len < wowlan->pattern_min_len)
10618 goto error;
10619
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010620 if (!pat_tb[NL80211_PKTPAT_OFFSET])
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010621 pkt_offset = 0;
10622 else
10623 pkt_offset = nla_get_u32(
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010624 pat_tb[NL80211_PKTPAT_OFFSET]);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010625 if (pkt_offset > wowlan->max_pkt_offset)
10626 goto error;
10627 new_triggers.patterns[i].pkt_offset = pkt_offset;
10628
Johannes Berg922bd802014-05-19 17:59:50 +020010629 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10630 if (!mask_pat) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020010631 err = -ENOMEM;
10632 goto error;
10633 }
Johannes Berg922bd802014-05-19 17:59:50 +020010634 new_triggers.patterns[i].mask = mask_pat;
10635 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010636 mask_len);
Johannes Berg922bd802014-05-19 17:59:50 +020010637 mask_pat += mask_len;
10638 new_triggers.patterns[i].pattern = mask_pat;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010639 new_triggers.patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010640 memcpy(mask_pat,
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010641 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010642 pat_len);
10643 i++;
10644 }
10645 }
10646
Johannes Berg2a0e0472013-01-23 22:57:40 +010010647 if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010648 regular = true;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010649 err = nl80211_parse_wowlan_tcp(
10650 rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
10651 &new_triggers);
10652 if (err)
10653 goto error;
10654 }
10655
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010656 if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010657 regular = true;
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010658 err = nl80211_parse_wowlan_nd(
10659 rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
10660 &new_triggers);
10661 if (err)
10662 goto error;
10663 }
10664
Johannes Berg98fc4382015-03-01 09:10:13 +020010665 /* The 'any' trigger means the device continues operating more or less
10666 * as in its normal operation mode and wakes up the host on most of the
10667 * normal interrupts (like packet RX, ...)
10668 * It therefore makes little sense to combine with the more constrained
10669 * wakeup trigger modes.
10670 */
10671 if (new_triggers.any && regular) {
10672 err = -EINVAL;
10673 goto error;
10674 }
10675
Johannes Bergae33bd82012-07-12 16:25:02 +020010676 ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
10677 if (!ntrig) {
10678 err = -ENOMEM;
10679 goto error;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010680 }
Johannes Bergae33bd82012-07-12 16:25:02 +020010681 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010682 rdev->wiphy.wowlan_config = ntrig;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010683
Johannes Bergae33bd82012-07-12 16:25:02 +020010684 set_wakeup:
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010685 if (rdev->ops->set_wakeup &&
10686 prev_enabled != !!rdev->wiphy.wowlan_config)
10687 rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
Johannes Berg6d525632012-04-04 15:05:25 +020010688
Johannes Bergff1b6e62011-05-04 15:37:28 +020010689 return 0;
10690 error:
10691 for (i = 0; i < new_triggers.n_patterns; i++)
10692 kfree(new_triggers.patterns[i].mask);
10693 kfree(new_triggers.patterns);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010694 if (new_triggers.tcp && new_triggers.tcp->sock)
10695 sock_release(new_triggers.tcp->sock);
10696 kfree(new_triggers.tcp);
Ola Olssone5dbe072015-12-12 23:17:17 +010010697 kfree(new_triggers.nd_config);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010698 return err;
10699}
Johannes Bergdfb89c52012-06-27 09:23:48 +020010700#endif
Johannes Bergff1b6e62011-05-04 15:37:28 +020010701
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010702static int nl80211_send_coalesce_rules(struct sk_buff *msg,
10703 struct cfg80211_registered_device *rdev)
10704{
10705 struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
10706 int i, j, pat_len;
10707 struct cfg80211_coalesce_rules *rule;
10708
10709 if (!rdev->coalesce->n_rules)
10710 return 0;
10711
10712 nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
10713 if (!nl_rules)
10714 return -ENOBUFS;
10715
10716 for (i = 0; i < rdev->coalesce->n_rules; i++) {
10717 nl_rule = nla_nest_start(msg, i + 1);
10718 if (!nl_rule)
10719 return -ENOBUFS;
10720
10721 rule = &rdev->coalesce->rules[i];
10722 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
10723 rule->delay))
10724 return -ENOBUFS;
10725
10726 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
10727 rule->condition))
10728 return -ENOBUFS;
10729
10730 nl_pats = nla_nest_start(msg,
10731 NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
10732 if (!nl_pats)
10733 return -ENOBUFS;
10734
10735 for (j = 0; j < rule->n_patterns; j++) {
10736 nl_pat = nla_nest_start(msg, j + 1);
10737 if (!nl_pat)
10738 return -ENOBUFS;
10739 pat_len = rule->patterns[j].pattern_len;
10740 if (nla_put(msg, NL80211_PKTPAT_MASK,
10741 DIV_ROUND_UP(pat_len, 8),
10742 rule->patterns[j].mask) ||
10743 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
10744 rule->patterns[j].pattern) ||
10745 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
10746 rule->patterns[j].pkt_offset))
10747 return -ENOBUFS;
10748 nla_nest_end(msg, nl_pat);
10749 }
10750 nla_nest_end(msg, nl_pats);
10751 nla_nest_end(msg, nl_rule);
10752 }
10753 nla_nest_end(msg, nl_rules);
10754
10755 return 0;
10756}
10757
10758static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
10759{
10760 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10761 struct sk_buff *msg;
10762 void *hdr;
10763
10764 if (!rdev->wiphy.coalesce)
10765 return -EOPNOTSUPP;
10766
10767 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10768 if (!msg)
10769 return -ENOMEM;
10770
10771 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
10772 NL80211_CMD_GET_COALESCE);
10773 if (!hdr)
10774 goto nla_put_failure;
10775
10776 if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
10777 goto nla_put_failure;
10778
10779 genlmsg_end(msg, hdr);
10780 return genlmsg_reply(msg, info);
10781
10782nla_put_failure:
10783 nlmsg_free(msg);
10784 return -ENOBUFS;
10785}
10786
10787void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
10788{
10789 struct cfg80211_coalesce *coalesce = rdev->coalesce;
10790 int i, j;
10791 struct cfg80211_coalesce_rules *rule;
10792
10793 if (!coalesce)
10794 return;
10795
10796 for (i = 0; i < coalesce->n_rules; i++) {
10797 rule = &coalesce->rules[i];
10798 for (j = 0; j < rule->n_patterns; j++)
10799 kfree(rule->patterns[j].mask);
10800 kfree(rule->patterns);
10801 }
10802 kfree(coalesce->rules);
10803 kfree(coalesce);
10804 rdev->coalesce = NULL;
10805}
10806
10807static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
10808 struct nlattr *rule,
10809 struct cfg80211_coalesce_rules *new_rule)
10810{
10811 int err, i;
10812 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10813 struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
10814 int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
10815 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
10816
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010817 err = nla_parse_nested(tb, NL80211_ATTR_COALESCE_RULE_MAX, rule,
Johannes Bergfceb6432017-04-12 14:34:07 +020010818 nl80211_coalesce_policy, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010819 if (err)
10820 return err;
10821
10822 if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
10823 new_rule->delay =
10824 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
10825 if (new_rule->delay > coalesce->max_delay)
10826 return -EINVAL;
10827
10828 if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
10829 new_rule->condition =
10830 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
10831 if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH &&
10832 new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH)
10833 return -EINVAL;
10834
10835 if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
10836 return -EINVAL;
10837
10838 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
10839 rem)
10840 n_patterns++;
10841 if (n_patterns > coalesce->n_patterns)
10842 return -EINVAL;
10843
10844 new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
10845 GFP_KERNEL);
10846 if (!new_rule->patterns)
10847 return -ENOMEM;
10848
10849 new_rule->n_patterns = n_patterns;
10850 i = 0;
10851
10852 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
10853 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010854 u8 *mask_pat;
10855
Peng Xuad670232017-10-03 23:21:51 +030010856 nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat,
10857 nl80211_packet_pattern_policy, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010858 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10859 !pat_tb[NL80211_PKTPAT_PATTERN])
10860 return -EINVAL;
10861 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
10862 mask_len = DIV_ROUND_UP(pat_len, 8);
10863 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
10864 return -EINVAL;
10865 if (pat_len > coalesce->pattern_max_len ||
10866 pat_len < coalesce->pattern_min_len)
10867 return -EINVAL;
10868
10869 if (!pat_tb[NL80211_PKTPAT_OFFSET])
10870 pkt_offset = 0;
10871 else
10872 pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
10873 if (pkt_offset > coalesce->max_pkt_offset)
10874 return -EINVAL;
10875 new_rule->patterns[i].pkt_offset = pkt_offset;
10876
Johannes Berg922bd802014-05-19 17:59:50 +020010877 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10878 if (!mask_pat)
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010879 return -ENOMEM;
Johannes Berg922bd802014-05-19 17:59:50 +020010880
10881 new_rule->patterns[i].mask = mask_pat;
10882 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
10883 mask_len);
10884
10885 mask_pat += mask_len;
10886 new_rule->patterns[i].pattern = mask_pat;
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010887 new_rule->patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010888 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
10889 pat_len);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010890 i++;
10891 }
10892
10893 return 0;
10894}
10895
10896static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
10897{
10898 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10899 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10900 struct cfg80211_coalesce new_coalesce = {};
10901 struct cfg80211_coalesce *n_coalesce;
10902 int err, rem_rule, n_rules = 0, i, j;
10903 struct nlattr *rule;
10904 struct cfg80211_coalesce_rules *tmp_rule;
10905
10906 if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
10907 return -EOPNOTSUPP;
10908
10909 if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
10910 cfg80211_rdev_free_coalesce(rdev);
Ilan Peera1056b1b2015-10-22 22:27:46 +030010911 rdev_set_coalesce(rdev, NULL);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010912 return 0;
10913 }
10914
10915 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
10916 rem_rule)
10917 n_rules++;
10918 if (n_rules > coalesce->n_rules)
10919 return -EINVAL;
10920
10921 new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
10922 GFP_KERNEL);
10923 if (!new_coalesce.rules)
10924 return -ENOMEM;
10925
10926 new_coalesce.n_rules = n_rules;
10927 i = 0;
10928
10929 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
10930 rem_rule) {
10931 err = nl80211_parse_coalesce_rule(rdev, rule,
10932 &new_coalesce.rules[i]);
10933 if (err)
10934 goto error;
10935
10936 i++;
10937 }
10938
Ilan Peera1056b1b2015-10-22 22:27:46 +030010939 err = rdev_set_coalesce(rdev, &new_coalesce);
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070010940 if (err)
10941 goto error;
10942
10943 n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
10944 if (!n_coalesce) {
10945 err = -ENOMEM;
10946 goto error;
10947 }
10948 cfg80211_rdev_free_coalesce(rdev);
10949 rdev->coalesce = n_coalesce;
10950
10951 return 0;
10952error:
10953 for (i = 0; i < new_coalesce.n_rules; i++) {
10954 tmp_rule = &new_coalesce.rules[i];
10955 for (j = 0; j < tmp_rule->n_patterns; j++)
10956 kfree(tmp_rule->patterns[j].mask);
10957 kfree(tmp_rule->patterns);
10958 }
10959 kfree(new_coalesce.rules);
10960
10961 return err;
10962}
10963
Johannes Berge5497d72011-07-05 16:35:40 +020010964static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
10965{
10966 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10967 struct net_device *dev = info->user_ptr[1];
10968 struct wireless_dev *wdev = dev->ieee80211_ptr;
10969 struct nlattr *tb[NUM_NL80211_REKEY_DATA];
10970 struct cfg80211_gtk_rekey_data rekey_data;
10971 int err;
10972
10973 if (!info->attrs[NL80211_ATTR_REKEY_DATA])
10974 return -EINVAL;
10975
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010976 err = nla_parse_nested(tb, MAX_NL80211_REKEY_DATA,
10977 info->attrs[NL80211_ATTR_REKEY_DATA],
Johannes Bergfe521452017-04-12 14:34:08 +020010978 nl80211_rekey_policy, info->extack);
Johannes Berge5497d72011-07-05 16:35:40 +020010979 if (err)
10980 return err;
10981
Vladis Dronove785fa02017-09-13 00:21:21 +020010982 if (!tb[NL80211_REKEY_DATA_REPLAY_CTR] || !tb[NL80211_REKEY_DATA_KEK] ||
10983 !tb[NL80211_REKEY_DATA_KCK])
10984 return -EINVAL;
Johannes Berge5497d72011-07-05 16:35:40 +020010985 if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
10986 return -ERANGE;
10987 if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
10988 return -ERANGE;
10989 if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
10990 return -ERANGE;
10991
Johannes Berg78f686c2014-09-10 22:28:06 +030010992 rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
10993 rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
10994 rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
Johannes Berge5497d72011-07-05 16:35:40 +020010995
10996 wdev_lock(wdev);
10997 if (!wdev->current_bss) {
10998 err = -ENOTCONN;
10999 goto out;
11000 }
11001
11002 if (!rdev->ops->set_rekey_data) {
11003 err = -EOPNOTSUPP;
11004 goto out;
11005 }
11006
Hila Gonene35e4d22012-06-27 17:19:42 +030011007 err = rdev_set_rekey_data(rdev, dev, &rekey_data);
Johannes Berge5497d72011-07-05 16:35:40 +020011008 out:
11009 wdev_unlock(wdev);
11010 return err;
11011}
11012
Johannes Berg28946da2011-11-04 11:18:12 +010011013static int nl80211_register_unexpected_frame(struct sk_buff *skb,
11014 struct genl_info *info)
11015{
11016 struct net_device *dev = info->user_ptr[1];
11017 struct wireless_dev *wdev = dev->ieee80211_ptr;
11018
11019 if (wdev->iftype != NL80211_IFTYPE_AP &&
11020 wdev->iftype != NL80211_IFTYPE_P2P_GO)
11021 return -EINVAL;
11022
Eric W. Biederman15e47302012-09-07 20:12:54 +000011023 if (wdev->ap_unexpected_nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010011024 return -EBUSY;
11025
Eric W. Biederman15e47302012-09-07 20:12:54 +000011026 wdev->ap_unexpected_nlportid = info->snd_portid;
Johannes Berg28946da2011-11-04 11:18:12 +010011027 return 0;
11028}
11029
Johannes Berg7f6cf312011-11-04 11:18:15 +010011030static int nl80211_probe_client(struct sk_buff *skb,
11031 struct genl_info *info)
11032{
11033 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11034 struct net_device *dev = info->user_ptr[1];
11035 struct wireless_dev *wdev = dev->ieee80211_ptr;
11036 struct sk_buff *msg;
11037 void *hdr;
11038 const u8 *addr;
11039 u64 cookie;
11040 int err;
11041
11042 if (wdev->iftype != NL80211_IFTYPE_AP &&
11043 wdev->iftype != NL80211_IFTYPE_P2P_GO)
11044 return -EOPNOTSUPP;
11045
11046 if (!info->attrs[NL80211_ATTR_MAC])
11047 return -EINVAL;
11048
11049 if (!rdev->ops->probe_client)
11050 return -EOPNOTSUPP;
11051
11052 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11053 if (!msg)
11054 return -ENOMEM;
11055
Eric W. Biederman15e47302012-09-07 20:12:54 +000011056 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg7f6cf312011-11-04 11:18:15 +010011057 NL80211_CMD_PROBE_CLIENT);
Dan Carpentercb35fba2013-08-14 14:50:01 +030011058 if (!hdr) {
11059 err = -ENOBUFS;
Johannes Berg7f6cf312011-11-04 11:18:15 +010011060 goto free_msg;
11061 }
11062
11063 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
11064
Hila Gonene35e4d22012-06-27 17:19:42 +030011065 err = rdev_probe_client(rdev, dev, addr, &cookie);
Johannes Berg7f6cf312011-11-04 11:18:15 +010011066 if (err)
11067 goto free_msg;
11068
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020011069 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
11070 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040011071 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010011072
11073 genlmsg_end(msg, hdr);
11074
11075 return genlmsg_reply(msg, info);
11076
11077 nla_put_failure:
11078 err = -ENOBUFS;
11079 free_msg:
11080 nlmsg_free(msg);
11081 return err;
11082}
11083
Johannes Berg5e760232011-11-04 11:18:17 +010011084static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
11085{
11086 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Ben Greear37c73b52012-10-26 14:49:25 -070011087 struct cfg80211_beacon_registration *reg, *nreg;
11088 int rv;
Johannes Berg5e760232011-11-04 11:18:17 +010011089
11090 if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
11091 return -EOPNOTSUPP;
11092
Ben Greear37c73b52012-10-26 14:49:25 -070011093 nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
11094 if (!nreg)
11095 return -ENOMEM;
Johannes Berg5e760232011-11-04 11:18:17 +010011096
Ben Greear37c73b52012-10-26 14:49:25 -070011097 /* First, check if already registered. */
11098 spin_lock_bh(&rdev->beacon_registrations_lock);
11099 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
11100 if (reg->nlportid == info->snd_portid) {
11101 rv = -EALREADY;
11102 goto out_err;
11103 }
11104 }
11105 /* Add it to the list */
11106 nreg->nlportid = info->snd_portid;
11107 list_add(&nreg->list, &rdev->beacon_registrations);
11108
11109 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010011110
11111 return 0;
Ben Greear37c73b52012-10-26 14:49:25 -070011112out_err:
11113 spin_unlock_bh(&rdev->beacon_registrations_lock);
11114 kfree(nreg);
11115 return rv;
Johannes Berg5e760232011-11-04 11:18:17 +010011116}
11117
Johannes Berg98104fde2012-06-16 00:19:54 +020011118static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
11119{
11120 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11121 struct wireless_dev *wdev = info->user_ptr[1];
11122 int err;
11123
11124 if (!rdev->ops->start_p2p_device)
11125 return -EOPNOTSUPP;
11126
11127 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
11128 return -EOPNOTSUPP;
11129
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011130 if (wdev_running(wdev))
Johannes Berg98104fde2012-06-16 00:19:54 +020011131 return 0;
11132
Luciano Coelhob6a55012014-02-27 11:07:21 +020011133 if (rfkill_blocked(rdev->rfkill))
11134 return -ERFKILL;
Johannes Berg98104fde2012-06-16 00:19:54 +020011135
Johannes Bergeeb126e2012-10-23 15:16:50 +020011136 err = rdev_start_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020011137 if (err)
11138 return err;
11139
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011140 wdev->is_running = true;
Johannes Berg98104fde2012-06-16 00:19:54 +020011141 rdev->opencount++;
Johannes Berg98104fde2012-06-16 00:19:54 +020011142
11143 return 0;
11144}
11145
11146static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
11147{
11148 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11149 struct wireless_dev *wdev = info->user_ptr[1];
11150
11151 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
11152 return -EOPNOTSUPP;
11153
11154 if (!rdev->ops->stop_p2p_device)
11155 return -EOPNOTSUPP;
11156
Johannes Bergf9f47522013-03-19 15:04:07 +010011157 cfg80211_stop_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020011158
11159 return 0;
11160}
11161
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011162static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
11163{
11164 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11165 struct wireless_dev *wdev = info->user_ptr[1];
11166 struct cfg80211_nan_conf conf = {};
11167 int err;
11168
11169 if (wdev->iftype != NL80211_IFTYPE_NAN)
11170 return -EOPNOTSUPP;
11171
Johannes Bergeeb04a92016-11-21 13:55:48 +010011172 if (wdev_running(wdev))
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011173 return -EEXIST;
11174
11175 if (rfkill_blocked(rdev->rfkill))
11176 return -ERFKILL;
11177
11178 if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
11179 return -EINVAL;
11180
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011181 conf.master_pref =
11182 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
11183 if (!conf.master_pref)
11184 return -EINVAL;
11185
Luca Coelho85859892017-02-08 15:00:34 +020011186 if (info->attrs[NL80211_ATTR_BANDS]) {
11187 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
11188
11189 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
11190 return -EOPNOTSUPP;
11191
11192 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
11193 return -EINVAL;
11194
11195 conf.bands = bands;
11196 }
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011197
11198 err = rdev_start_nan(rdev, wdev, &conf);
11199 if (err)
11200 return err;
11201
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011202 wdev->is_running = true;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011203 rdev->opencount++;
11204
11205 return 0;
11206}
11207
11208static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
11209{
11210 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11211 struct wireless_dev *wdev = info->user_ptr[1];
11212
11213 if (wdev->iftype != NL80211_IFTYPE_NAN)
11214 return -EOPNOTSUPP;
11215
11216 cfg80211_stop_nan(rdev, wdev);
11217
11218 return 0;
11219}
11220
Ayala Bekera442b762016-09-20 17:31:15 +030011221static int validate_nan_filter(struct nlattr *filter_attr)
11222{
11223 struct nlattr *attr;
11224 int len = 0, n_entries = 0, rem;
11225
11226 nla_for_each_nested(attr, filter_attr, rem) {
11227 len += nla_len(attr);
11228 n_entries++;
11229 }
11230
11231 if (len >= U8_MAX)
11232 return -EINVAL;
11233
11234 return n_entries;
11235}
11236
11237static int handle_nan_filter(struct nlattr *attr_filter,
11238 struct cfg80211_nan_func *func,
11239 bool tx)
11240{
11241 struct nlattr *attr;
11242 int n_entries, rem, i;
11243 struct cfg80211_nan_func_filter *filter;
11244
11245 n_entries = validate_nan_filter(attr_filter);
11246 if (n_entries < 0)
11247 return n_entries;
11248
11249 BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters));
11250
11251 filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL);
11252 if (!filter)
11253 return -ENOMEM;
11254
11255 i = 0;
11256 nla_for_each_nested(attr, attr_filter, rem) {
Thomas Grafb15ca182016-10-26 10:53:16 +020011257 filter[i].filter = nla_memdup(attr, GFP_KERNEL);
Ayala Bekera442b762016-09-20 17:31:15 +030011258 filter[i].len = nla_len(attr);
11259 i++;
11260 }
11261 if (tx) {
11262 func->num_tx_filters = n_entries;
11263 func->tx_filters = filter;
11264 } else {
11265 func->num_rx_filters = n_entries;
11266 func->rx_filters = filter;
11267 }
11268
11269 return 0;
11270}
11271
11272static int nl80211_nan_add_func(struct sk_buff *skb,
11273 struct genl_info *info)
11274{
11275 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11276 struct wireless_dev *wdev = info->user_ptr[1];
11277 struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR], *func_attr;
11278 struct cfg80211_nan_func *func;
11279 struct sk_buff *msg = NULL;
11280 void *hdr = NULL;
11281 int err = 0;
11282
11283 if (wdev->iftype != NL80211_IFTYPE_NAN)
11284 return -EOPNOTSUPP;
11285
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011286 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030011287 return -ENOTCONN;
11288
11289 if (!info->attrs[NL80211_ATTR_NAN_FUNC])
11290 return -EINVAL;
11291
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020011292 err = nla_parse_nested(tb, NL80211_NAN_FUNC_ATTR_MAX,
11293 info->attrs[NL80211_ATTR_NAN_FUNC],
Johannes Bergfe521452017-04-12 14:34:08 +020011294 nl80211_nan_func_policy, info->extack);
Ayala Bekera442b762016-09-20 17:31:15 +030011295 if (err)
11296 return err;
11297
11298 func = kzalloc(sizeof(*func), GFP_KERNEL);
11299 if (!func)
11300 return -ENOMEM;
11301
11302 func->cookie = wdev->wiphy->cookie_counter++;
11303
11304 if (!tb[NL80211_NAN_FUNC_TYPE] ||
11305 nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]) > NL80211_NAN_FUNC_MAX_TYPE) {
11306 err = -EINVAL;
11307 goto out;
11308 }
11309
11310
11311 func->type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]);
11312
11313 if (!tb[NL80211_NAN_FUNC_SERVICE_ID]) {
11314 err = -EINVAL;
11315 goto out;
11316 }
11317
11318 memcpy(func->service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]),
11319 sizeof(func->service_id));
11320
11321 func->close_range =
11322 nla_get_flag(tb[NL80211_NAN_FUNC_CLOSE_RANGE]);
11323
11324 if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) {
11325 func->serv_spec_info_len =
11326 nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
11327 func->serv_spec_info =
11328 kmemdup(nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]),
11329 func->serv_spec_info_len,
11330 GFP_KERNEL);
11331 if (!func->serv_spec_info) {
11332 err = -ENOMEM;
11333 goto out;
11334 }
11335 }
11336
11337 if (tb[NL80211_NAN_FUNC_TTL])
11338 func->ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]);
11339
11340 switch (func->type) {
11341 case NL80211_NAN_FUNC_PUBLISH:
11342 if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE]) {
11343 err = -EINVAL;
11344 goto out;
11345 }
11346
11347 func->publish_type =
11348 nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]);
11349 func->publish_bcast =
11350 nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]);
11351
11352 if ((!(func->publish_type & NL80211_NAN_SOLICITED_PUBLISH)) &&
11353 func->publish_bcast) {
11354 err = -EINVAL;
11355 goto out;
11356 }
11357 break;
11358 case NL80211_NAN_FUNC_SUBSCRIBE:
11359 func->subscribe_active =
11360 nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]);
11361 break;
11362 case NL80211_NAN_FUNC_FOLLOW_UP:
11363 if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] ||
Hao Chen3ea15452018-01-03 11:00:31 +080011364 !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] ||
11365 !tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]) {
Ayala Bekera442b762016-09-20 17:31:15 +030011366 err = -EINVAL;
11367 goto out;
11368 }
11369
11370 func->followup_id =
11371 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]);
11372 func->followup_reqid =
11373 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]);
11374 memcpy(func->followup_dest.addr,
11375 nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]),
11376 sizeof(func->followup_dest.addr));
11377 if (func->ttl) {
11378 err = -EINVAL;
11379 goto out;
11380 }
11381 break;
11382 default:
11383 err = -EINVAL;
11384 goto out;
11385 }
11386
11387 if (tb[NL80211_NAN_FUNC_SRF]) {
11388 struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
11389
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020011390 err = nla_parse_nested(srf_tb, NL80211_NAN_SRF_ATTR_MAX,
11391 tb[NL80211_NAN_FUNC_SRF],
Johannes Bergfe521452017-04-12 14:34:08 +020011392 nl80211_nan_srf_policy, info->extack);
Ayala Bekera442b762016-09-20 17:31:15 +030011393 if (err)
11394 goto out;
11395
11396 func->srf_include =
11397 nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]);
11398
11399 if (srf_tb[NL80211_NAN_SRF_BF]) {
11400 if (srf_tb[NL80211_NAN_SRF_MAC_ADDRS] ||
11401 !srf_tb[NL80211_NAN_SRF_BF_IDX]) {
11402 err = -EINVAL;
11403 goto out;
11404 }
11405
11406 func->srf_bf_len =
11407 nla_len(srf_tb[NL80211_NAN_SRF_BF]);
11408 func->srf_bf =
11409 kmemdup(nla_data(srf_tb[NL80211_NAN_SRF_BF]),
11410 func->srf_bf_len, GFP_KERNEL);
11411 if (!func->srf_bf) {
11412 err = -ENOMEM;
11413 goto out;
11414 }
11415
11416 func->srf_bf_idx =
11417 nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]);
11418 } else {
11419 struct nlattr *attr, *mac_attr =
11420 srf_tb[NL80211_NAN_SRF_MAC_ADDRS];
11421 int n_entries, rem, i = 0;
11422
11423 if (!mac_attr) {
11424 err = -EINVAL;
11425 goto out;
11426 }
11427
11428 n_entries = validate_acl_mac_addrs(mac_attr);
11429 if (n_entries <= 0) {
11430 err = -EINVAL;
11431 goto out;
11432 }
11433
11434 func->srf_num_macs = n_entries;
11435 func->srf_macs =
11436 kzalloc(sizeof(*func->srf_macs) * n_entries,
11437 GFP_KERNEL);
11438 if (!func->srf_macs) {
11439 err = -ENOMEM;
11440 goto out;
11441 }
11442
11443 nla_for_each_nested(attr, mac_attr, rem)
11444 memcpy(func->srf_macs[i++].addr, nla_data(attr),
11445 sizeof(*func->srf_macs));
11446 }
11447 }
11448
11449 if (tb[NL80211_NAN_FUNC_TX_MATCH_FILTER]) {
11450 err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER],
11451 func, true);
11452 if (err)
11453 goto out;
11454 }
11455
11456 if (tb[NL80211_NAN_FUNC_RX_MATCH_FILTER]) {
11457 err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER],
11458 func, false);
11459 if (err)
11460 goto out;
11461 }
11462
11463 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11464 if (!msg) {
11465 err = -ENOMEM;
11466 goto out;
11467 }
11468
11469 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11470 NL80211_CMD_ADD_NAN_FUNCTION);
11471 /* This can't really happen - we just allocated 4KB */
11472 if (WARN_ON(!hdr)) {
11473 err = -ENOMEM;
11474 goto out;
11475 }
11476
11477 err = rdev_add_nan_func(rdev, wdev, func);
11478out:
11479 if (err < 0) {
11480 cfg80211_free_nan_func(func);
11481 nlmsg_free(msg);
11482 return err;
11483 }
11484
11485 /* propagate the instance id and cookie to userspace */
11486 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, func->cookie,
11487 NL80211_ATTR_PAD))
11488 goto nla_put_failure;
11489
11490 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11491 if (!func_attr)
11492 goto nla_put_failure;
11493
11494 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID,
11495 func->instance_id))
11496 goto nla_put_failure;
11497
11498 nla_nest_end(msg, func_attr);
11499
11500 genlmsg_end(msg, hdr);
11501 return genlmsg_reply(msg, info);
11502
11503nla_put_failure:
11504 nlmsg_free(msg);
11505 return -ENOBUFS;
11506}
11507
11508static int nl80211_nan_del_func(struct sk_buff *skb,
11509 struct genl_info *info)
11510{
11511 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11512 struct wireless_dev *wdev = info->user_ptr[1];
11513 u64 cookie;
11514
11515 if (wdev->iftype != NL80211_IFTYPE_NAN)
11516 return -EOPNOTSUPP;
11517
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011518 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030011519 return -ENOTCONN;
11520
11521 if (!info->attrs[NL80211_ATTR_COOKIE])
11522 return -EINVAL;
11523
Ayala Bekera442b762016-09-20 17:31:15 +030011524 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
11525
11526 rdev_del_nan_func(rdev, wdev, cookie);
11527
11528 return 0;
11529}
11530
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011531static int nl80211_nan_change_config(struct sk_buff *skb,
11532 struct genl_info *info)
11533{
11534 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11535 struct wireless_dev *wdev = info->user_ptr[1];
11536 struct cfg80211_nan_conf conf = {};
11537 u32 changed = 0;
11538
11539 if (wdev->iftype != NL80211_IFTYPE_NAN)
11540 return -EOPNOTSUPP;
11541
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011542 if (!wdev_running(wdev))
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011543 return -ENOTCONN;
11544
11545 if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
11546 conf.master_pref =
11547 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
11548 if (conf.master_pref <= 1 || conf.master_pref == 255)
11549 return -EINVAL;
11550
11551 changed |= CFG80211_NAN_CONF_CHANGED_PREF;
11552 }
11553
Luca Coelho85859892017-02-08 15:00:34 +020011554 if (info->attrs[NL80211_ATTR_BANDS]) {
11555 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
11556
11557 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
11558 return -EOPNOTSUPP;
11559
11560 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
11561 return -EINVAL;
11562
11563 conf.bands = bands;
11564 changed |= CFG80211_NAN_CONF_CHANGED_BANDS;
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011565 }
11566
11567 if (!changed)
11568 return -EINVAL;
11569
11570 return rdev_nan_change_conf(rdev, wdev, &conf, changed);
11571}
11572
Ayala Beker50bcd312016-09-20 17:31:17 +030011573void cfg80211_nan_match(struct wireless_dev *wdev,
11574 struct cfg80211_nan_match_params *match, gfp_t gfp)
11575{
11576 struct wiphy *wiphy = wdev->wiphy;
11577 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11578 struct nlattr *match_attr, *local_func_attr, *peer_func_attr;
11579 struct sk_buff *msg;
11580 void *hdr;
11581
11582 if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr))
11583 return;
11584
11585 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11586 if (!msg)
11587 return;
11588
11589 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH);
11590 if (!hdr) {
11591 nlmsg_free(msg);
11592 return;
11593 }
11594
11595 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11596 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11597 wdev->netdev->ifindex)) ||
11598 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11599 NL80211_ATTR_PAD))
11600 goto nla_put_failure;
11601
11602 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie,
11603 NL80211_ATTR_PAD) ||
11604 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr))
11605 goto nla_put_failure;
11606
11607 match_attr = nla_nest_start(msg, NL80211_ATTR_NAN_MATCH);
11608 if (!match_attr)
11609 goto nla_put_failure;
11610
11611 local_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_LOCAL);
11612 if (!local_func_attr)
11613 goto nla_put_failure;
11614
11615 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id))
11616 goto nla_put_failure;
11617
11618 nla_nest_end(msg, local_func_attr);
11619
11620 peer_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_PEER);
11621 if (!peer_func_attr)
11622 goto nla_put_failure;
11623
11624 if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) ||
11625 nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id))
11626 goto nla_put_failure;
11627
11628 if (match->info && match->info_len &&
11629 nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len,
11630 match->info))
11631 goto nla_put_failure;
11632
11633 nla_nest_end(msg, peer_func_attr);
11634 nla_nest_end(msg, match_attr);
11635 genlmsg_end(msg, hdr);
11636
11637 if (!wdev->owner_nlportid)
11638 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11639 msg, 0, NL80211_MCGRP_NAN, gfp);
11640 else
11641 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11642 wdev->owner_nlportid);
11643
11644 return;
11645
11646nla_put_failure:
11647 nlmsg_free(msg);
11648}
11649EXPORT_SYMBOL(cfg80211_nan_match);
11650
Ayala Beker368e5a72016-09-20 17:31:18 +030011651void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
11652 u8 inst_id,
11653 enum nl80211_nan_func_term_reason reason,
11654 u64 cookie, gfp_t gfp)
11655{
11656 struct wiphy *wiphy = wdev->wiphy;
11657 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11658 struct sk_buff *msg;
11659 struct nlattr *func_attr;
11660 void *hdr;
11661
11662 if (WARN_ON(!inst_id))
11663 return;
11664
11665 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11666 if (!msg)
11667 return;
11668
11669 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_NAN_FUNCTION);
11670 if (!hdr) {
11671 nlmsg_free(msg);
11672 return;
11673 }
11674
11675 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11676 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11677 wdev->netdev->ifindex)) ||
11678 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11679 NL80211_ATTR_PAD))
11680 goto nla_put_failure;
11681
11682 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
11683 NL80211_ATTR_PAD))
11684 goto nla_put_failure;
11685
11686 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11687 if (!func_attr)
11688 goto nla_put_failure;
11689
11690 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, inst_id) ||
11691 nla_put_u8(msg, NL80211_NAN_FUNC_TERM_REASON, reason))
11692 goto nla_put_failure;
11693
11694 nla_nest_end(msg, func_attr);
11695 genlmsg_end(msg, hdr);
11696
11697 if (!wdev->owner_nlportid)
11698 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11699 msg, 0, NL80211_MCGRP_NAN, gfp);
11700 else
11701 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11702 wdev->owner_nlportid);
11703
11704 return;
11705
11706nla_put_failure:
11707 nlmsg_free(msg);
11708}
11709EXPORT_SYMBOL(cfg80211_nan_func_terminated);
11710
Johannes Berg3713b4e2013-02-14 16:19:38 +010011711static int nl80211_get_protocol_features(struct sk_buff *skb,
11712 struct genl_info *info)
11713{
11714 void *hdr;
11715 struct sk_buff *msg;
11716
11717 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11718 if (!msg)
11719 return -ENOMEM;
11720
11721 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11722 NL80211_CMD_GET_PROTOCOL_FEATURES);
11723 if (!hdr)
11724 goto nla_put_failure;
11725
11726 if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
11727 NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
11728 goto nla_put_failure;
11729
11730 genlmsg_end(msg, hdr);
11731 return genlmsg_reply(msg, info);
11732
11733 nla_put_failure:
11734 kfree_skb(msg);
11735 return -ENOBUFS;
11736}
11737
Jouni Malinen355199e2013-02-27 17:14:27 +020011738static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
11739{
11740 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11741 struct cfg80211_update_ft_ies_params ft_params;
11742 struct net_device *dev = info->user_ptr[1];
11743
11744 if (!rdev->ops->update_ft_ies)
11745 return -EOPNOTSUPP;
11746
11747 if (!info->attrs[NL80211_ATTR_MDID] ||
11748 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
11749 return -EINVAL;
11750
11751 memset(&ft_params, 0, sizeof(ft_params));
11752 ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
11753 ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
11754 ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
11755
11756 return rdev_update_ft_ies(rdev, dev, &ft_params);
11757}
11758
Arend van Spriel5de17982013-04-18 15:49:00 +020011759static int nl80211_crit_protocol_start(struct sk_buff *skb,
11760 struct genl_info *info)
11761{
11762 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11763 struct wireless_dev *wdev = info->user_ptr[1];
11764 enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
11765 u16 duration;
11766 int ret;
11767
11768 if (!rdev->ops->crit_proto_start)
11769 return -EOPNOTSUPP;
11770
11771 if (WARN_ON(!rdev->ops->crit_proto_stop))
11772 return -EINVAL;
11773
11774 if (rdev->crit_proto_nlportid)
11775 return -EBUSY;
11776
11777 /* determine protocol if provided */
11778 if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
11779 proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
11780
11781 if (proto >= NUM_NL80211_CRIT_PROTO)
11782 return -EINVAL;
11783
11784 /* timeout must be provided */
11785 if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
11786 return -EINVAL;
11787
11788 duration =
11789 nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
11790
11791 if (duration > NL80211_CRIT_PROTO_MAX_DURATION)
11792 return -ERANGE;
11793
11794 ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
11795 if (!ret)
11796 rdev->crit_proto_nlportid = info->snd_portid;
11797
11798 return ret;
11799}
11800
11801static int nl80211_crit_protocol_stop(struct sk_buff *skb,
11802 struct genl_info *info)
11803{
11804 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11805 struct wireless_dev *wdev = info->user_ptr[1];
11806
11807 if (!rdev->ops->crit_proto_stop)
11808 return -EOPNOTSUPP;
11809
11810 if (rdev->crit_proto_nlportid) {
11811 rdev->crit_proto_nlportid = 0;
11812 rdev_crit_proto_stop(rdev, wdev);
11813 }
11814 return 0;
11815}
11816
Johannes Bergad7e7182013-11-13 13:37:47 +010011817static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
11818{
11819 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11820 struct wireless_dev *wdev =
11821 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
11822 int i, err;
11823 u32 vid, subcmd;
11824
11825 if (!rdev->wiphy.vendor_commands)
11826 return -EOPNOTSUPP;
11827
11828 if (IS_ERR(wdev)) {
11829 err = PTR_ERR(wdev);
11830 if (err != -EINVAL)
11831 return err;
11832 wdev = NULL;
11833 } else if (wdev->wiphy != &rdev->wiphy) {
11834 return -EINVAL;
11835 }
11836
11837 if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
11838 !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
11839 return -EINVAL;
11840
11841 vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
11842 subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
11843 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
11844 const struct wiphy_vendor_command *vcmd;
11845 void *data = NULL;
11846 int len = 0;
11847
11848 vcmd = &rdev->wiphy.vendor_commands[i];
11849
11850 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
11851 continue;
11852
11853 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
11854 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
11855 if (!wdev)
11856 return -EINVAL;
11857 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
11858 !wdev->netdev)
11859 return -EINVAL;
11860
11861 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011862 if (!wdev_running(wdev))
Johannes Bergad7e7182013-11-13 13:37:47 +010011863 return -ENETDOWN;
11864 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030011865
11866 if (!vcmd->doit)
11867 return -EOPNOTSUPP;
Johannes Bergad7e7182013-11-13 13:37:47 +010011868 } else {
11869 wdev = NULL;
11870 }
11871
11872 if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
11873 data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
11874 len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
11875 }
11876
11877 rdev->cur_cmd_info = info;
11878 err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
11879 data, len);
11880 rdev->cur_cmd_info = NULL;
11881 return err;
11882 }
11883
11884 return -EOPNOTSUPP;
11885}
11886
Johannes Berg7bdbe402015-08-15 22:39:49 +030011887static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
11888 struct netlink_callback *cb,
11889 struct cfg80211_registered_device **rdev,
11890 struct wireless_dev **wdev)
11891{
Johannes Bergc90c39d2016-10-24 14:40:01 +020011892 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011893 u32 vid, subcmd;
11894 unsigned int i;
11895 int vcmd_idx = -1;
11896 int err;
11897 void *data = NULL;
11898 unsigned int data_len = 0;
11899
Johannes Berg7bdbe402015-08-15 22:39:49 +030011900 if (cb->args[0]) {
11901 /* subtract the 1 again here */
11902 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
11903 struct wireless_dev *tmp;
11904
Johannes Bergea90e0d2017-03-15 14:26:04 +010011905 if (!wiphy)
11906 return -ENODEV;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011907 *rdev = wiphy_to_rdev(wiphy);
11908 *wdev = NULL;
11909
11910 if (cb->args[1]) {
Johannes Berg53873f12016-05-03 16:52:04 +030011911 list_for_each_entry(tmp, &wiphy->wdev_list, list) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011912 if (tmp->identifier == cb->args[1] - 1) {
11913 *wdev = tmp;
11914 break;
11915 }
11916 }
11917 }
11918
11919 /* keep rtnl locked in successful case */
11920 return 0;
11921 }
11922
Johannes Bergfceb6432017-04-12 14:34:07 +020011923 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, attrbuf,
11924 nl80211_fam.maxattr, nl80211_policy, NULL);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011925 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +010011926 return err;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011927
Johannes Bergc90c39d2016-10-24 14:40:01 +020011928 if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
Johannes Bergea90e0d2017-03-15 14:26:04 +010011929 !attrbuf[NL80211_ATTR_VENDOR_SUBCMD])
11930 return -EINVAL;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011931
Johannes Bergc90c39d2016-10-24 14:40:01 +020011932 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011933 if (IS_ERR(*wdev))
11934 *wdev = NULL;
11935
Johannes Bergc90c39d2016-10-24 14:40:01 +020011936 *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Bergea90e0d2017-03-15 14:26:04 +010011937 if (IS_ERR(*rdev))
11938 return PTR_ERR(*rdev);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011939
Johannes Bergc90c39d2016-10-24 14:40:01 +020011940 vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
11941 subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011942
11943 for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
11944 const struct wiphy_vendor_command *vcmd;
11945
11946 vcmd = &(*rdev)->wiphy.vendor_commands[i];
11947
11948 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
11949 continue;
11950
Johannes Bergea90e0d2017-03-15 14:26:04 +010011951 if (!vcmd->dumpit)
11952 return -EOPNOTSUPP;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011953
11954 vcmd_idx = i;
11955 break;
11956 }
11957
Johannes Bergea90e0d2017-03-15 14:26:04 +010011958 if (vcmd_idx < 0)
11959 return -EOPNOTSUPP;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011960
Johannes Bergc90c39d2016-10-24 14:40:01 +020011961 if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
11962 data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
11963 data_len = nla_len(attrbuf[NL80211_ATTR_VENDOR_DATA]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011964 }
11965
11966 /* 0 is the first index - add 1 to parse only once */
11967 cb->args[0] = (*rdev)->wiphy_idx + 1;
11968 /* add 1 to know if it was NULL */
11969 cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
11970 cb->args[2] = vcmd_idx;
11971 cb->args[3] = (unsigned long)data;
11972 cb->args[4] = data_len;
11973
11974 /* keep rtnl locked in successful case */
11975 return 0;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011976}
11977
11978static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
11979 struct netlink_callback *cb)
11980{
11981 struct cfg80211_registered_device *rdev;
11982 struct wireless_dev *wdev;
11983 unsigned int vcmd_idx;
11984 const struct wiphy_vendor_command *vcmd;
11985 void *data;
11986 int data_len;
11987 int err;
11988 struct nlattr *vendor_data;
11989
Johannes Bergea90e0d2017-03-15 14:26:04 +010011990 rtnl_lock();
Johannes Berg7bdbe402015-08-15 22:39:49 +030011991 err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
11992 if (err)
Johannes Bergea90e0d2017-03-15 14:26:04 +010011993 goto out;
Johannes Berg7bdbe402015-08-15 22:39:49 +030011994
11995 vcmd_idx = cb->args[2];
11996 data = (void *)cb->args[3];
11997 data_len = cb->args[4];
11998 vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
11999
12000 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
12001 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
Johannes Bergea90e0d2017-03-15 14:26:04 +010012002 if (!wdev) {
12003 err = -EINVAL;
12004 goto out;
12005 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030012006 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
Johannes Bergea90e0d2017-03-15 14:26:04 +010012007 !wdev->netdev) {
12008 err = -EINVAL;
12009 goto out;
12010 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030012011
12012 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Johannes Bergea90e0d2017-03-15 14:26:04 +010012013 if (!wdev_running(wdev)) {
12014 err = -ENETDOWN;
12015 goto out;
12016 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030012017 }
12018 }
12019
12020 while (1) {
12021 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
12022 cb->nlh->nlmsg_seq, NLM_F_MULTI,
12023 NL80211_CMD_VENDOR);
12024 if (!hdr)
12025 break;
12026
12027 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020012028 (wdev && nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
12029 wdev_id(wdev),
12030 NL80211_ATTR_PAD))) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030012031 genlmsg_cancel(skb, hdr);
12032 break;
12033 }
12034
12035 vendor_data = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
12036 if (!vendor_data) {
12037 genlmsg_cancel(skb, hdr);
12038 break;
12039 }
12040
12041 err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
12042 (unsigned long *)&cb->args[5]);
12043 nla_nest_end(skb, vendor_data);
12044
12045 if (err == -ENOBUFS || err == -ENOENT) {
12046 genlmsg_cancel(skb, hdr);
12047 break;
12048 } else if (err) {
12049 genlmsg_cancel(skb, hdr);
12050 goto out;
12051 }
12052
12053 genlmsg_end(skb, hdr);
12054 }
12055
12056 err = skb->len;
12057 out:
12058 rtnl_unlock();
12059 return err;
12060}
12061
Johannes Bergad7e7182013-11-13 13:37:47 +010012062struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
12063 enum nl80211_commands cmd,
12064 enum nl80211_attrs attr,
12065 int approxlen)
12066{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080012067 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Bergad7e7182013-11-13 13:37:47 +010012068
12069 if (WARN_ON(!rdev->cur_cmd_info))
12070 return NULL;
12071
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020012072 return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
Johannes Bergad7e7182013-11-13 13:37:47 +010012073 rdev->cur_cmd_info->snd_portid,
12074 rdev->cur_cmd_info->snd_seq,
Johannes Berg567ffc32013-12-18 14:43:31 +010012075 cmd, attr, NULL, GFP_KERNEL);
Johannes Bergad7e7182013-11-13 13:37:47 +010012076}
12077EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
12078
12079int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
12080{
12081 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
12082 void *hdr = ((void **)skb->cb)[1];
12083 struct nlattr *data = ((void **)skb->cb)[2];
12084
Johannes Bergbd8c78e2014-07-30 14:55:26 +020012085 /* clear CB data for netlink core to own from now on */
12086 memset(skb->cb, 0, sizeof(skb->cb));
12087
Johannes Bergad7e7182013-11-13 13:37:47 +010012088 if (WARN_ON(!rdev->cur_cmd_info)) {
12089 kfree_skb(skb);
12090 return -EINVAL;
12091 }
12092
12093 nla_nest_end(skb, data);
12094 genlmsg_end(skb, hdr);
12095 return genlmsg_reply(skb, rdev->cur_cmd_info);
12096}
12097EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
12098
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080012099static int nl80211_set_qos_map(struct sk_buff *skb,
12100 struct genl_info *info)
12101{
12102 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12103 struct cfg80211_qos_map *qos_map = NULL;
12104 struct net_device *dev = info->user_ptr[1];
12105 u8 *pos, len, num_des, des_len, des;
12106 int ret;
12107
12108 if (!rdev->ops->set_qos_map)
12109 return -EOPNOTSUPP;
12110
12111 if (info->attrs[NL80211_ATTR_QOS_MAP]) {
12112 pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
12113 len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
12114
12115 if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
12116 len > IEEE80211_QOS_MAP_LEN_MAX)
12117 return -EINVAL;
12118
12119 qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
12120 if (!qos_map)
12121 return -ENOMEM;
12122
12123 num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
12124 if (num_des) {
12125 des_len = num_des *
12126 sizeof(struct cfg80211_dscp_exception);
12127 memcpy(qos_map->dscp_exception, pos, des_len);
12128 qos_map->num_des = num_des;
12129 for (des = 0; des < num_des; des++) {
12130 if (qos_map->dscp_exception[des].up > 7) {
12131 kfree(qos_map);
12132 return -EINVAL;
12133 }
12134 }
12135 pos += des_len;
12136 }
12137 memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
12138 }
12139
12140 wdev_lock(dev->ieee80211_ptr);
12141 ret = nl80211_key_allowed(dev->ieee80211_ptr);
12142 if (!ret)
12143 ret = rdev_set_qos_map(rdev, dev, qos_map);
12144 wdev_unlock(dev->ieee80211_ptr);
12145
12146 kfree(qos_map);
12147 return ret;
12148}
12149
Johannes Berg960d01a2014-09-09 22:55:35 +030012150static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
12151{
12152 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12153 struct net_device *dev = info->user_ptr[1];
12154 struct wireless_dev *wdev = dev->ieee80211_ptr;
12155 const u8 *peer;
12156 u8 tsid, up;
12157 u16 admitted_time = 0;
12158 int err;
12159
Johannes Berg723e73a2014-10-22 09:25:06 +020012160 if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
Johannes Berg960d01a2014-09-09 22:55:35 +030012161 return -EOPNOTSUPP;
12162
12163 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
12164 !info->attrs[NL80211_ATTR_USER_PRIO])
12165 return -EINVAL;
12166
12167 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
12168 if (tsid >= IEEE80211_NUM_TIDS)
12169 return -EINVAL;
12170
12171 up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
12172 if (up >= IEEE80211_NUM_UPS)
12173 return -EINVAL;
12174
12175 /* WMM uses TIDs 0-7 even for TSPEC */
Johannes Berg723e73a2014-10-22 09:25:06 +020012176 if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
Johannes Berg960d01a2014-09-09 22:55:35 +030012177 /* TODO: handle 802.11 TSPEC/admission control
Johannes Berg723e73a2014-10-22 09:25:06 +020012178 * need more attributes for that (e.g. BA session requirement);
12179 * change the WMM adminssion test above to allow both then
Johannes Berg960d01a2014-09-09 22:55:35 +030012180 */
12181 return -EINVAL;
12182 }
12183
12184 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
12185
12186 if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
12187 admitted_time =
12188 nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
12189 if (!admitted_time)
12190 return -EINVAL;
12191 }
12192
12193 wdev_lock(wdev);
12194 switch (wdev->iftype) {
12195 case NL80211_IFTYPE_STATION:
12196 case NL80211_IFTYPE_P2P_CLIENT:
12197 if (wdev->current_bss)
12198 break;
12199 err = -ENOTCONN;
12200 goto out;
12201 default:
12202 err = -EOPNOTSUPP;
12203 goto out;
12204 }
12205
12206 err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
12207
12208 out:
12209 wdev_unlock(wdev);
12210 return err;
12211}
12212
12213static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
12214{
12215 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12216 struct net_device *dev = info->user_ptr[1];
12217 struct wireless_dev *wdev = dev->ieee80211_ptr;
12218 const u8 *peer;
12219 u8 tsid;
12220 int err;
12221
12222 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
12223 return -EINVAL;
12224
12225 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
12226 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
12227
12228 wdev_lock(wdev);
12229 err = rdev_del_tx_ts(rdev, dev, tsid, peer);
12230 wdev_unlock(wdev);
12231
12232 return err;
12233}
12234
Arik Nemtsov1057d352014-11-19 12:54:26 +020012235static int nl80211_tdls_channel_switch(struct sk_buff *skb,
12236 struct genl_info *info)
12237{
12238 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12239 struct net_device *dev = info->user_ptr[1];
12240 struct wireless_dev *wdev = dev->ieee80211_ptr;
12241 struct cfg80211_chan_def chandef = {};
12242 const u8 *addr;
12243 u8 oper_class;
12244 int err;
12245
12246 if (!rdev->ops->tdls_channel_switch ||
12247 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
12248 return -EOPNOTSUPP;
12249
12250 switch (dev->ieee80211_ptr->iftype) {
12251 case NL80211_IFTYPE_STATION:
12252 case NL80211_IFTYPE_P2P_CLIENT:
12253 break;
12254 default:
12255 return -EOPNOTSUPP;
12256 }
12257
12258 if (!info->attrs[NL80211_ATTR_MAC] ||
12259 !info->attrs[NL80211_ATTR_OPER_CLASS])
12260 return -EINVAL;
12261
12262 err = nl80211_parse_chandef(rdev, info, &chandef);
12263 if (err)
12264 return err;
12265
12266 /*
12267 * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012
12268 * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the
12269 * specification is not defined for them.
12270 */
Johannes Berg57fbcce2016-04-12 15:56:15 +020012271 if (chandef.chan->band == NL80211_BAND_2GHZ &&
Arik Nemtsov1057d352014-11-19 12:54:26 +020012272 chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
12273 chandef.width != NL80211_CHAN_WIDTH_20)
12274 return -EINVAL;
12275
12276 /* we will be active on the TDLS link */
Arik Nemtsov923b3522015-07-08 15:41:44 +030012277 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
12278 wdev->iftype))
Arik Nemtsov1057d352014-11-19 12:54:26 +020012279 return -EINVAL;
12280
12281 /* don't allow switching to DFS channels */
12282 if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype))
12283 return -EINVAL;
12284
12285 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
12286 oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]);
12287
12288 wdev_lock(wdev);
12289 err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef);
12290 wdev_unlock(wdev);
12291
12292 return err;
12293}
12294
12295static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
12296 struct genl_info *info)
12297{
12298 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12299 struct net_device *dev = info->user_ptr[1];
12300 struct wireless_dev *wdev = dev->ieee80211_ptr;
12301 const u8 *addr;
12302
12303 if (!rdev->ops->tdls_channel_switch ||
12304 !rdev->ops->tdls_cancel_channel_switch ||
12305 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
12306 return -EOPNOTSUPP;
12307
12308 switch (dev->ieee80211_ptr->iftype) {
12309 case NL80211_IFTYPE_STATION:
12310 case NL80211_IFTYPE_P2P_CLIENT:
12311 break;
12312 default:
12313 return -EOPNOTSUPP;
12314 }
12315
12316 if (!info->attrs[NL80211_ATTR_MAC])
12317 return -EINVAL;
12318
12319 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
12320
12321 wdev_lock(wdev);
12322 rdev_tdls_cancel_channel_switch(rdev, dev, addr);
12323 wdev_unlock(wdev);
12324
12325 return 0;
12326}
12327
Michael Braunce0ce132016-10-10 19:12:22 +020012328static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
12329 struct genl_info *info)
12330{
12331 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12332 struct net_device *dev = info->user_ptr[1];
12333 struct wireless_dev *wdev = dev->ieee80211_ptr;
12334 const struct nlattr *nla;
12335 bool enabled;
12336
Michael Braunce0ce132016-10-10 19:12:22 +020012337 if (!rdev->ops->set_multicast_to_unicast)
12338 return -EOPNOTSUPP;
12339
12340 if (wdev->iftype != NL80211_IFTYPE_AP &&
12341 wdev->iftype != NL80211_IFTYPE_P2P_GO)
12342 return -EOPNOTSUPP;
12343
12344 nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
12345 enabled = nla_get_flag(nla);
12346
12347 return rdev_set_multicast_to_unicast(rdev, dev, enabled);
12348}
12349
Avraham Stern3a00df52017-06-09 13:08:43 +010012350static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
12351{
12352 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12353 struct net_device *dev = info->user_ptr[1];
12354 struct wireless_dev *wdev = dev->ieee80211_ptr;
12355 struct cfg80211_pmk_conf pmk_conf = {};
12356 int ret;
12357
12358 if (wdev->iftype != NL80211_IFTYPE_STATION &&
12359 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
12360 return -EOPNOTSUPP;
12361
12362 if (!wiphy_ext_feature_isset(&rdev->wiphy,
12363 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
12364 return -EOPNOTSUPP;
12365
12366 if (!info->attrs[NL80211_ATTR_MAC] || !info->attrs[NL80211_ATTR_PMK])
12367 return -EINVAL;
12368
12369 wdev_lock(wdev);
12370 if (!wdev->current_bss) {
12371 ret = -ENOTCONN;
12372 goto out;
12373 }
12374
12375 pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
12376 if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) {
12377 ret = -EINVAL;
12378 goto out;
12379 }
12380
12381 pmk_conf.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
12382 pmk_conf.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
12383 if (pmk_conf.pmk_len != WLAN_PMK_LEN &&
12384 pmk_conf.pmk_len != WLAN_PMK_LEN_SUITE_B_192) {
12385 ret = -EINVAL;
12386 goto out;
12387 }
12388
12389 if (info->attrs[NL80211_ATTR_PMKR0_NAME]) {
12390 int r0_name_len = nla_len(info->attrs[NL80211_ATTR_PMKR0_NAME]);
12391
12392 if (r0_name_len != WLAN_PMK_NAME_LEN) {
12393 ret = -EINVAL;
12394 goto out;
12395 }
12396
12397 pmk_conf.pmk_r0_name =
12398 nla_data(info->attrs[NL80211_ATTR_PMKR0_NAME]);
12399 }
12400
12401 ret = rdev_set_pmk(rdev, dev, &pmk_conf);
12402out:
12403 wdev_unlock(wdev);
12404 return ret;
12405}
12406
12407static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
12408{
12409 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12410 struct net_device *dev = info->user_ptr[1];
12411 struct wireless_dev *wdev = dev->ieee80211_ptr;
12412 const u8 *aa;
12413 int ret;
12414
12415 if (wdev->iftype != NL80211_IFTYPE_STATION &&
12416 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
12417 return -EOPNOTSUPP;
12418
12419 if (!wiphy_ext_feature_isset(&rdev->wiphy,
12420 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
12421 return -EOPNOTSUPP;
12422
12423 if (!info->attrs[NL80211_ATTR_MAC])
12424 return -EINVAL;
12425
12426 wdev_lock(wdev);
12427 aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
12428 ret = rdev_del_pmk(rdev, dev, aa);
12429 wdev_unlock(wdev);
12430
12431 return ret;
12432}
12433
Johannes Berg4c476992010-10-04 21:36:35 +020012434#define NL80211_FLAG_NEED_WIPHY 0x01
12435#define NL80211_FLAG_NEED_NETDEV 0x02
12436#define NL80211_FLAG_NEED_RTNL 0x04
Johannes Berg41265712010-10-04 21:14:05 +020012437#define NL80211_FLAG_CHECK_NETDEV_UP 0x08
12438#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
12439 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg1bf614e2012-06-15 15:23:36 +020012440#define NL80211_FLAG_NEED_WDEV 0x10
Johannes Berg98104fde2012-06-16 00:19:54 +020012441/* If a netdev is associated, it must be UP, P2P must be started */
Johannes Berg1bf614e2012-06-15 15:23:36 +020012442#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
12443 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg5393b912014-09-10 15:00:16 +030012444#define NL80211_FLAG_CLEAR_SKB 0x20
Johannes Berg4c476992010-10-04 21:36:35 +020012445
Johannes Bergf84f7712013-11-14 17:14:45 +010012446static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020012447 struct genl_info *info)
12448{
12449 struct cfg80211_registered_device *rdev;
Johannes Berg89a54e42012-06-15 14:33:17 +020012450 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020012451 struct net_device *dev;
Johannes Berg4c476992010-10-04 21:36:35 +020012452 bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
12453
12454 if (rtnl)
12455 rtnl_lock();
12456
12457 if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
Johannes Berg4f7eff12012-06-15 14:14:22 +020012458 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
Johannes Berg4c476992010-10-04 21:36:35 +020012459 if (IS_ERR(rdev)) {
12460 if (rtnl)
12461 rtnl_unlock();
12462 return PTR_ERR(rdev);
12463 }
12464 info->user_ptr[0] = rdev;
Johannes Berg1bf614e2012-06-15 15:23:36 +020012465 } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
12466 ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
Johannes Berg5fe231e2013-05-08 21:45:15 +020012467 ASSERT_RTNL();
12468
Johannes Berg89a54e42012-06-15 14:33:17 +020012469 wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
12470 info->attrs);
12471 if (IS_ERR(wdev)) {
Johannes Berg4c476992010-10-04 21:36:35 +020012472 if (rtnl)
12473 rtnl_unlock();
Johannes Berg89a54e42012-06-15 14:33:17 +020012474 return PTR_ERR(wdev);
Johannes Berg4c476992010-10-04 21:36:35 +020012475 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012476
Johannes Berg89a54e42012-06-15 14:33:17 +020012477 dev = wdev->netdev;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080012478 rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg89a54e42012-06-15 14:33:17 +020012479
Johannes Berg1bf614e2012-06-15 15:23:36 +020012480 if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
12481 if (!dev) {
Johannes Berg1bf614e2012-06-15 15:23:36 +020012482 if (rtnl)
12483 rtnl_unlock();
12484 return -EINVAL;
12485 }
12486
12487 info->user_ptr[1] = dev;
12488 } else {
12489 info->user_ptr[1] = wdev;
Johannes Berg41265712010-10-04 21:14:05 +020012490 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012491
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012492 if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
12493 !wdev_running(wdev)) {
12494 if (rtnl)
12495 rtnl_unlock();
12496 return -ENETDOWN;
Johannes Berg1bf614e2012-06-15 15:23:36 +020012497 }
12498
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012499 if (dev)
12500 dev_hold(dev);
12501
Johannes Berg4c476992010-10-04 21:36:35 +020012502 info->user_ptr[0] = rdev;
Johannes Berg4c476992010-10-04 21:36:35 +020012503 }
12504
12505 return 0;
12506}
12507
Johannes Bergf84f7712013-11-14 17:14:45 +010012508static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020012509 struct genl_info *info)
12510{
Johannes Berg1bf614e2012-06-15 15:23:36 +020012511 if (info->user_ptr[1]) {
12512 if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
12513 struct wireless_dev *wdev = info->user_ptr[1];
12514
12515 if (wdev->netdev)
12516 dev_put(wdev->netdev);
12517 } else {
12518 dev_put(info->user_ptr[1]);
12519 }
12520 }
Johannes Berg5393b912014-09-10 15:00:16 +030012521
Johannes Berg4c476992010-10-04 21:36:35 +020012522 if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
12523 rtnl_unlock();
Johannes Berg5393b912014-09-10 15:00:16 +030012524
12525 /* If needed, clear the netlink message payload from the SKB
12526 * as it might contain key data that shouldn't stick around on
12527 * the heap after the SKB is freed. The netlink message header
12528 * is still needed for further processing, so leave it intact.
12529 */
12530 if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) {
12531 struct nlmsghdr *nlh = nlmsg_hdr(skb);
12532
12533 memset(nlmsg_data(nlh), 0, nlmsg_len(nlh));
12534 }
Johannes Berg4c476992010-10-04 21:36:35 +020012535}
12536
Johannes Berg4534de82013-11-14 17:14:46 +010012537static const struct genl_ops nl80211_ops[] = {
Johannes Berg55682962007-09-20 13:09:35 -040012538 {
12539 .cmd = NL80211_CMD_GET_WIPHY,
12540 .doit = nl80211_get_wiphy,
12541 .dumpit = nl80211_dump_wiphy,
Johannes Berg86e8cf92013-06-19 10:57:22 +020012542 .done = nl80211_dump_wiphy_done,
Johannes Berg55682962007-09-20 13:09:35 -040012543 .policy = nl80211_policy,
12544 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012545 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12546 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012547 },
12548 {
12549 .cmd = NL80211_CMD_SET_WIPHY,
12550 .doit = nl80211_set_wiphy,
12551 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012552 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012553 .internal_flags = NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012554 },
12555 {
12556 .cmd = NL80211_CMD_GET_INTERFACE,
12557 .doit = nl80211_get_interface,
12558 .dumpit = nl80211_dump_interface,
12559 .policy = nl80211_policy,
12560 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012561 .internal_flags = NL80211_FLAG_NEED_WDEV |
12562 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012563 },
12564 {
12565 .cmd = NL80211_CMD_SET_INTERFACE,
12566 .doit = nl80211_set_interface,
12567 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012568 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012569 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12570 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012571 },
12572 {
12573 .cmd = NL80211_CMD_NEW_INTERFACE,
12574 .doit = nl80211_new_interface,
12575 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012576 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012577 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12578 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012579 },
12580 {
12581 .cmd = NL80211_CMD_DEL_INTERFACE,
12582 .doit = nl80211_del_interface,
12583 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012584 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg84efbb82012-06-16 00:00:26 +020012585 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012586 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012587 },
Johannes Berg41ade002007-12-19 02:03:29 +010012588 {
12589 .cmd = NL80211_CMD_GET_KEY,
12590 .doit = nl80211_get_key,
12591 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012592 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012593 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012594 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012595 },
12596 {
12597 .cmd = NL80211_CMD_SET_KEY,
12598 .doit = nl80211_set_key,
12599 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012600 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012601 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012602 NL80211_FLAG_NEED_RTNL |
12603 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012604 },
12605 {
12606 .cmd = NL80211_CMD_NEW_KEY,
12607 .doit = nl80211_new_key,
12608 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012609 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012610 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012611 NL80211_FLAG_NEED_RTNL |
12612 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012613 },
12614 {
12615 .cmd = NL80211_CMD_DEL_KEY,
12616 .doit = nl80211_del_key,
12617 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012618 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012619 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012620 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012621 },
Johannes Berged1b6cc2007-12-19 02:03:32 +010012622 {
12623 .cmd = NL80211_CMD_SET_BEACON,
12624 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012625 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012626 .doit = nl80211_set_beacon,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012627 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012628 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012629 },
12630 {
Johannes Berg88600202012-02-13 15:17:18 +010012631 .cmd = NL80211_CMD_START_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012632 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012633 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012634 .doit = nl80211_start_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012635 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012636 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012637 },
12638 {
Johannes Berg88600202012-02-13 15:17:18 +010012639 .cmd = NL80211_CMD_STOP_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012640 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012641 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012642 .doit = nl80211_stop_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012643 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012644 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012645 },
Johannes Berg5727ef12007-12-19 02:03:34 +010012646 {
12647 .cmd = NL80211_CMD_GET_STATION,
12648 .doit = nl80211_get_station,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012649 .dumpit = nl80211_dump_station,
Johannes Berg5727ef12007-12-19 02:03:34 +010012650 .policy = nl80211_policy,
Johannes Berg4c476992010-10-04 21:36:35 +020012651 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12652 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012653 },
12654 {
12655 .cmd = NL80211_CMD_SET_STATION,
12656 .doit = nl80211_set_station,
12657 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012658 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012659 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012660 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012661 },
12662 {
12663 .cmd = NL80211_CMD_NEW_STATION,
12664 .doit = nl80211_new_station,
12665 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012666 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012667 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012668 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012669 },
12670 {
12671 .cmd = NL80211_CMD_DEL_STATION,
12672 .doit = nl80211_del_station,
12673 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012674 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012675 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012676 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012677 },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012678 {
12679 .cmd = NL80211_CMD_GET_MPATH,
12680 .doit = nl80211_get_mpath,
12681 .dumpit = nl80211_dump_mpath,
12682 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012683 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012684 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012685 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012686 },
12687 {
Henning Rogge66be7d22014-09-12 08:58:49 +020012688 .cmd = NL80211_CMD_GET_MPP,
12689 .doit = nl80211_get_mpp,
12690 .dumpit = nl80211_dump_mpp,
12691 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012692 .flags = GENL_UNS_ADMIN_PERM,
Henning Rogge66be7d22014-09-12 08:58:49 +020012693 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12694 NL80211_FLAG_NEED_RTNL,
12695 },
12696 {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012697 .cmd = NL80211_CMD_SET_MPATH,
12698 .doit = nl80211_set_mpath,
12699 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012700 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012701 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012702 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012703 },
12704 {
12705 .cmd = NL80211_CMD_NEW_MPATH,
12706 .doit = nl80211_new_mpath,
12707 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012708 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012709 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012710 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012711 },
12712 {
12713 .cmd = NL80211_CMD_DEL_MPATH,
12714 .doit = nl80211_del_mpath,
12715 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012716 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012717 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012718 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012719 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012720 {
12721 .cmd = NL80211_CMD_SET_BSS,
12722 .doit = nl80211_set_bss,
12723 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012724 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012725 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012726 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012727 },
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012728 {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012729 .cmd = NL80211_CMD_GET_REG,
Arik Nemtsovad30ca22014-12-15 19:25:59 +020012730 .doit = nl80211_get_reg_do,
12731 .dumpit = nl80211_get_reg_dump,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012732 .policy = nl80211_policy,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012733 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012734 /* can be retrieved by unprivileged users */
12735 },
Johannes Bergb6863032015-10-15 09:25:18 +020012736#ifdef CONFIG_CFG80211_CRDA_SUPPORT
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012737 {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012738 .cmd = NL80211_CMD_SET_REG,
12739 .doit = nl80211_set_reg,
12740 .policy = nl80211_policy,
12741 .flags = GENL_ADMIN_PERM,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012742 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012743 },
Johannes Bergb6863032015-10-15 09:25:18 +020012744#endif
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012745 {
12746 .cmd = NL80211_CMD_REQ_SET_REG,
12747 .doit = nl80211_req_set_reg,
12748 .policy = nl80211_policy,
12749 .flags = GENL_ADMIN_PERM,
12750 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012751 {
Johannes Berg1ea4ff32017-09-13 16:07:22 +020012752 .cmd = NL80211_CMD_RELOAD_REGDB,
12753 .doit = nl80211_reload_regdb,
12754 .policy = nl80211_policy,
12755 .flags = GENL_ADMIN_PERM,
12756 },
12757 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012758 .cmd = NL80211_CMD_GET_MESH_CONFIG,
12759 .doit = nl80211_get_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012760 .policy = nl80211_policy,
12761 /* can be retrieved by unprivileged users */
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012762 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012763 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012764 },
12765 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012766 .cmd = NL80211_CMD_SET_MESH_CONFIG,
12767 .doit = nl80211_update_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012768 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012769 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012770 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012771 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012772 },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +020012773 {
Johannes Berg2a519312009-02-10 21:25:55 +010012774 .cmd = NL80211_CMD_TRIGGER_SCAN,
12775 .doit = nl80211_trigger_scan,
12776 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012777 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergfd014282012-06-18 19:17:03 +020012778 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012779 NL80211_FLAG_NEED_RTNL,
Johannes Berg2a519312009-02-10 21:25:55 +010012780 },
12781 {
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053012782 .cmd = NL80211_CMD_ABORT_SCAN,
12783 .doit = nl80211_abort_scan,
12784 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012785 .flags = GENL_UNS_ADMIN_PERM,
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053012786 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12787 NL80211_FLAG_NEED_RTNL,
12788 },
12789 {
Johannes Berg2a519312009-02-10 21:25:55 +010012790 .cmd = NL80211_CMD_GET_SCAN,
12791 .policy = nl80211_policy,
12792 .dumpit = nl80211_dump_scan,
12793 },
Jouni Malinen636a5d32009-03-19 13:39:22 +020012794 {
Luciano Coelho807f8a82011-05-11 17:09:35 +030012795 .cmd = NL80211_CMD_START_SCHED_SCAN,
12796 .doit = nl80211_start_sched_scan,
12797 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012798 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012799 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12800 NL80211_FLAG_NEED_RTNL,
12801 },
12802 {
12803 .cmd = NL80211_CMD_STOP_SCHED_SCAN,
12804 .doit = nl80211_stop_sched_scan,
12805 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012806 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012807 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12808 NL80211_FLAG_NEED_RTNL,
12809 },
12810 {
Jouni Malinen636a5d32009-03-19 13:39:22 +020012811 .cmd = NL80211_CMD_AUTHENTICATE,
12812 .doit = nl80211_authenticate,
12813 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012814 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012815 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012816 NL80211_FLAG_NEED_RTNL |
12817 NL80211_FLAG_CLEAR_SKB,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012818 },
12819 {
12820 .cmd = NL80211_CMD_ASSOCIATE,
12821 .doit = nl80211_associate,
12822 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012823 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012824 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012825 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012826 },
12827 {
12828 .cmd = NL80211_CMD_DEAUTHENTICATE,
12829 .doit = nl80211_deauthenticate,
12830 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012831 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012832 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012833 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012834 },
12835 {
12836 .cmd = NL80211_CMD_DISASSOCIATE,
12837 .doit = nl80211_disassociate,
12838 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012839 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012840 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012841 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012842 },
Johannes Berg04a773a2009-04-19 21:24:32 +020012843 {
12844 .cmd = NL80211_CMD_JOIN_IBSS,
12845 .doit = nl80211_join_ibss,
12846 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012847 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012848 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012849 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020012850 },
12851 {
12852 .cmd = NL80211_CMD_LEAVE_IBSS,
12853 .doit = nl80211_leave_ibss,
12854 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012855 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012856 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012857 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020012858 },
Johannes Bergaff89a92009-07-01 21:26:51 +020012859#ifdef CONFIG_NL80211_TESTMODE
12860 {
12861 .cmd = NL80211_CMD_TESTMODE,
12862 .doit = nl80211_testmode_do,
Wey-Yi Guy71063f02011-05-20 09:05:54 -070012863 .dumpit = nl80211_testmode_dump,
Johannes Bergaff89a92009-07-01 21:26:51 +020012864 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012865 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012866 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12867 NL80211_FLAG_NEED_RTNL,
Johannes Bergaff89a92009-07-01 21:26:51 +020012868 },
12869#endif
Samuel Ortizb23aa672009-07-01 21:26:54 +020012870 {
12871 .cmd = NL80211_CMD_CONNECT,
12872 .doit = nl80211_connect,
12873 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012874 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012875 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012876 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020012877 },
12878 {
vamsi krishna088e8df2016-10-27 16:51:11 +030012879 .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
12880 .doit = nl80211_update_connect_params,
12881 .policy = nl80211_policy,
12882 .flags = GENL_ADMIN_PERM,
12883 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12884 NL80211_FLAG_NEED_RTNL,
12885 },
12886 {
Samuel Ortizb23aa672009-07-01 21:26:54 +020012887 .cmd = NL80211_CMD_DISCONNECT,
12888 .doit = nl80211_disconnect,
12889 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012890 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012891 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012892 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020012893 },
Johannes Berg463d0182009-07-14 00:33:35 +020012894 {
12895 .cmd = NL80211_CMD_SET_WIPHY_NETNS,
12896 .doit = nl80211_wiphy_netns,
12897 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012898 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012899 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12900 NL80211_FLAG_NEED_RTNL,
Johannes Berg463d0182009-07-14 00:33:35 +020012901 },
Holger Schurig61fa7132009-11-11 12:25:40 +010012902 {
12903 .cmd = NL80211_CMD_GET_SURVEY,
12904 .policy = nl80211_policy,
12905 .dumpit = nl80211_dump_survey,
12906 },
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012907 {
12908 .cmd = NL80211_CMD_SET_PMKSA,
12909 .doit = nl80211_setdel_pmksa,
12910 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012911 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012912 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012913 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012914 },
12915 {
12916 .cmd = NL80211_CMD_DEL_PMKSA,
12917 .doit = nl80211_setdel_pmksa,
12918 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012919 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012920 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012921 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012922 },
12923 {
12924 .cmd = NL80211_CMD_FLUSH_PMKSA,
12925 .doit = nl80211_flush_pmksa,
12926 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012927 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012928 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012929 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012930 },
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012931 {
12932 .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
12933 .doit = nl80211_remain_on_channel,
12934 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012935 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012936 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012937 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012938 },
12939 {
12940 .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
12941 .doit = nl80211_cancel_remain_on_channel,
12942 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012943 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012944 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012945 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012946 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +020012947 {
12948 .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
12949 .doit = nl80211_set_tx_bitrate_mask,
12950 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012951 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012952 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12953 NL80211_FLAG_NEED_RTNL,
Jouni Malinen13ae75b2009-12-29 12:59:45 +020012954 },
Jouni Malinen026331c2010-02-15 12:53:10 +020012955 {
Johannes Berg2e161f72010-08-12 15:38:38 +020012956 .cmd = NL80211_CMD_REGISTER_FRAME,
12957 .doit = nl80211_register_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020012958 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012959 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012960 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012961 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020012962 },
12963 {
Johannes Berg2e161f72010-08-12 15:38:38 +020012964 .cmd = NL80211_CMD_FRAME,
12965 .doit = nl80211_tx_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020012966 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012967 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012968 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012969 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020012970 },
Kalle Valoffb9eb32010-02-17 17:58:10 +020012971 {
Johannes Bergf7ca38d2010-11-25 10:02:29 +010012972 .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
12973 .doit = nl80211_tx_mgmt_cancel_wait,
12974 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012975 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012976 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Bergf7ca38d2010-11-25 10:02:29 +010012977 NL80211_FLAG_NEED_RTNL,
12978 },
12979 {
Kalle Valoffb9eb32010-02-17 17:58:10 +020012980 .cmd = NL80211_CMD_SET_POWER_SAVE,
12981 .doit = nl80211_set_power_save,
12982 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012983 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012984 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12985 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020012986 },
12987 {
12988 .cmd = NL80211_CMD_GET_POWER_SAVE,
12989 .doit = nl80211_get_power_save,
12990 .policy = nl80211_policy,
12991 /* can be retrieved by unprivileged users */
Johannes Berg4c476992010-10-04 21:36:35 +020012992 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12993 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020012994 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012995 {
12996 .cmd = NL80211_CMD_SET_CQM,
12997 .doit = nl80211_set_cqm,
12998 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012999 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020013000 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13001 NL80211_FLAG_NEED_RTNL,
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020013002 },
Johannes Bergf444de02010-05-05 15:25:02 +020013003 {
13004 .cmd = NL80211_CMD_SET_CHANNEL,
13005 .doit = nl80211_set_channel,
13006 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013007 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020013008 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13009 NL80211_FLAG_NEED_RTNL,
Johannes Bergf444de02010-05-05 15:25:02 +020013010 },
Bill Jordane8347eb2010-10-01 13:54:28 -040013011 {
13012 .cmd = NL80211_CMD_SET_WDS_PEER,
13013 .doit = nl80211_set_wds_peer,
13014 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013015 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg43b19952010-10-07 13:10:30 +020013016 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13017 NL80211_FLAG_NEED_RTNL,
Bill Jordane8347eb2010-10-01 13:54:28 -040013018 },
Johannes Berg29cbe682010-12-03 09:20:44 +010013019 {
13020 .cmd = NL80211_CMD_JOIN_MESH,
13021 .doit = nl80211_join_mesh,
13022 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013023 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010013024 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13025 NL80211_FLAG_NEED_RTNL,
13026 },
13027 {
13028 .cmd = NL80211_CMD_LEAVE_MESH,
13029 .doit = nl80211_leave_mesh,
13030 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013031 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010013032 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13033 NL80211_FLAG_NEED_RTNL,
13034 },
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010013035 {
13036 .cmd = NL80211_CMD_JOIN_OCB,
13037 .doit = nl80211_join_ocb,
13038 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013039 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010013040 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13041 NL80211_FLAG_NEED_RTNL,
13042 },
13043 {
13044 .cmd = NL80211_CMD_LEAVE_OCB,
13045 .doit = nl80211_leave_ocb,
13046 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013047 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010013048 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13049 NL80211_FLAG_NEED_RTNL,
13050 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020013051#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +020013052 {
13053 .cmd = NL80211_CMD_GET_WOWLAN,
13054 .doit = nl80211_get_wowlan,
13055 .policy = nl80211_policy,
13056 /* can be retrieved by unprivileged users */
13057 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13058 NL80211_FLAG_NEED_RTNL,
13059 },
13060 {
13061 .cmd = NL80211_CMD_SET_WOWLAN,
13062 .doit = nl80211_set_wowlan,
13063 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013064 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergff1b6e62011-05-04 15:37:28 +020013065 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13066 NL80211_FLAG_NEED_RTNL,
13067 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020013068#endif
Johannes Berge5497d72011-07-05 16:35:40 +020013069 {
13070 .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
13071 .doit = nl80211_set_rekey_data,
13072 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013073 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berge5497d72011-07-05 16:35:40 +020013074 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030013075 NL80211_FLAG_NEED_RTNL |
13076 NL80211_FLAG_CLEAR_SKB,
Johannes Berge5497d72011-07-05 16:35:40 +020013077 },
Arik Nemtsov109086c2011-09-28 14:12:50 +030013078 {
13079 .cmd = NL80211_CMD_TDLS_MGMT,
13080 .doit = nl80211_tdls_mgmt,
13081 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013082 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030013083 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13084 NL80211_FLAG_NEED_RTNL,
13085 },
13086 {
13087 .cmd = NL80211_CMD_TDLS_OPER,
13088 .doit = nl80211_tdls_oper,
13089 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013090 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030013091 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13092 NL80211_FLAG_NEED_RTNL,
13093 },
Johannes Berg28946da2011-11-04 11:18:12 +010013094 {
13095 .cmd = NL80211_CMD_UNEXPECTED_FRAME,
13096 .doit = nl80211_register_unexpected_frame,
13097 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013098 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg28946da2011-11-04 11:18:12 +010013099 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13100 NL80211_FLAG_NEED_RTNL,
13101 },
Johannes Berg7f6cf312011-11-04 11:18:15 +010013102 {
13103 .cmd = NL80211_CMD_PROBE_CLIENT,
13104 .doit = nl80211_probe_client,
13105 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013106 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020013107 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg7f6cf312011-11-04 11:18:15 +010013108 NL80211_FLAG_NEED_RTNL,
13109 },
Johannes Berg5e760232011-11-04 11:18:17 +010013110 {
13111 .cmd = NL80211_CMD_REGISTER_BEACONS,
13112 .doit = nl80211_register_beacons,
13113 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013114 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg5e760232011-11-04 11:18:17 +010013115 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13116 NL80211_FLAG_NEED_RTNL,
13117 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010013118 {
13119 .cmd = NL80211_CMD_SET_NOACK_MAP,
13120 .doit = nl80211_set_noack_map,
13121 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013122 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010013123 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13124 NL80211_FLAG_NEED_RTNL,
13125 },
Johannes Berg98104fde2012-06-16 00:19:54 +020013126 {
13127 .cmd = NL80211_CMD_START_P2P_DEVICE,
13128 .doit = nl80211_start_p2p_device,
13129 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013130 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020013131 .internal_flags = NL80211_FLAG_NEED_WDEV |
13132 NL80211_FLAG_NEED_RTNL,
13133 },
13134 {
13135 .cmd = NL80211_CMD_STOP_P2P_DEVICE,
13136 .doit = nl80211_stop_p2p_device,
13137 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013138 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020013139 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13140 NL80211_FLAG_NEED_RTNL,
13141 },
Antonio Quartullif4e583c2012-11-02 13:27:48 +010013142 {
Ayala Bekercb3b7d82016-09-20 17:31:13 +030013143 .cmd = NL80211_CMD_START_NAN,
13144 .doit = nl80211_start_nan,
13145 .policy = nl80211_policy,
13146 .flags = GENL_ADMIN_PERM,
13147 .internal_flags = NL80211_FLAG_NEED_WDEV |
13148 NL80211_FLAG_NEED_RTNL,
13149 },
13150 {
13151 .cmd = NL80211_CMD_STOP_NAN,
13152 .doit = nl80211_stop_nan,
13153 .policy = nl80211_policy,
13154 .flags = GENL_ADMIN_PERM,
13155 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13156 NL80211_FLAG_NEED_RTNL,
13157 },
13158 {
Ayala Bekera442b762016-09-20 17:31:15 +030013159 .cmd = NL80211_CMD_ADD_NAN_FUNCTION,
13160 .doit = nl80211_nan_add_func,
13161 .policy = nl80211_policy,
13162 .flags = GENL_ADMIN_PERM,
13163 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13164 NL80211_FLAG_NEED_RTNL,
13165 },
13166 {
13167 .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
13168 .doit = nl80211_nan_del_func,
13169 .policy = nl80211_policy,
13170 .flags = GENL_ADMIN_PERM,
13171 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13172 NL80211_FLAG_NEED_RTNL,
13173 },
13174 {
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030013175 .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
13176 .doit = nl80211_nan_change_config,
13177 .policy = nl80211_policy,
13178 .flags = GENL_ADMIN_PERM,
13179 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13180 NL80211_FLAG_NEED_RTNL,
13181 },
13182 {
Antonio Quartullif4e583c2012-11-02 13:27:48 +010013183 .cmd = NL80211_CMD_SET_MCAST_RATE,
13184 .doit = nl80211_set_mcast_rate,
13185 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013186 .flags = GENL_UNS_ADMIN_PERM,
Antonio Quartullif4e583c2012-11-02 13:27:48 +010013187 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13188 NL80211_FLAG_NEED_RTNL,
13189 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053013190 {
13191 .cmd = NL80211_CMD_SET_MAC_ACL,
13192 .doit = nl80211_set_mac_acl,
13193 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013194 .flags = GENL_UNS_ADMIN_PERM,
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053013195 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13196 NL80211_FLAG_NEED_RTNL,
13197 },
Simon Wunderlich04f39042013-02-08 18:16:19 +010013198 {
13199 .cmd = NL80211_CMD_RADAR_DETECT,
13200 .doit = nl80211_start_radar_detection,
13201 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013202 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich04f39042013-02-08 18:16:19 +010013203 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13204 NL80211_FLAG_NEED_RTNL,
13205 },
Johannes Berg3713b4e2013-02-14 16:19:38 +010013206 {
13207 .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
13208 .doit = nl80211_get_protocol_features,
13209 .policy = nl80211_policy,
13210 },
Jouni Malinen355199e2013-02-27 17:14:27 +020013211 {
13212 .cmd = NL80211_CMD_UPDATE_FT_IES,
13213 .doit = nl80211_update_ft_ies,
13214 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013215 .flags = GENL_UNS_ADMIN_PERM,
Jouni Malinen355199e2013-02-27 17:14:27 +020013216 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13217 NL80211_FLAG_NEED_RTNL,
13218 },
Arend van Spriel5de17982013-04-18 15:49:00 +020013219 {
13220 .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
13221 .doit = nl80211_crit_protocol_start,
13222 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013223 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020013224 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13225 NL80211_FLAG_NEED_RTNL,
13226 },
13227 {
13228 .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
13229 .doit = nl80211_crit_protocol_stop,
13230 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013231 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020013232 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
13233 NL80211_FLAG_NEED_RTNL,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070013234 },
13235 {
13236 .cmd = NL80211_CMD_GET_COALESCE,
13237 .doit = nl80211_get_coalesce,
13238 .policy = nl80211_policy,
13239 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13240 NL80211_FLAG_NEED_RTNL,
13241 },
13242 {
13243 .cmd = NL80211_CMD_SET_COALESCE,
13244 .doit = nl80211_set_coalesce,
13245 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013246 .flags = GENL_UNS_ADMIN_PERM,
Amitkumar Karwarbe29b99a2013-06-28 11:51:26 -070013247 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13248 NL80211_FLAG_NEED_RTNL,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020013249 },
13250 {
13251 .cmd = NL80211_CMD_CHANNEL_SWITCH,
13252 .doit = nl80211_channel_switch,
13253 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013254 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020013255 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13256 NL80211_FLAG_NEED_RTNL,
13257 },
Johannes Bergad7e7182013-11-13 13:37:47 +010013258 {
13259 .cmd = NL80211_CMD_VENDOR,
13260 .doit = nl80211_vendor_cmd,
Johannes Berg7bdbe402015-08-15 22:39:49 +030013261 .dumpit = nl80211_vendor_cmd_dump,
Johannes Bergad7e7182013-11-13 13:37:47 +010013262 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013263 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergad7e7182013-11-13 13:37:47 +010013264 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13265 NL80211_FLAG_NEED_RTNL,
13266 },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080013267 {
13268 .cmd = NL80211_CMD_SET_QOS_MAP,
13269 .doit = nl80211_set_qos_map,
13270 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013271 .flags = GENL_UNS_ADMIN_PERM,
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080013272 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13273 NL80211_FLAG_NEED_RTNL,
13274 },
Johannes Berg960d01a2014-09-09 22:55:35 +030013275 {
13276 .cmd = NL80211_CMD_ADD_TX_TS,
13277 .doit = nl80211_add_tx_ts,
13278 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013279 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030013280 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13281 NL80211_FLAG_NEED_RTNL,
13282 },
13283 {
13284 .cmd = NL80211_CMD_DEL_TX_TS,
13285 .doit = nl80211_del_tx_ts,
13286 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013287 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030013288 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13289 NL80211_FLAG_NEED_RTNL,
13290 },
Arik Nemtsov1057d352014-11-19 12:54:26 +020013291 {
13292 .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
13293 .doit = nl80211_tdls_channel_switch,
13294 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013295 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020013296 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13297 NL80211_FLAG_NEED_RTNL,
13298 },
13299 {
13300 .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
13301 .doit = nl80211_tdls_cancel_channel_switch,
13302 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013303 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020013304 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13305 NL80211_FLAG_NEED_RTNL,
13306 },
Michael Braunce0ce132016-10-10 19:12:22 +020013307 {
13308 .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
13309 .doit = nl80211_set_multicast_to_unicast,
13310 .policy = nl80211_policy,
13311 .flags = GENL_UNS_ADMIN_PERM,
13312 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13313 NL80211_FLAG_NEED_RTNL,
13314 },
Avraham Stern3a00df52017-06-09 13:08:43 +010013315 {
13316 .cmd = NL80211_CMD_SET_PMK,
13317 .doit = nl80211_set_pmk,
13318 .policy = nl80211_policy,
13319 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13320 NL80211_FLAG_NEED_RTNL,
13321 },
13322 {
13323 .cmd = NL80211_CMD_DEL_PMK,
13324 .doit = nl80211_del_pmk,
13325 .policy = nl80211_policy,
13326 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13327 NL80211_FLAG_NEED_RTNL,
13328 },
13329
Johannes Berg55682962007-09-20 13:09:35 -040013330};
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013331
Johannes Berg56989f62016-10-24 14:40:05 +020013332static struct genl_family nl80211_fam __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +020013333 .name = NL80211_GENL_NAME, /* have users key off the name instead */
13334 .hdrsize = 0, /* no private header */
13335 .version = 1, /* no particular meaning now */
13336 .maxattr = NL80211_ATTR_MAX,
13337 .netnsok = true,
13338 .pre_doit = nl80211_pre_doit,
13339 .post_doit = nl80211_post_doit,
13340 .module = THIS_MODULE,
13341 .ops = nl80211_ops,
13342 .n_ops = ARRAY_SIZE(nl80211_ops),
13343 .mcgrps = nl80211_mcgrps,
13344 .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
13345};
13346
Johannes Berg55682962007-09-20 13:09:35 -040013347/* notification functions */
13348
Johannes Berg3bb20552014-05-26 13:52:25 +020013349void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
13350 enum nl80211_commands cmd)
Johannes Berg55682962007-09-20 13:09:35 -040013351{
13352 struct sk_buff *msg;
Johannes Berg86e8cf92013-06-19 10:57:22 +020013353 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -040013354
Johannes Berg3bb20552014-05-26 13:52:25 +020013355 WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
13356 cmd != NL80211_CMD_DEL_WIPHY);
13357
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013358 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040013359 if (!msg)
13360 return;
13361
Johannes Berg3bb20552014-05-26 13:52:25 +020013362 if (nl80211_send_wiphy(rdev, cmd, msg, 0, 0, 0, &state) < 0) {
Johannes Berg55682962007-09-20 13:09:35 -040013363 nlmsg_free(msg);
13364 return;
13365 }
13366
Johannes Berg68eb5502013-11-19 15:19:38 +010013367 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013368 NL80211_MCGRP_CONFIG, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040013369}
13370
Denis Kenzior896ff062016-08-03 16:58:33 -050013371void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
13372 struct wireless_dev *wdev,
13373 enum nl80211_commands cmd)
13374{
13375 struct sk_buff *msg;
13376
13377 WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
13378 cmd != NL80211_CMD_DEL_INTERFACE);
13379
13380 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13381 if (!msg)
13382 return;
13383
13384 if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
13385 cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
13386 nlmsg_free(msg);
13387 return;
13388 }
13389
13390 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
13391 NL80211_MCGRP_CONFIG, GFP_KERNEL);
13392}
13393
Johannes Berg362a4152009-05-24 16:43:15 +020013394static int nl80211_add_scan_req(struct sk_buff *msg,
13395 struct cfg80211_registered_device *rdev)
13396{
13397 struct cfg80211_scan_request *req = rdev->scan_req;
13398 struct nlattr *nest;
13399 int i;
13400
13401 if (WARN_ON(!req))
13402 return 0;
13403
13404 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
13405 if (!nest)
13406 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040013407 for (i = 0; i < req->n_ssids; i++) {
13408 if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
13409 goto nla_put_failure;
13410 }
Johannes Berg362a4152009-05-24 16:43:15 +020013411 nla_nest_end(msg, nest);
13412
13413 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
13414 if (!nest)
13415 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040013416 for (i = 0; i < req->n_channels; i++) {
13417 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
13418 goto nla_put_failure;
13419 }
Johannes Berg362a4152009-05-24 16:43:15 +020013420 nla_nest_end(msg, nest);
13421
David S. Miller9360ffd2012-03-29 04:41:26 -040013422 if (req->ie &&
13423 nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
13424 goto nla_put_failure;
Johannes Berg362a4152009-05-24 16:43:15 +020013425
Johannes Bergae917c92013-10-25 11:05:22 +020013426 if (req->flags &&
13427 nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
13428 goto nla_put_failure;
Sam Lefflered4737712012-10-11 21:03:31 -070013429
Avraham Stern1d762502016-07-05 17:10:13 +030013430 if (req->info.scan_start_tsf &&
13431 (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
13432 req->info.scan_start_tsf, NL80211_BSS_PAD) ||
13433 nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
13434 req->info.tsf_bssid)))
13435 goto nla_put_failure;
13436
Johannes Berg362a4152009-05-24 16:43:15 +020013437 return 0;
13438 nla_put_failure:
13439 return -ENOBUFS;
13440}
13441
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013442static int nl80211_prep_scan_msg(struct sk_buff *msg,
Johannes Berga538e2d2009-06-16 19:56:42 +020013443 struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020013444 struct wireless_dev *wdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000013445 u32 portid, u32 seq, int flags,
Johannes Berga538e2d2009-06-16 19:56:42 +020013446 u32 cmd)
Johannes Berg2a519312009-02-10 21:25:55 +010013447{
13448 void *hdr;
13449
Eric W. Biederman15e47302012-09-07 20:12:54 +000013450 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg2a519312009-02-10 21:25:55 +010013451 if (!hdr)
13452 return -1;
13453
David S. Miller9360ffd2012-03-29 04:41:26 -040013454 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Bergfd014282012-06-18 19:17:03 +020013455 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13456 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013457 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13458 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013459 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +010013460
Johannes Berg362a4152009-05-24 16:43:15 +020013461 /* ignore errors and send incomplete event anyway */
13462 nl80211_add_scan_req(msg, rdev);
Johannes Berg2a519312009-02-10 21:25:55 +010013463
Johannes Berg053c0952015-01-16 22:09:00 +010013464 genlmsg_end(msg, hdr);
13465 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +010013466
13467 nla_put_failure:
13468 genlmsg_cancel(msg, hdr);
13469 return -EMSGSIZE;
13470}
13471
Luciano Coelho807f8a82011-05-11 17:09:35 +030013472static int
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013473nl80211_prep_sched_scan_msg(struct sk_buff *msg,
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013474 struct cfg80211_sched_scan_request *req, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030013475{
13476 void *hdr;
13477
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013478 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013479 if (!hdr)
13480 return -1;
13481
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013482 if (nla_put_u32(msg, NL80211_ATTR_WIPHY,
13483 wiphy_to_rdev(req->wiphy)->wiphy_idx) ||
13484 nla_put_u32(msg, NL80211_ATTR_IFINDEX, req->dev->ifindex) ||
13485 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->reqid,
13486 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013487 goto nla_put_failure;
Luciano Coelho807f8a82011-05-11 17:09:35 +030013488
Johannes Berg053c0952015-01-16 22:09:00 +010013489 genlmsg_end(msg, hdr);
13490 return 0;
Luciano Coelho807f8a82011-05-11 17:09:35 +030013491
13492 nla_put_failure:
13493 genlmsg_cancel(msg, hdr);
13494 return -EMSGSIZE;
13495}
13496
Johannes Berga538e2d2009-06-16 19:56:42 +020013497void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020013498 struct wireless_dev *wdev)
Johannes Berga538e2d2009-06-16 19:56:42 +020013499{
13500 struct sk_buff *msg;
13501
Thomas Graf58050fc2012-06-28 03:57:45 +000013502 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013503 if (!msg)
13504 return;
13505
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013506 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Berga538e2d2009-06-16 19:56:42 +020013507 NL80211_CMD_TRIGGER_SCAN) < 0) {
13508 nlmsg_free(msg);
13509 return;
13510 }
13511
Johannes Berg68eb5502013-11-19 15:19:38 +010013512 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013513 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013514}
13515
Johannes Bergf9d15d12014-01-22 11:14:19 +020013516struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
13517 struct wireless_dev *wdev, bool aborted)
Johannes Berg2a519312009-02-10 21:25:55 +010013518{
13519 struct sk_buff *msg;
13520
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013521 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013522 if (!msg)
Johannes Bergf9d15d12014-01-22 11:14:19 +020013523 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013524
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013525 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Bergf9d15d12014-01-22 11:14:19 +020013526 aborted ? NL80211_CMD_SCAN_ABORTED :
13527 NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +010013528 nlmsg_free(msg);
Johannes Bergf9d15d12014-01-22 11:14:19 +020013529 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013530 }
13531
Johannes Bergf9d15d12014-01-22 11:14:19 +020013532 return msg;
Johannes Berg2a519312009-02-10 21:25:55 +010013533}
13534
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013535/* send message created by nl80211_build_scan_msg() */
13536void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
13537 struct sk_buff *msg)
Johannes Berg2a519312009-02-10 21:25:55 +010013538{
Johannes Berg2a519312009-02-10 21:25:55 +010013539 if (!msg)
13540 return;
13541
Johannes Berg68eb5502013-11-19 15:19:38 +010013542 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013543 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013544}
13545
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013546void nl80211_send_sched_scan(struct cfg80211_sched_scan_request *req, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030013547{
13548 struct sk_buff *msg;
13549
Thomas Graf58050fc2012-06-28 03:57:45 +000013550 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013551 if (!msg)
13552 return;
13553
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013554 if (nl80211_prep_sched_scan_msg(msg, req, cmd) < 0) {
Luciano Coelho807f8a82011-05-11 17:09:35 +030013555 nlmsg_free(msg);
13556 return;
13557 }
13558
Arend Van Spriel96b08fd2017-04-13 13:06:27 +010013559 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(req->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013560 NL80211_MCGRP_SCAN, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013561}
13562
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013563static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
13564 struct regulatory_request *request)
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013565{
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013566 /* Userspace can always count this one always being set */
David S. Miller9360ffd2012-03-29 04:41:26 -040013567 if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
13568 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013569
David S. Miller9360ffd2012-03-29 04:41:26 -040013570 if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
13571 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13572 NL80211_REGDOM_TYPE_WORLD))
13573 goto nla_put_failure;
13574 } else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
13575 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13576 NL80211_REGDOM_TYPE_CUSTOM_WORLD))
13577 goto nla_put_failure;
13578 } else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
13579 request->intersect) {
13580 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13581 NL80211_REGDOM_TYPE_INTERSECTION))
13582 goto nla_put_failure;
13583 } else {
13584 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13585 NL80211_REGDOM_TYPE_COUNTRY) ||
13586 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
13587 request->alpha2))
13588 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013589 }
13590
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013591 if (request->wiphy_idx != WIPHY_IDX_INVALID) {
13592 struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
13593
13594 if (wiphy &&
13595 nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
13596 goto nla_put_failure;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +020013597
13598 if (wiphy &&
13599 wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
13600 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
13601 goto nla_put_failure;
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013602 }
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013603
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013604 return true;
13605
13606nla_put_failure:
13607 return false;
13608}
13609
13610/*
13611 * This can happen on global regulatory changes or device specific settings
13612 * based on custom regulatory domains.
13613 */
13614void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
13615 struct regulatory_request *request)
13616{
13617 struct sk_buff *msg;
13618 void *hdr;
13619
13620 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13621 if (!msg)
13622 return;
13623
13624 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
13625 if (!hdr) {
13626 nlmsg_free(msg);
13627 return;
13628 }
13629
13630 if (nl80211_reg_change_event_fill(msg, request) == false)
13631 goto nla_put_failure;
13632
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013633 genlmsg_end(msg, hdr);
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013634
Johannes Bergbc43b282009-07-25 10:54:13 +020013635 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010013636 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013637 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Bergbc43b282009-07-25 10:54:13 +020013638 rcu_read_unlock();
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013639
13640 return;
13641
13642nla_put_failure:
13643 genlmsg_cancel(msg, hdr);
13644 nlmsg_free(msg);
13645}
13646
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013647static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
13648 struct net_device *netdev,
13649 const u8 *buf, size_t len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013650 enum nl80211_commands cmd, gfp_t gfp,
13651 int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013652{
13653 struct sk_buff *msg;
13654 void *hdr;
13655
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013656 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013657 if (!msg)
13658 return;
13659
13660 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13661 if (!hdr) {
13662 nlmsg_free(msg);
13663 return;
13664 }
13665
David S. Miller9360ffd2012-03-29 04:41:26 -040013666 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13667 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13668 nla_put(msg, NL80211_ATTR_FRAME, len, buf))
13669 goto nla_put_failure;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013670
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013671 if (uapsd_queues >= 0) {
13672 struct nlattr *nla_wmm =
13673 nla_nest_start(msg, NL80211_ATTR_STA_WME);
13674 if (!nla_wmm)
13675 goto nla_put_failure;
13676
13677 if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
13678 uapsd_queues))
13679 goto nla_put_failure;
13680
13681 nla_nest_end(msg, nla_wmm);
13682 }
13683
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013684 genlmsg_end(msg, hdr);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013685
Johannes Berg68eb5502013-11-19 15:19:38 +010013686 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013687 NL80211_MCGRP_MLME, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013688 return;
13689
13690 nla_put_failure:
13691 genlmsg_cancel(msg, hdr);
13692 nlmsg_free(msg);
13693}
13694
13695void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013696 struct net_device *netdev, const u8 *buf,
13697 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013698{
13699 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013700 NL80211_CMD_AUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013701}
13702
13703void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
13704 struct net_device *netdev, const u8 *buf,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013705 size_t len, gfp_t gfp, int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013706{
Johannes Berge6d6e342009-07-01 21:26:47 +020013707 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013708 NL80211_CMD_ASSOCIATE, gfp, uapsd_queues);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013709}
13710
Jouni Malinen53b46b82009-03-27 20:53:56 +020013711void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013712 struct net_device *netdev, const u8 *buf,
13713 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013714{
13715 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013716 NL80211_CMD_DEAUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013717}
13718
Jouni Malinen53b46b82009-03-27 20:53:56 +020013719void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
13720 struct net_device *netdev, const u8 *buf,
Johannes Berge6d6e342009-07-01 21:26:47 +020013721 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013722{
13723 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013724 NL80211_CMD_DISASSOCIATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013725}
13726
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013727void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
13728 size_t len)
Jouni Malinencf4e5942010-12-16 00:52:40 +020013729{
Johannes Berg947add32013-02-22 22:05:20 +010013730 struct wireless_dev *wdev = dev->ieee80211_ptr;
13731 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013732 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013733 const struct ieee80211_mgmt *mgmt = (void *)buf;
13734 u32 cmd;
Jouni Malinencf4e5942010-12-16 00:52:40 +020013735
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013736 if (WARN_ON(len < 2))
13737 return;
13738
13739 if (ieee80211_is_deauth(mgmt->frame_control))
13740 cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
13741 else
13742 cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
13743
13744 trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013745 nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1);
Jouni Malinencf4e5942010-12-16 00:52:40 +020013746}
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013747EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
Jouni Malinencf4e5942010-12-16 00:52:40 +020013748
Luis R. Rodriguez1b06bb42009-05-02 00:34:48 -040013749static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
13750 struct net_device *netdev, int cmd,
Johannes Berge6d6e342009-07-01 21:26:47 +020013751 const u8 *addr, gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013752{
13753 struct sk_buff *msg;
13754 void *hdr;
13755
Johannes Berge6d6e342009-07-01 21:26:47 +020013756 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013757 if (!msg)
13758 return;
13759
13760 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13761 if (!hdr) {
13762 nlmsg_free(msg);
13763 return;
13764 }
13765
David S. Miller9360ffd2012-03-29 04:41:26 -040013766 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13767 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13768 nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
13769 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
13770 goto nla_put_failure;
Jouni Malinen1965c852009-04-22 21:38:25 +030013771
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013772 genlmsg_end(msg, hdr);
Jouni Malinen1965c852009-04-22 21:38:25 +030013773
Johannes Berg68eb5502013-11-19 15:19:38 +010013774 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013775 NL80211_MCGRP_MLME, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013776 return;
13777
13778 nla_put_failure:
13779 genlmsg_cancel(msg, hdr);
13780 nlmsg_free(msg);
13781}
13782
13783void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013784 struct net_device *netdev, const u8 *addr,
13785 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013786{
13787 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
Johannes Berge6d6e342009-07-01 21:26:47 +020013788 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013789}
13790
13791void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013792 struct net_device *netdev, const u8 *addr,
13793 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013794{
Johannes Berge6d6e342009-07-01 21:26:47 +020013795 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
13796 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013797}
13798
Samuel Ortizb23aa672009-07-01 21:26:54 +020013799void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030013800 struct net_device *netdev,
13801 struct cfg80211_connect_resp_params *cr,
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020013802 gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013803{
13804 struct sk_buff *msg;
13805 void *hdr;
13806
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030013807 msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
13808 cr->fils_kek_len + cr->pmk_len +
13809 (cr->pmkid ? WLAN_PMKID_LEN : 0), gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013810 if (!msg)
13811 return;
13812
13813 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
13814 if (!hdr) {
13815 nlmsg_free(msg);
13816 return;
13817 }
13818
David S. Miller9360ffd2012-03-29 04:41:26 -040013819 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13820 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030013821 (cr->bssid &&
13822 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
Jouni Malinenbf1ecd22016-05-31 00:16:50 +030013823 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030013824 cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
13825 cr->status) ||
13826 (cr->status < 0 &&
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020013827 (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030013828 nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
13829 cr->timeout_reason))) ||
13830 (cr->req_ie &&
13831 nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
13832 (cr->resp_ie &&
13833 nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030013834 cr->resp_ie)) ||
13835 (cr->update_erp_next_seq_num &&
13836 nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
13837 cr->fils_erp_next_seq_num)) ||
13838 (cr->status == WLAN_STATUS_SUCCESS &&
13839 ((cr->fils_kek &&
13840 nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils_kek_len,
13841 cr->fils_kek)) ||
13842 (cr->pmk &&
13843 nla_put(msg, NL80211_ATTR_PMK, cr->pmk_len, cr->pmk)) ||
13844 (cr->pmkid &&
13845 nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->pmkid)))))
David S. Miller9360ffd2012-03-29 04:41:26 -040013846 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013847
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013848 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013849
Johannes Berg68eb5502013-11-19 15:19:38 +010013850 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013851 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013852 return;
13853
13854 nla_put_failure:
13855 genlmsg_cancel(msg, hdr);
13856 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013857}
13858
13859void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
Avraham Stern29ce6ec2017-04-26 10:58:49 +030013860 struct net_device *netdev,
13861 struct cfg80211_roam_info *info, gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013862{
13863 struct sk_buff *msg;
13864 void *hdr;
Avraham Stern29ce6ec2017-04-26 10:58:49 +030013865 const u8 *bssid = info->bss ? info->bss->bssid : info->bssid;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013866
Avraham Stern29ce6ec2017-04-26 10:58:49 +030013867 msg = nlmsg_new(100 + info->req_ie_len + info->resp_ie_len, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013868 if (!msg)
13869 return;
13870
13871 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
13872 if (!hdr) {
13873 nlmsg_free(msg);
13874 return;
13875 }
13876
David S. Miller9360ffd2012-03-29 04:41:26 -040013877 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13878 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13879 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
Avraham Stern29ce6ec2017-04-26 10:58:49 +030013880 (info->req_ie &&
13881 nla_put(msg, NL80211_ATTR_REQ_IE, info->req_ie_len,
13882 info->req_ie)) ||
13883 (info->resp_ie &&
13884 nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
Avraham Stern503c1fb2017-09-29 14:21:49 +020013885 info->resp_ie)))
David S. Miller9360ffd2012-03-29 04:41:26 -040013886 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013887
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013888 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013889
Johannes Berg68eb5502013-11-19 15:19:38 +010013890 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013891 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013892 return;
13893
13894 nla_put_failure:
13895 genlmsg_cancel(msg, hdr);
13896 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013897}
13898
Avraham Stern503c1fb2017-09-29 14:21:49 +020013899void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
13900 struct net_device *netdev, const u8 *bssid)
13901{
13902 struct sk_buff *msg;
13903 void *hdr;
13904
13905 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13906 if (!msg)
13907 return;
13908
13909 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PORT_AUTHORIZED);
13910 if (!hdr) {
13911 nlmsg_free(msg);
13912 return;
13913 }
13914
13915 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
13916 goto nla_put_failure;
13917
13918 genlmsg_end(msg, hdr);
13919
13920 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
13921 NL80211_MCGRP_MLME, GFP_KERNEL);
13922 return;
13923
13924 nla_put_failure:
13925 genlmsg_cancel(msg, hdr);
13926 nlmsg_free(msg);
13927}
13928
Samuel Ortizb23aa672009-07-01 21:26:54 +020013929void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
13930 struct net_device *netdev, u16 reason,
Johannes Berg667503d2009-07-07 03:56:11 +020013931 const u8 *ie, size_t ie_len, bool from_ap)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013932{
13933 struct sk_buff *msg;
13934 void *hdr;
13935
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013936 msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013937 if (!msg)
13938 return;
13939
13940 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
13941 if (!hdr) {
13942 nlmsg_free(msg);
13943 return;
13944 }
13945
David S. Miller9360ffd2012-03-29 04:41:26 -040013946 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13947 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13948 (from_ap && reason &&
13949 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
13950 (from_ap &&
13951 nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
13952 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
13953 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013954
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013955 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013956
Johannes Berg68eb5502013-11-19 15:19:38 +010013957 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013958 NL80211_MCGRP_MLME, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013959 return;
13960
13961 nla_put_failure:
13962 genlmsg_cancel(msg, hdr);
13963 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013964}
13965
Johannes Berg04a773a2009-04-19 21:24:32 +020013966void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
13967 struct net_device *netdev, const u8 *bssid,
13968 gfp_t gfp)
13969{
13970 struct sk_buff *msg;
13971 void *hdr;
13972
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013973 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020013974 if (!msg)
13975 return;
13976
13977 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
13978 if (!hdr) {
13979 nlmsg_free(msg);
13980 return;
13981 }
13982
David S. Miller9360ffd2012-03-29 04:41:26 -040013983 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13984 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13985 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
13986 goto nla_put_failure;
Johannes Berg04a773a2009-04-19 21:24:32 +020013987
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013988 genlmsg_end(msg, hdr);
Johannes Berg04a773a2009-04-19 21:24:32 +020013989
Johannes Berg68eb5502013-11-19 15:19:38 +010013990 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013991 NL80211_MCGRP_MLME, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020013992 return;
13993
13994 nla_put_failure:
13995 genlmsg_cancel(msg, hdr);
13996 nlmsg_free(msg);
13997}
13998
Johannes Berg947add32013-02-22 22:05:20 +010013999void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
14000 const u8* ie, u8 ie_len, gfp_t gfp)
Javier Cardonac93b5e72011-04-07 15:08:34 -070014001{
Johannes Berg947add32013-02-22 22:05:20 +010014002 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014003 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Javier Cardonac93b5e72011-04-07 15:08:34 -070014004 struct sk_buff *msg;
14005 void *hdr;
14006
Johannes Berg947add32013-02-22 22:05:20 +010014007 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
14008 return;
14009
14010 trace_cfg80211_notify_new_peer_candidate(dev, addr);
14011
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014012 msg = nlmsg_new(100 + ie_len, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070014013 if (!msg)
14014 return;
14015
14016 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
14017 if (!hdr) {
14018 nlmsg_free(msg);
14019 return;
14020 }
14021
David S. Miller9360ffd2012-03-29 04:41:26 -040014022 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010014023 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14024 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014025 (ie_len && ie &&
14026 nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
14027 goto nla_put_failure;
Javier Cardonac93b5e72011-04-07 15:08:34 -070014028
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014029 genlmsg_end(msg, hdr);
Javier Cardonac93b5e72011-04-07 15:08:34 -070014030
Johannes Berg68eb5502013-11-19 15:19:38 +010014031 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014032 NL80211_MCGRP_MLME, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070014033 return;
14034
14035 nla_put_failure:
14036 genlmsg_cancel(msg, hdr);
14037 nlmsg_free(msg);
14038}
Johannes Berg947add32013-02-22 22:05:20 +010014039EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
Javier Cardonac93b5e72011-04-07 15:08:34 -070014040
Jouni Malinena3b8b052009-03-27 21:59:49 +020014041void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
14042 struct net_device *netdev, const u8 *addr,
14043 enum nl80211_key_type key_type, int key_id,
Johannes Berge6d6e342009-07-01 21:26:47 +020014044 const u8 *tsc, gfp_t gfp)
Jouni Malinena3b8b052009-03-27 21:59:49 +020014045{
14046 struct sk_buff *msg;
14047 void *hdr;
14048
Johannes Berge6d6e342009-07-01 21:26:47 +020014049 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020014050 if (!msg)
14051 return;
14052
14053 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
14054 if (!hdr) {
14055 nlmsg_free(msg);
14056 return;
14057 }
14058
David S. Miller9360ffd2012-03-29 04:41:26 -040014059 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14060 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14061 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
14062 nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
14063 (key_id != -1 &&
14064 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
14065 (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
14066 goto nla_put_failure;
Jouni Malinena3b8b052009-03-27 21:59:49 +020014067
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014068 genlmsg_end(msg, hdr);
Jouni Malinena3b8b052009-03-27 21:59:49 +020014069
Johannes Berg68eb5502013-11-19 15:19:38 +010014070 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014071 NL80211_MCGRP_MLME, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020014072 return;
14073
14074 nla_put_failure:
14075 genlmsg_cancel(msg, hdr);
14076 nlmsg_free(msg);
14077}
14078
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014079void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
14080 struct ieee80211_channel *channel_before,
14081 struct ieee80211_channel *channel_after)
14082{
14083 struct sk_buff *msg;
14084 void *hdr;
14085 struct nlattr *nl_freq;
14086
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070014087 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014088 if (!msg)
14089 return;
14090
14091 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
14092 if (!hdr) {
14093 nlmsg_free(msg);
14094 return;
14095 }
14096
14097 /*
14098 * Since we are applying the beacon hint to a wiphy we know its
14099 * wiphy_idx is valid
14100 */
David S. Miller9360ffd2012-03-29 04:41:26 -040014101 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
14102 goto nla_put_failure;
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014103
14104 /* Before */
14105 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
14106 if (!nl_freq)
14107 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +010014108 if (nl80211_msg_put_channel(msg, channel_before, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014109 goto nla_put_failure;
14110 nla_nest_end(msg, nl_freq);
14111
14112 /* After */
14113 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
14114 if (!nl_freq)
14115 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +010014116 if (nl80211_msg_put_channel(msg, channel_after, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014117 goto nla_put_failure;
14118 nla_nest_end(msg, nl_freq);
14119
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014120 genlmsg_end(msg, hdr);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014121
Johannes Berg463d0182009-07-14 00:33:35 +020014122 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010014123 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014124 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Berg463d0182009-07-14 00:33:35 +020014125 rcu_read_unlock();
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040014126
14127 return;
14128
14129nla_put_failure:
14130 genlmsg_cancel(msg, hdr);
14131 nlmsg_free(msg);
14132}
14133
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014134static void nl80211_send_remain_on_chan_event(
14135 int cmd, struct cfg80211_registered_device *rdev,
Johannes Berg71bbc992012-06-15 15:30:18 +020014136 struct wireless_dev *wdev, u64 cookie,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014137 struct ieee80211_channel *chan,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014138 unsigned int duration, gfp_t gfp)
14139{
14140 struct sk_buff *msg;
14141 void *hdr;
14142
14143 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14144 if (!msg)
14145 return;
14146
14147 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
14148 if (!hdr) {
14149 nlmsg_free(msg);
14150 return;
14151 }
14152
David S. Miller9360ffd2012-03-29 04:41:26 -040014153 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020014154 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14155 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014156 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14157 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014158 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
Johannes Berg42d97a52012-11-08 18:31:02 +010014159 nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
14160 NL80211_CHAN_NO_HT) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014161 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14162 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040014163 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014164
David S. Miller9360ffd2012-03-29 04:41:26 -040014165 if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
14166 nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
14167 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014168
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014169 genlmsg_end(msg, hdr);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014170
Johannes Berg68eb5502013-11-19 15:19:38 +010014171 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014172 NL80211_MCGRP_MLME, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014173 return;
14174
14175 nla_put_failure:
14176 genlmsg_cancel(msg, hdr);
14177 nlmsg_free(msg);
14178}
14179
Johannes Berg947add32013-02-22 22:05:20 +010014180void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
14181 struct ieee80211_channel *chan,
14182 unsigned int duration, gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014183{
Johannes Berg947add32013-02-22 22:05:20 +010014184 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014185 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014186
14187 trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014188 nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
Johannes Berg71bbc992012-06-15 15:30:18 +020014189 rdev, wdev, cookie, chan,
Johannes Berg42d97a52012-11-08 18:31:02 +010014190 duration, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014191}
Johannes Berg947add32013-02-22 22:05:20 +010014192EXPORT_SYMBOL(cfg80211_ready_on_channel);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014193
Johannes Berg947add32013-02-22 22:05:20 +010014194void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
14195 struct ieee80211_channel *chan,
14196 gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014197{
Johannes Berg947add32013-02-22 22:05:20 +010014198 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014199 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014200
14201 trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014202 nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
Johannes Berg42d97a52012-11-08 18:31:02 +010014203 rdev, wdev, cookie, chan, 0, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014204}
Johannes Berg947add32013-02-22 22:05:20 +010014205EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010014206
Johannes Berg947add32013-02-22 22:05:20 +010014207void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
14208 struct station_info *sinfo, gfp_t gfp)
Johannes Berg98b62182009-12-23 13:15:44 +010014209{
Johannes Berg947add32013-02-22 22:05:20 +010014210 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014211 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg98b62182009-12-23 13:15:44 +010014212 struct sk_buff *msg;
14213
Johannes Berg947add32013-02-22 22:05:20 +010014214 trace_cfg80211_new_sta(dev, mac_addr, sinfo);
14215
Thomas Graf58050fc2012-06-28 03:57:45 +000014216 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010014217 if (!msg)
14218 return;
14219
Johannes Bergcf5ead82014-11-14 17:14:00 +010014220 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
John W. Linville66266b32012-03-15 13:25:41 -040014221 rdev, dev, mac_addr, sinfo) < 0) {
Johannes Berg98b62182009-12-23 13:15:44 +010014222 nlmsg_free(msg);
14223 return;
14224 }
14225
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);
Johannes Berg98b62182009-12-23 13:15:44 +010014228}
Johannes Berg947add32013-02-22 22:05:20 +010014229EXPORT_SYMBOL(cfg80211_new_sta);
Johannes Berg98b62182009-12-23 13:15:44 +010014230
Johannes Bergcf5ead82014-11-14 17:14:00 +010014231void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
14232 struct station_info *sinfo, gfp_t gfp)
Jouni Malinenec15e682011-03-23 15:29:52 +020014233{
Johannes Berg947add32013-02-22 22:05:20 +010014234 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014235 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinenec15e682011-03-23 15:29:52 +020014236 struct sk_buff *msg;
Johannes Bergcf5ead82014-11-14 17:14:00 +010014237 struct station_info empty_sinfo = {};
14238
14239 if (!sinfo)
14240 sinfo = &empty_sinfo;
Jouni Malinenec15e682011-03-23 15:29:52 +020014241
Johannes Berg947add32013-02-22 22:05:20 +010014242 trace_cfg80211_del_sta(dev, mac_addr);
14243
Thomas Graf58050fc2012-06-28 03:57:45 +000014244 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020014245 if (!msg)
14246 return;
14247
Johannes Bergcf5ead82014-11-14 17:14:00 +010014248 if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
Johannes Berg57007122015-01-16 21:05:02 +010014249 rdev, dev, mac_addr, sinfo) < 0) {
Jouni Malinenec15e682011-03-23 15:29:52 +020014250 nlmsg_free(msg);
14251 return;
14252 }
14253
Johannes Berg68eb5502013-11-19 15:19:38 +010014254 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014255 NL80211_MCGRP_MLME, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020014256}
Johannes Bergcf5ead82014-11-14 17:14:00 +010014257EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
Jouni Malinenec15e682011-03-23 15:29:52 +020014258
Johannes Berg947add32013-02-22 22:05:20 +010014259void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
14260 enum nl80211_connect_failed_reason reason,
14261 gfp_t gfp)
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053014262{
Johannes Berg947add32013-02-22 22:05:20 +010014263 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014264 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053014265 struct sk_buff *msg;
14266 void *hdr;
14267
14268 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
14269 if (!msg)
14270 return;
14271
14272 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED);
14273 if (!hdr) {
14274 nlmsg_free(msg);
14275 return;
14276 }
14277
14278 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14279 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
14280 nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason))
14281 goto nla_put_failure;
14282
14283 genlmsg_end(msg, hdr);
14284
Johannes Berg68eb5502013-11-19 15:19:38 +010014285 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014286 NL80211_MCGRP_MLME, gfp);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053014287 return;
14288
14289 nla_put_failure:
14290 genlmsg_cancel(msg, hdr);
14291 nlmsg_free(msg);
14292}
Johannes Berg947add32013-02-22 22:05:20 +010014293EXPORT_SYMBOL(cfg80211_conn_failed);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053014294
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014295static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
14296 const u8 *addr, gfp_t gfp)
Johannes Berg28946da2011-11-04 11:18:12 +010014297{
14298 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014299 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg28946da2011-11-04 11:18:12 +010014300 struct sk_buff *msg;
14301 void *hdr;
Mark Rutland6aa7de02017-10-23 14:07:29 -070014302 u32 nlportid = READ_ONCE(wdev->ap_unexpected_nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010014303
Eric W. Biederman15e47302012-09-07 20:12:54 +000014304 if (!nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010014305 return false;
14306
14307 msg = nlmsg_new(100, gfp);
14308 if (!msg)
14309 return true;
14310
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014311 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Johannes Berg28946da2011-11-04 11:18:12 +010014312 if (!hdr) {
14313 nlmsg_free(msg);
14314 return true;
14315 }
14316
David S. Miller9360ffd2012-03-29 04:41:26 -040014317 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14318 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14319 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
14320 goto nla_put_failure;
Johannes Berg28946da2011-11-04 11:18:12 +010014321
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014322 genlmsg_end(msg, hdr);
Eric W. Biederman15e47302012-09-07 20:12:54 +000014323 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010014324 return true;
14325
14326 nla_put_failure:
14327 genlmsg_cancel(msg, hdr);
14328 nlmsg_free(msg);
14329 return true;
14330}
14331
Johannes Berg947add32013-02-22 22:05:20 +010014332bool cfg80211_rx_spurious_frame(struct net_device *dev,
14333 const u8 *addr, gfp_t gfp)
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014334{
Johannes Berg947add32013-02-22 22:05:20 +010014335 struct wireless_dev *wdev = dev->ieee80211_ptr;
14336 bool ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014337
Johannes Berg947add32013-02-22 22:05:20 +010014338 trace_cfg80211_rx_spurious_frame(dev, addr);
14339
14340 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
14341 wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
14342 trace_cfg80211_return_bool(false);
14343 return false;
14344 }
14345 ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
14346 addr, gfp);
14347 trace_cfg80211_return_bool(ret);
14348 return ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014349}
Johannes Berg947add32013-02-22 22:05:20 +010014350EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
14351
14352bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
14353 const u8 *addr, gfp_t gfp)
14354{
14355 struct wireless_dev *wdev = dev->ieee80211_ptr;
14356 bool ret;
14357
14358 trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
14359
14360 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
14361 wdev->iftype != NL80211_IFTYPE_P2P_GO &&
14362 wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
14363 trace_cfg80211_return_bool(false);
14364 return false;
14365 }
14366 ret = __nl80211_unexpected_frame(dev,
14367 NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
14368 addr, gfp);
14369 trace_cfg80211_return_bool(ret);
14370 return ret;
14371}
14372EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014373
Johannes Berg2e161f72010-08-12 15:38:38 +020014374int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000014375 struct wireless_dev *wdev, u32 nlportid,
Johannes Berg804483e2012-03-05 22:18:41 +010014376 int freq, int sig_dbm,
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030014377 const u8 *buf, size_t len, u32 flags, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020014378{
Johannes Berg71bbc992012-06-15 15:30:18 +020014379 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020014380 struct sk_buff *msg;
14381 void *hdr;
Jouni Malinen026331c2010-02-15 12:53:10 +020014382
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014383 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014384 if (!msg)
14385 return -ENOMEM;
14386
Johannes Berg2e161f72010-08-12 15:38:38 +020014387 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
Jouni Malinen026331c2010-02-15 12:53:10 +020014388 if (!hdr) {
14389 nlmsg_free(msg);
14390 return -ENOMEM;
14391 }
14392
David S. Miller9360ffd2012-03-29 04:41:26 -040014393 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020014394 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14395 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014396 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14397 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014398 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
14399 (sig_dbm &&
14400 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030014401 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
14402 (flags &&
14403 nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
David S. Miller9360ffd2012-03-29 04:41:26 -040014404 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020014405
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014406 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020014407
Eric W. Biederman15e47302012-09-07 20:12:54 +000014408 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Jouni Malinen026331c2010-02-15 12:53:10 +020014409
14410 nla_put_failure:
14411 genlmsg_cancel(msg, hdr);
14412 nlmsg_free(msg);
14413 return -ENOBUFS;
14414}
14415
Johannes Berg947add32013-02-22 22:05:20 +010014416void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
14417 const u8 *buf, size_t len, bool ack, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020014418{
Johannes Berg947add32013-02-22 22:05:20 +010014419 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014420 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg71bbc992012-06-15 15:30:18 +020014421 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020014422 struct sk_buff *msg;
14423 void *hdr;
14424
Johannes Berg947add32013-02-22 22:05:20 +010014425 trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
14426
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014427 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014428 if (!msg)
14429 return;
14430
Johannes Berg2e161f72010-08-12 15:38:38 +020014431 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
Jouni Malinen026331c2010-02-15 12:53:10 +020014432 if (!hdr) {
14433 nlmsg_free(msg);
14434 return;
14435 }
14436
David S. Miller9360ffd2012-03-29 04:41:26 -040014437 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020014438 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14439 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014440 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14441 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014442 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014443 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14444 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014445 (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
14446 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020014447
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014448 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020014449
Johannes Berg68eb5502013-11-19 15:19:38 +010014450 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014451 NL80211_MCGRP_MLME, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014452 return;
14453
14454 nla_put_failure:
14455 genlmsg_cancel(msg, hdr);
14456 nlmsg_free(msg);
14457}
Johannes Berg947add32013-02-22 22:05:20 +010014458EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
Jouni Malinen026331c2010-02-15 12:53:10 +020014459
Johannes Berg5b97f492014-11-26 12:37:43 +010014460static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
14461 const char *mac, gfp_t gfp)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014462{
Johannes Berg947add32013-02-22 22:05:20 +010014463 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg5b97f492014-11-26 12:37:43 +010014464 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
14465 struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14466 void **cb;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014467
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014468 if (!msg)
Johannes Berg5b97f492014-11-26 12:37:43 +010014469 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014470
Johannes Berg5b97f492014-11-26 12:37:43 +010014471 cb = (void **)msg->cb;
14472
14473 cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
14474 if (!cb[0]) {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014475 nlmsg_free(msg);
Johannes Berg5b97f492014-11-26 12:37:43 +010014476 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014477 }
14478
David S. Miller9360ffd2012-03-29 04:41:26 -040014479 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010014480 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
David S. Miller9360ffd2012-03-29 04:41:26 -040014481 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014482
Johannes Berg5b97f492014-11-26 12:37:43 +010014483 if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014484 goto nla_put_failure;
14485
Johannes Berg5b97f492014-11-26 12:37:43 +010014486 cb[1] = nla_nest_start(msg, NL80211_ATTR_CQM);
14487 if (!cb[1])
14488 goto nla_put_failure;
14489
14490 cb[2] = rdev;
14491
14492 return msg;
14493 nla_put_failure:
14494 nlmsg_free(msg);
14495 return NULL;
14496}
14497
14498static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
14499{
14500 void **cb = (void **)msg->cb;
14501 struct cfg80211_registered_device *rdev = cb[2];
14502
14503 nla_nest_end(msg, cb[1]);
14504 genlmsg_end(msg, cb[0]);
14505
14506 memset(msg->cb, 0, sizeof(msg->cb));
14507
14508 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
14509 NL80211_MCGRP_MLME, gfp);
14510}
14511
14512void cfg80211_cqm_rssi_notify(struct net_device *dev,
14513 enum nl80211_cqm_rssi_threshold_event rssi_event,
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010014514 s32 rssi_level, gfp_t gfp)
Johannes Berg5b97f492014-11-26 12:37:43 +010014515{
14516 struct sk_buff *msg;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010014517 struct wireless_dev *wdev = dev->ieee80211_ptr;
14518 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg5b97f492014-11-26 12:37:43 +010014519
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010014520 trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
Johannes Berg5b97f492014-11-26 12:37:43 +010014521
Johannes Berg98f03342014-11-26 12:42:02 +010014522 if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
14523 rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
14524 return;
14525
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010014526 if (wdev->cqm_config) {
14527 wdev->cqm_config->last_rssi_event_value = rssi_level;
14528
14529 cfg80211_cqm_rssi_update(rdev, dev);
14530
14531 if (rssi_level == 0)
14532 rssi_level = wdev->cqm_config->last_rssi_event_value;
14533 }
14534
Johannes Berg5b97f492014-11-26 12:37:43 +010014535 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
14536 if (!msg)
14537 return;
14538
David S. Miller9360ffd2012-03-29 04:41:26 -040014539 if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
14540 rssi_event))
14541 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014542
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010014543 if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
14544 rssi_level))
14545 goto nla_put_failure;
14546
Johannes Berg5b97f492014-11-26 12:37:43 +010014547 cfg80211_send_cqm(msg, gfp);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014548
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014549 return;
14550
14551 nla_put_failure:
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014552 nlmsg_free(msg);
14553}
Johannes Berg947add32013-02-22 22:05:20 +010014554EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014555
Johannes Berg5b97f492014-11-26 12:37:43 +010014556void cfg80211_cqm_txe_notify(struct net_device *dev,
14557 const u8 *peer, u32 num_packets,
14558 u32 rate, u32 intvl, gfp_t gfp)
14559{
14560 struct sk_buff *msg;
14561
14562 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14563 if (!msg)
14564 return;
14565
14566 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
14567 goto nla_put_failure;
14568
14569 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
14570 goto nla_put_failure;
14571
14572 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
14573 goto nla_put_failure;
14574
14575 cfg80211_send_cqm(msg, gfp);
14576 return;
14577
14578 nla_put_failure:
14579 nlmsg_free(msg);
14580}
14581EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
14582
14583void cfg80211_cqm_pktloss_notify(struct net_device *dev,
14584 const u8 *peer, u32 num_packets, gfp_t gfp)
14585{
14586 struct sk_buff *msg;
14587
14588 trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
14589
14590 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14591 if (!msg)
14592 return;
14593
14594 if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
14595 goto nla_put_failure;
14596
14597 cfg80211_send_cqm(msg, gfp);
14598 return;
14599
14600 nla_put_failure:
14601 nlmsg_free(msg);
14602}
14603EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
14604
Johannes Berg98f03342014-11-26 12:42:02 +010014605void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
14606{
14607 struct sk_buff *msg;
14608
14609 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
14610 if (!msg)
14611 return;
14612
14613 if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
14614 goto nla_put_failure;
14615
14616 cfg80211_send_cqm(msg, gfp);
14617 return;
14618
14619 nla_put_failure:
14620 nlmsg_free(msg);
14621}
14622EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
14623
Johannes Berg947add32013-02-22 22:05:20 +010014624static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
14625 struct net_device *netdev, const u8 *bssid,
14626 const u8 *replay_ctr, gfp_t gfp)
Johannes Berge5497d72011-07-05 16:35:40 +020014627{
14628 struct sk_buff *msg;
14629 struct nlattr *rekey_attr;
14630 void *hdr;
14631
Thomas Graf58050fc2012-06-28 03:57:45 +000014632 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014633 if (!msg)
14634 return;
14635
14636 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
14637 if (!hdr) {
14638 nlmsg_free(msg);
14639 return;
14640 }
14641
David S. Miller9360ffd2012-03-29 04:41:26 -040014642 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14643 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14644 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
14645 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014646
14647 rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
14648 if (!rekey_attr)
14649 goto nla_put_failure;
14650
David S. Miller9360ffd2012-03-29 04:41:26 -040014651 if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
14652 NL80211_REPLAY_CTR_LEN, replay_ctr))
14653 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014654
14655 nla_nest_end(msg, rekey_attr);
14656
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014657 genlmsg_end(msg, hdr);
Johannes Berge5497d72011-07-05 16:35:40 +020014658
Johannes Berg68eb5502013-11-19 15:19:38 +010014659 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014660 NL80211_MCGRP_MLME, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014661 return;
14662
14663 nla_put_failure:
14664 genlmsg_cancel(msg, hdr);
14665 nlmsg_free(msg);
14666}
14667
Johannes Berg947add32013-02-22 22:05:20 +010014668void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
14669 const u8 *replay_ctr, gfp_t gfp)
14670{
14671 struct wireless_dev *wdev = dev->ieee80211_ptr;
14672 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014673 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014674
14675 trace_cfg80211_gtk_rekey_notify(dev, bssid);
14676 nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
14677}
14678EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
14679
14680static void
14681nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
14682 struct net_device *netdev, int index,
14683 const u8 *bssid, bool preauth, gfp_t gfp)
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014684{
14685 struct sk_buff *msg;
14686 struct nlattr *attr;
14687 void *hdr;
14688
Thomas Graf58050fc2012-06-28 03:57:45 +000014689 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014690 if (!msg)
14691 return;
14692
14693 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
14694 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) ||
14700 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
14701 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014702
14703 attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE);
14704 if (!attr)
14705 goto nla_put_failure;
14706
David S. Miller9360ffd2012-03-29 04:41:26 -040014707 if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
14708 nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
14709 (preauth &&
14710 nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
14711 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014712
14713 nla_nest_end(msg, attr);
14714
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014715 genlmsg_end(msg, hdr);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014716
Johannes Berg68eb5502013-11-19 15:19:38 +010014717 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014718 NL80211_MCGRP_MLME, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014719 return;
14720
14721 nla_put_failure:
14722 genlmsg_cancel(msg, hdr);
14723 nlmsg_free(msg);
14724}
14725
Johannes Berg947add32013-02-22 22:05:20 +010014726void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
14727 const u8 *bssid, bool preauth, gfp_t gfp)
14728{
14729 struct wireless_dev *wdev = dev->ieee80211_ptr;
14730 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014731 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014732
14733 trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
14734 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
14735}
14736EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
14737
14738static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
14739 struct net_device *netdev,
14740 struct cfg80211_chan_def *chandef,
Luciano Coelhof8d75522014-11-07 14:31:35 +020014741 gfp_t gfp,
14742 enum nl80211_commands notif,
14743 u8 count)
Thomas Pedersen53145262012-04-06 13:35:47 -070014744{
14745 struct sk_buff *msg;
14746 void *hdr;
14747
Thomas Graf58050fc2012-06-28 03:57:45 +000014748 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070014749 if (!msg)
14750 return;
14751
Luciano Coelhof8d75522014-11-07 14:31:35 +020014752 hdr = nl80211hdr_put(msg, 0, 0, 0, notif);
Thomas Pedersen53145262012-04-06 13:35:47 -070014753 if (!hdr) {
14754 nlmsg_free(msg);
14755 return;
14756 }
14757
Johannes Berg683b6d32012-11-08 21:25:48 +010014758 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
14759 goto nla_put_failure;
14760
14761 if (nl80211_send_chandef(msg, chandef))
John W. Linville7eab0f62012-04-12 14:25:14 -040014762 goto nla_put_failure;
Thomas Pedersen53145262012-04-06 13:35:47 -070014763
Luciano Coelhof8d75522014-11-07 14:31:35 +020014764 if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) &&
14765 (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count)))
14766 goto nla_put_failure;
14767
Thomas Pedersen53145262012-04-06 13:35:47 -070014768 genlmsg_end(msg, hdr);
14769
Johannes Berg68eb5502013-11-19 15:19:38 +010014770 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014771 NL80211_MCGRP_MLME, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070014772 return;
14773
14774 nla_put_failure:
14775 genlmsg_cancel(msg, hdr);
14776 nlmsg_free(msg);
14777}
14778
Johannes Berg947add32013-02-22 22:05:20 +010014779void cfg80211_ch_switch_notify(struct net_device *dev,
14780 struct cfg80211_chan_def *chandef)
Thomas Pedersen84f10702012-07-12 16:17:33 -070014781{
Johannes Berg947add32013-02-22 22:05:20 +010014782 struct wireless_dev *wdev = dev->ieee80211_ptr;
14783 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014784 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014785
Simon Wunderliche487eae2013-11-21 18:19:51 +010014786 ASSERT_WDEV_LOCK(wdev);
Johannes Berg947add32013-02-22 22:05:20 +010014787
Simon Wunderliche487eae2013-11-21 18:19:51 +010014788 trace_cfg80211_ch_switch_notify(dev, chandef);
Johannes Berg947add32013-02-22 22:05:20 +010014789
Michal Kazior9e0e2962014-01-29 14:22:27 +010014790 wdev->chandef = *chandef;
Janusz Dziedzic96f55f12014-01-24 14:29:21 +010014791 wdev->preset_chandef = *chandef;
Luciano Coelhof8d75522014-11-07 14:31:35 +020014792 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
14793 NL80211_CMD_CH_SWITCH_NOTIFY, 0);
Johannes Berg947add32013-02-22 22:05:20 +010014794}
14795EXPORT_SYMBOL(cfg80211_ch_switch_notify);
14796
Luciano Coelhof8d75522014-11-07 14:31:35 +020014797void cfg80211_ch_switch_started_notify(struct net_device *dev,
14798 struct cfg80211_chan_def *chandef,
14799 u8 count)
14800{
14801 struct wireless_dev *wdev = dev->ieee80211_ptr;
14802 struct wiphy *wiphy = wdev->wiphy;
14803 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
14804
14805 trace_cfg80211_ch_switch_started_notify(dev, chandef);
14806
14807 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
14808 NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count);
14809}
14810EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
14811
Thomas Pedersen84f10702012-07-12 16:17:33 -070014812void
Simon Wunderlich04f39042013-02-08 18:16:19 +010014813nl80211_radar_notify(struct cfg80211_registered_device *rdev,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +010014814 const struct cfg80211_chan_def *chandef,
Simon Wunderlich04f39042013-02-08 18:16:19 +010014815 enum nl80211_radar_event event,
14816 struct net_device *netdev, gfp_t gfp)
14817{
14818 struct sk_buff *msg;
14819 void *hdr;
14820
14821 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14822 if (!msg)
14823 return;
14824
14825 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
14826 if (!hdr) {
14827 nlmsg_free(msg);
14828 return;
14829 }
14830
14831 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
14832 goto nla_put_failure;
14833
14834 /* NOP and radar events don't need a netdev parameter */
14835 if (netdev) {
14836 struct wireless_dev *wdev = netdev->ieee80211_ptr;
14837
14838 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014839 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14840 NL80211_ATTR_PAD))
Simon Wunderlich04f39042013-02-08 18:16:19 +010014841 goto nla_put_failure;
14842 }
14843
14844 if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
14845 goto nla_put_failure;
14846
14847 if (nl80211_send_chandef(msg, chandef))
14848 goto nla_put_failure;
14849
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014850 genlmsg_end(msg, hdr);
Simon Wunderlich04f39042013-02-08 18:16:19 +010014851
Johannes Berg68eb5502013-11-19 15:19:38 +010014852 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014853 NL80211_MCGRP_MLME, gfp);
Simon Wunderlich04f39042013-02-08 18:16:19 +010014854 return;
14855
14856 nla_put_failure:
14857 genlmsg_cancel(msg, hdr);
14858 nlmsg_free(msg);
14859}
14860
Johannes Berg7f6cf312011-11-04 11:18:15 +010014861void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
14862 u64 cookie, bool acked, gfp_t gfp)
14863{
14864 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014865 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014866 struct sk_buff *msg;
14867 void *hdr;
Johannes Berg7f6cf312011-11-04 11:18:15 +010014868
Beni Lev4ee3e062012-08-27 12:49:39 +030014869 trace_cfg80211_probe_status(dev, addr, cookie, acked);
14870
Thomas Graf58050fc2012-06-28 03:57:45 +000014871 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Beni Lev4ee3e062012-08-27 12:49:39 +030014872
Johannes Berg7f6cf312011-11-04 11:18:15 +010014873 if (!msg)
14874 return;
14875
14876 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
14877 if (!hdr) {
14878 nlmsg_free(msg);
14879 return;
14880 }
14881
David S. Miller9360ffd2012-03-29 04:41:26 -040014882 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14883 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14884 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014885 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14886 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014887 (acked && nla_put_flag(msg, NL80211_ATTR_ACK)))
14888 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010014889
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014890 genlmsg_end(msg, hdr);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014891
Johannes Berg68eb5502013-11-19 15:19:38 +010014892 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014893 NL80211_MCGRP_MLME, gfp);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014894 return;
14895
14896 nla_put_failure:
14897 genlmsg_cancel(msg, hdr);
14898 nlmsg_free(msg);
14899}
14900EXPORT_SYMBOL(cfg80211_probe_status);
14901
Johannes Berg5e760232011-11-04 11:18:17 +010014902void cfg80211_report_obss_beacon(struct wiphy *wiphy,
14903 const u8 *frame, size_t len,
Ben Greear37c73b52012-10-26 14:49:25 -070014904 int freq, int sig_dbm)
Johannes Berg5e760232011-11-04 11:18:17 +010014905{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014906 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg5e760232011-11-04 11:18:17 +010014907 struct sk_buff *msg;
14908 void *hdr;
Ben Greear37c73b52012-10-26 14:49:25 -070014909 struct cfg80211_beacon_registration *reg;
Johannes Berg5e760232011-11-04 11:18:17 +010014910
Beni Lev4ee3e062012-08-27 12:49:39 +030014911 trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
14912
Ben Greear37c73b52012-10-26 14:49:25 -070014913 spin_lock_bh(&rdev->beacon_registrations_lock);
14914 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
14915 msg = nlmsg_new(len + 100, GFP_ATOMIC);
14916 if (!msg) {
14917 spin_unlock_bh(&rdev->beacon_registrations_lock);
14918 return;
14919 }
Johannes Berg5e760232011-11-04 11:18:17 +010014920
Ben Greear37c73b52012-10-26 14:49:25 -070014921 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
14922 if (!hdr)
14923 goto nla_put_failure;
Johannes Berg5e760232011-11-04 11:18:17 +010014924
Ben Greear37c73b52012-10-26 14:49:25 -070014925 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14926 (freq &&
14927 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
14928 (sig_dbm &&
14929 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
14930 nla_put(msg, NL80211_ATTR_FRAME, len, frame))
14931 goto nla_put_failure;
14932
14933 genlmsg_end(msg, hdr);
14934
14935 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
Johannes Berg5e760232011-11-04 11:18:17 +010014936 }
Ben Greear37c73b52012-10-26 14:49:25 -070014937 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010014938 return;
14939
14940 nla_put_failure:
Ben Greear37c73b52012-10-26 14:49:25 -070014941 spin_unlock_bh(&rdev->beacon_registrations_lock);
14942 if (hdr)
14943 genlmsg_cancel(msg, hdr);
Johannes Berg5e760232011-11-04 11:18:17 +010014944 nlmsg_free(msg);
14945}
14946EXPORT_SYMBOL(cfg80211_report_obss_beacon);
14947
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014948#ifdef CONFIG_PM
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014949static int cfg80211_net_detect_results(struct sk_buff *msg,
14950 struct cfg80211_wowlan_wakeup *wakeup)
14951{
14952 struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect;
14953 struct nlattr *nl_results, *nl_match, *nl_freqs;
14954 int i, j;
14955
14956 nl_results = nla_nest_start(
14957 msg, NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS);
14958 if (!nl_results)
14959 return -EMSGSIZE;
14960
14961 for (i = 0; i < nd->n_matches; i++) {
14962 struct cfg80211_wowlan_nd_match *match = nd->matches[i];
14963
14964 nl_match = nla_nest_start(msg, i);
14965 if (!nl_match)
14966 break;
14967
14968 /* The SSID attribute is optional in nl80211, but for
14969 * simplicity reasons it's always present in the
14970 * cfg80211 structure. If a driver can't pass the
14971 * SSID, that needs to be changed. A zero length SSID
14972 * is still a valid SSID (wildcard), so it cannot be
14973 * used for this purpose.
14974 */
14975 if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len,
14976 match->ssid.ssid)) {
14977 nla_nest_cancel(msg, nl_match);
14978 goto out;
14979 }
14980
14981 if (match->n_channels) {
14982 nl_freqs = nla_nest_start(
14983 msg, NL80211_ATTR_SCAN_FREQUENCIES);
14984 if (!nl_freqs) {
14985 nla_nest_cancel(msg, nl_match);
14986 goto out;
14987 }
14988
14989 for (j = 0; j < match->n_channels; j++) {
Samuel Tan5528fae82015-02-09 21:29:15 +020014990 if (nla_put_u32(msg, j, match->channels[j])) {
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014991 nla_nest_cancel(msg, nl_freqs);
14992 nla_nest_cancel(msg, nl_match);
14993 goto out;
14994 }
14995 }
14996
14997 nla_nest_end(msg, nl_freqs);
14998 }
14999
15000 nla_nest_end(msg, nl_match);
15001 }
15002
15003out:
15004 nla_nest_end(msg, nl_results);
15005 return 0;
15006}
15007
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015008void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
15009 struct cfg80211_wowlan_wakeup *wakeup,
15010 gfp_t gfp)
15011{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015012 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015013 struct sk_buff *msg;
15014 void *hdr;
Johannes Berg9c90a9f2013-06-04 12:46:03 +020015015 int size = 200;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015016
15017 trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
15018
15019 if (wakeup)
15020 size += wakeup->packet_present_len;
15021
15022 msg = nlmsg_new(size, gfp);
15023 if (!msg)
15024 return;
15025
15026 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN);
15027 if (!hdr)
15028 goto free_msg;
15029
15030 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015031 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15032 NL80211_ATTR_PAD))
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015033 goto free_msg;
15034
15035 if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
15036 wdev->netdev->ifindex))
15037 goto free_msg;
15038
15039 if (wakeup) {
15040 struct nlattr *reasons;
15041
15042 reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
Johannes Berg7fa322c2013-10-25 11:16:58 +020015043 if (!reasons)
15044 goto free_msg;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015045
15046 if (wakeup->disconnect &&
15047 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
15048 goto free_msg;
15049 if (wakeup->magic_pkt &&
15050 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT))
15051 goto free_msg;
15052 if (wakeup->gtk_rekey_failure &&
15053 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE))
15054 goto free_msg;
15055 if (wakeup->eap_identity_req &&
15056 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST))
15057 goto free_msg;
15058 if (wakeup->four_way_handshake &&
15059 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE))
15060 goto free_msg;
15061 if (wakeup->rfkill_release &&
15062 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))
15063 goto free_msg;
15064
15065 if (wakeup->pattern_idx >= 0 &&
15066 nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
15067 wakeup->pattern_idx))
15068 goto free_msg;
15069
Johannes Bergae917c92013-10-25 11:05:22 +020015070 if (wakeup->tcp_match &&
15071 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
15072 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010015073
Johannes Bergae917c92013-10-25 11:05:22 +020015074 if (wakeup->tcp_connlost &&
15075 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
15076 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010015077
Johannes Bergae917c92013-10-25 11:05:22 +020015078 if (wakeup->tcp_nomoretokens &&
15079 nla_put_flag(msg,
15080 NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
15081 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010015082
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015083 if (wakeup->packet) {
15084 u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
15085 u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN;
15086
15087 if (!wakeup->packet_80211) {
15088 pkt_attr =
15089 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023;
15090 len_attr =
15091 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN;
15092 }
15093
15094 if (wakeup->packet_len &&
15095 nla_put_u32(msg, len_attr, wakeup->packet_len))
15096 goto free_msg;
15097
15098 if (nla_put(msg, pkt_attr, wakeup->packet_present_len,
15099 wakeup->packet))
15100 goto free_msg;
15101 }
15102
Luciano Coelho8cd4d452014-09-17 11:55:28 +030015103 if (wakeup->net_detect &&
15104 cfg80211_net_detect_results(msg, wakeup))
15105 goto free_msg;
15106
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015107 nla_nest_end(msg, reasons);
15108 }
15109
Johannes Berg9c90a9f2013-06-04 12:46:03 +020015110 genlmsg_end(msg, hdr);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015111
Johannes Berg68eb5502013-11-19 15:19:38 +010015112 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015113 NL80211_MCGRP_MLME, gfp);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010015114 return;
15115
15116 free_msg:
15117 nlmsg_free(msg);
15118}
15119EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup);
15120#endif
15121
Jouni Malinen3475b092012-11-16 22:49:57 +020015122void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
15123 enum nl80211_tdls_operation oper,
15124 u16 reason_code, gfp_t gfp)
15125{
15126 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015127 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Jouni Malinen3475b092012-11-16 22:49:57 +020015128 struct sk_buff *msg;
15129 void *hdr;
Jouni Malinen3475b092012-11-16 22:49:57 +020015130
15131 trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
15132 reason_code);
15133
15134 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15135 if (!msg)
15136 return;
15137
15138 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
15139 if (!hdr) {
15140 nlmsg_free(msg);
15141 return;
15142 }
15143
15144 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15145 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
15146 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
15147 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
15148 (reason_code > 0 &&
15149 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
15150 goto nla_put_failure;
15151
Johannes Berg9c90a9f2013-06-04 12:46:03 +020015152 genlmsg_end(msg, hdr);
Jouni Malinen3475b092012-11-16 22:49:57 +020015153
Johannes Berg68eb5502013-11-19 15:19:38 +010015154 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015155 NL80211_MCGRP_MLME, gfp);
Jouni Malinen3475b092012-11-16 22:49:57 +020015156 return;
15157
15158 nla_put_failure:
15159 genlmsg_cancel(msg, hdr);
15160 nlmsg_free(msg);
15161}
15162EXPORT_SYMBOL(cfg80211_tdls_oper_request);
15163
Jouni Malinen026331c2010-02-15 12:53:10 +020015164static int nl80211_netlink_notify(struct notifier_block * nb,
15165 unsigned long state,
15166 void *_notify)
15167{
15168 struct netlink_notify *notify = _notify;
15169 struct cfg80211_registered_device *rdev;
15170 struct wireless_dev *wdev;
Ben Greear37c73b52012-10-26 14:49:25 -070015171 struct cfg80211_beacon_registration *reg, *tmp;
Jouni Malinen026331c2010-02-15 12:53:10 +020015172
Dmitry Ivanov8f815cd2016-04-06 17:23:18 +030015173 if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
Jouni Malinen026331c2010-02-15 12:53:10 +020015174 return NOTIFY_DONE;
15175
15176 rcu_read_lock();
15177
Johannes Berg5e760232011-11-04 11:18:17 +010015178 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
Arend Van Sprielca986ad2017-04-21 13:05:00 +010015179 struct cfg80211_sched_scan_request *sched_scan_req;
Jukka Rissanen93a1e862014-12-15 13:25:39 +020015180
Arend Van Sprielca986ad2017-04-21 13:05:00 +010015181 list_for_each_entry_rcu(sched_scan_req,
15182 &rdev->sched_scan_req_list,
15183 list) {
15184 if (sched_scan_req->owner_nlportid == notify->portid) {
15185 sched_scan_req->nl_owner_dead = true;
Johannes Berg753aacf2017-01-05 10:57:14 +010015186 schedule_work(&rdev->sched_scan_stop_wk);
Arend Van Sprielca986ad2017-04-21 13:05:00 +010015187 }
Johannes Berg753aacf2017-01-05 10:57:14 +010015188 }
Johannes Berg78f22b62014-03-24 17:57:27 +010015189
Johannes Berg53873f12016-05-03 16:52:04 +030015190 list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
Eric W. Biederman15e47302012-09-07 20:12:54 +000015191 cfg80211_mlme_unregister_socket(wdev, notify->portid);
Ben Greear37c73b52012-10-26 14:49:25 -070015192
Johannes Bergab810072017-04-26 07:43:41 +020015193 if (wdev->owner_nlportid == notify->portid) {
15194 wdev->nl_owner_dead = true;
15195 schedule_work(&rdev->destroy_work);
15196 } else if (wdev->conn_owner_nlportid == notify->portid) {
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050015197 schedule_work(&wdev->disconnect_wk);
Johannes Bergab810072017-04-26 07:43:41 +020015198 }
Johannes Berg78f22b62014-03-24 17:57:27 +010015199 }
15200
Ben Greear37c73b52012-10-26 14:49:25 -070015201 spin_lock_bh(&rdev->beacon_registrations_lock);
15202 list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
15203 list) {
15204 if (reg->nlportid == notify->portid) {
15205 list_del(&reg->list);
15206 kfree(reg);
15207 break;
15208 }
15209 }
15210 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010015211 }
Jouni Malinen026331c2010-02-15 12:53:10 +020015212
15213 rcu_read_unlock();
15214
Ilan peer05050752015-03-04 00:32:06 -050015215 /*
15216 * It is possible that the user space process that is controlling the
15217 * indoor setting disappeared, so notify the regulatory core.
15218 */
15219 regulatory_netlink_notify(notify->portid);
Zhao, Gang6784c7d2014-04-21 12:53:04 +080015220 return NOTIFY_OK;
Jouni Malinen026331c2010-02-15 12:53:10 +020015221}
15222
15223static struct notifier_block nl80211_netlink_notifier = {
15224 .notifier_call = nl80211_netlink_notify,
15225};
15226
Jouni Malinen355199e2013-02-27 17:14:27 +020015227void cfg80211_ft_event(struct net_device *netdev,
15228 struct cfg80211_ft_event_params *ft_event)
15229{
15230 struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015231 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinen355199e2013-02-27 17:14:27 +020015232 struct sk_buff *msg;
15233 void *hdr;
Jouni Malinen355199e2013-02-27 17:14:27 +020015234
15235 trace_cfg80211_ft_event(wiphy, netdev, ft_event);
15236
15237 if (!ft_event->target_ap)
15238 return;
15239
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010015240 msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
Jouni Malinen355199e2013-02-27 17:14:27 +020015241 if (!msg)
15242 return;
15243
15244 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
Johannes Bergae917c92013-10-25 11:05:22 +020015245 if (!hdr)
15246 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020015247
Johannes Bergae917c92013-10-25 11:05:22 +020015248 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15249 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
15250 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
15251 goto out;
15252
15253 if (ft_event->ies &&
15254 nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
15255 goto out;
15256 if (ft_event->ric_ies &&
15257 nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
15258 ft_event->ric_ies))
15259 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020015260
Johannes Berg9c90a9f2013-06-04 12:46:03 +020015261 genlmsg_end(msg, hdr);
Jouni Malinen355199e2013-02-27 17:14:27 +020015262
Johannes Berg68eb5502013-11-19 15:19:38 +010015263 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010015264 NL80211_MCGRP_MLME, GFP_KERNEL);
Johannes Bergae917c92013-10-25 11:05:22 +020015265 return;
15266 out:
15267 nlmsg_free(msg);
Jouni Malinen355199e2013-02-27 17:14:27 +020015268}
15269EXPORT_SYMBOL(cfg80211_ft_event);
15270
Arend van Spriel5de17982013-04-18 15:49:00 +020015271void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
15272{
15273 struct cfg80211_registered_device *rdev;
15274 struct sk_buff *msg;
15275 void *hdr;
15276 u32 nlportid;
15277
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015278 rdev = wiphy_to_rdev(wdev->wiphy);
Arend van Spriel5de17982013-04-18 15:49:00 +020015279 if (!rdev->crit_proto_nlportid)
15280 return;
15281
15282 nlportid = rdev->crit_proto_nlportid;
15283 rdev->crit_proto_nlportid = 0;
15284
15285 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
15286 if (!msg)
15287 return;
15288
15289 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
15290 if (!hdr)
15291 goto nla_put_failure;
15292
15293 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015294 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15295 NL80211_ATTR_PAD))
Arend van Spriel5de17982013-04-18 15:49:00 +020015296 goto nla_put_failure;
15297
15298 genlmsg_end(msg, hdr);
15299
15300 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
15301 return;
15302
15303 nla_put_failure:
15304 if (hdr)
15305 genlmsg_cancel(msg, hdr);
15306 nlmsg_free(msg);
Arend van Spriel5de17982013-04-18 15:49:00 +020015307}
15308EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
15309
Johannes Berg348baf02014-01-24 14:06:29 +010015310void nl80211_send_ap_stopped(struct wireless_dev *wdev)
15311{
15312 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015313 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg348baf02014-01-24 14:06:29 +010015314 struct sk_buff *msg;
15315 void *hdr;
15316
15317 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
15318 if (!msg)
15319 return;
15320
15321 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
15322 if (!hdr)
15323 goto out;
15324
15325 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15326 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015327 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15328 NL80211_ATTR_PAD))
Johannes Berg348baf02014-01-24 14:06:29 +010015329 goto out;
15330
15331 genlmsg_end(msg, hdr);
15332
15333 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
15334 NL80211_MCGRP_MLME, GFP_KERNEL);
15335 return;
15336 out:
15337 nlmsg_free(msg);
15338}
15339
Johannes Berg55682962007-09-20 13:09:35 -040015340/* initialisation/exit functions */
15341
Johannes Berg56989f62016-10-24 14:40:05 +020015342int __init nl80211_init(void)
Johannes Berg55682962007-09-20 13:09:35 -040015343{
Michał Mirosław0d63cbb2009-05-21 10:34:06 +000015344 int err;
Johannes Berg55682962007-09-20 13:09:35 -040015345
Johannes Berg489111e2016-10-24 14:40:03 +020015346 err = genl_register_family(&nl80211_fam);
Johannes Berg55682962007-09-20 13:09:35 -040015347 if (err)
15348 return err;
15349
Jouni Malinen026331c2010-02-15 12:53:10 +020015350 err = netlink_register_notifier(&nl80211_netlink_notifier);
15351 if (err)
15352 goto err_out;
15353
Johannes Berg55682962007-09-20 13:09:35 -040015354 return 0;
15355 err_out:
15356 genl_unregister_family(&nl80211_fam);
15357 return err;
15358}
15359
15360void nl80211_exit(void)
15361{
Jouni Malinen026331c2010-02-15 12:53:10 +020015362 netlink_unregister_notifier(&nl80211_netlink_notifier);
Johannes Berg55682962007-09-20 13:09:35 -040015363 genl_unregister_family(&nl80211_fam);
15364}