blob: 9910aae08f1a99b2ce37e43782dbf8bf7019c83e [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 },
Samuel Ortiz67fbb162009-11-24 23:59:15 +0100294 [NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
295 .len = WLAN_PMKID_LEN },
Jouni Malinen9588bbd2009-12-23 13:15:41 +0100296 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
297 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +0200298 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
Jouni Malinen026331c2010-02-15 12:53:10 +0200299 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
300 .len = IEEE80211_MAX_DATA_LEN },
301 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
Kalle Valoffb9eb32010-02-17 17:58:10 +0200302 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +0200303 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
Jouni Malinend5cdfac2010-04-04 09:37:19 +0300304 [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +0200305 [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +0300306 [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
307 [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
Johannes Berg2e161f72010-08-12 15:38:38 +0200308 [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
Bruno Randolfafe0cbf2010-11-10 12:50:50 +0900309 [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 },
310 [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
Felix Fietkau885a46d2010-11-11 15:07:22 +0100311 [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
Johannes Bergf7ca38d2010-11-25 10:02:29 +0100312 [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100313 [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200314 [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
Javier Cardona9c3990a2011-05-03 16:57:11 -0700315 [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
Luciano Coelhobbe6ad62011-05-11 17:09:37 +0300316 [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
Johannes Berge5497d72011-07-05 16:35:40 +0200317 [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
Johannes Berg34850ab2011-07-18 18:08:35 +0200318 [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
Jouni Malinen32e9de82011-08-10 23:53:31 +0300319 [NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
Jouni Malinen9946ecf2011-08-10 23:55:56 +0300320 [NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
321 .len = IEEE80211_MAX_DATA_LEN },
322 [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
323 .len = IEEE80211_MAX_DATA_LEN },
Vivek Natarajanf4b34b52011-08-29 14:23:03 +0530324 [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300325 [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +0530326 [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
Arik Nemtsov109086c2011-09-28 14:12:50 +0300327 [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
328 [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
329 [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
330 [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
331 [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
Arik Nemtsov31fa97c2014-06-11 17:18:21 +0300332 [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG },
Johannes Berge247bd902011-11-04 11:18:21 +0100333 [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
Arik Nemtsov00f740e2011-11-10 11:28:56 +0200334 [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
335 .len = IEEE80211_MAX_DATA_LEN },
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -0700336 [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
Ben Greear7e7c8922011-11-18 11:31:59 -0800337 [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
338 [NL80211_ATTR_HT_CAPABILITY_MASK] = {
339 .len = NL80211_HT_CAPABILITY_LEN
340 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +0100341 [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +0530342 [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
Bala Shanmugam4486ea92012-03-07 17:27:12 +0530343 [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
Johannes Berg89a54e42012-06-15 14:33:17 +0200344 [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -0700345 [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
Jouni Malinen11b6b5a2016-10-27 00:41:58 +0300346 [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +0000347 [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
Sam Lefflered4737712012-10-11 21:03:31 -0700348 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
Johannes Berg53cabad2012-11-14 15:17:28 +0100349 [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
350 [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
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 },
Johannes Berg55682962007-09-20 13:09:35 -0400422};
423
Johannes Berge31b8212010-10-05 19:39:30 +0200424/* policy for the key attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000425static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
Johannes Bergfffd0932009-07-08 14:22:54 +0200426 [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
Johannes Bergb9454e82009-07-08 13:29:08 +0200427 [NL80211_KEY_IDX] = { .type = NLA_U8 },
428 [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
Jouni Malinen81962262011-11-02 23:36:31 +0200429 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Johannes Bergb9454e82009-07-08 13:29:08 +0200430 [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
431 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
Johannes Berge31b8212010-10-05 19:39:30 +0200432 [NL80211_KEY_TYPE] = { .type = NLA_U32 },
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100433 [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
434};
435
436/* policy for the key default flags */
437static const struct nla_policy
438nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
439 [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
440 [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
Johannes Bergb9454e82009-07-08 13:29:08 +0200441};
442
Johannes Bergf83ace32016-10-17 08:04:07 +0200443#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +0200444/* policy for WoWLAN attributes */
445static const struct nla_policy
446nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
447 [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
448 [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
449 [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
450 [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
Johannes Berg77dbbb12011-07-13 10:48:55 +0200451 [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG },
452 [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG },
453 [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG },
454 [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100455 [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED },
Luciano Coelho8cd4d452014-09-17 11:55:28 +0300456 [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED },
Johannes Berg2a0e0472013-01-23 22:57:40 +0100457};
458
459static const struct nla_policy
460nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
461 [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
462 [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
463 [NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN },
464 [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
465 [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
466 [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 },
467 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
468 .len = sizeof(struct nl80211_wowlan_tcp_data_seq)
469 },
470 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = {
471 .len = sizeof(struct nl80211_wowlan_tcp_data_token)
472 },
473 [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
474 [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 },
475 [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
Johannes Bergff1b6e62011-05-04 15:37:28 +0200476};
Johannes Bergf83ace32016-10-17 08:04:07 +0200477#endif /* CONFIG_PM */
Johannes Bergff1b6e62011-05-04 15:37:28 +0200478
Amitkumar Karwarbe29b992013-06-28 11:51:26 -0700479/* policy for coalesce rule attributes */
480static const struct nla_policy
481nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
482 [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
483 [NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 },
484 [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
485};
486
Johannes Berge5497d72011-07-05 16:35:40 +0200487/* policy for GTK rekey offload attributes */
488static const struct nla_policy
489nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
490 [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN },
491 [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN },
492 [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
493};
494
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300495static const struct nla_policy
496nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
Johannes Berg4a4ab0d2012-06-13 11:17:11 +0200497 [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300498 .len = IEEE80211_MAX_SSID_LEN },
Thomas Pedersen88e920b2012-06-21 11:09:54 -0700499 [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
Luciano Coelhoa1f1c212011-08-31 16:01:48 +0300500};
501
Avraham Stern3b06d272015-10-12 09:51:34 +0300502static const struct nla_policy
503nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
504 [NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
505 [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
506};
507
Arend van Spriel38de03d2016-03-02 20:37:18 +0100508static const struct nla_policy
509nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
510 [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
511 [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
512 [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
513 .len = sizeof(struct nl80211_bss_select_rssi_adjust)
514 },
515};
516
Ayala Bekera442b762016-09-20 17:31:15 +0300517/* policy for NAN function attributes */
518static const struct nla_policy
519nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
520 [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
521 [NL80211_NAN_FUNC_SERVICE_ID] = { .type = NLA_BINARY,
522 .len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
523 [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
524 [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
525 [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
526 [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
527 [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
528 [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { .len = ETH_ALEN },
529 [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
530 [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
531 [NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
532 .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN },
533 [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
534 [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
535 [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
536 [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8 },
537 [NL80211_NAN_FUNC_TERM_REASON] = { .type = NLA_U8 },
538};
539
540/* policy for Service Response Filter attributes */
541static const struct nla_policy
542nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
543 [NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG },
544 [NL80211_NAN_SRF_BF] = { .type = NLA_BINARY,
545 .len = NL80211_NAN_FUNC_SRF_MAX_LEN },
546 [NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 },
547 [NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED },
548};
549
Johannes Berg97990a02013-04-19 01:02:55 +0200550static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
551 struct netlink_callback *cb,
552 struct cfg80211_registered_device **rdev,
553 struct wireless_dev **wdev)
Holger Schuriga0438972009-11-11 11:30:02 +0100554{
Johannes Berg67748892010-10-04 21:14:06 +0200555 int err;
556
Johannes Berg67748892010-10-04 21:14:06 +0200557 rtnl_lock();
558
Johannes Berg97990a02013-04-19 01:02:55 +0200559 if (!cb->args[0]) {
560 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergc90c39d2016-10-24 14:40:01 +0200561 genl_family_attrbuf(&nl80211_fam),
562 nl80211_fam.maxattr, nl80211_policy);
Johannes Berg97990a02013-04-19 01:02:55 +0200563 if (err)
564 goto out_unlock;
565
Johannes Bergc90c39d2016-10-24 14:40:01 +0200566 *wdev = __cfg80211_wdev_from_attrs(
567 sock_net(skb->sk),
568 genl_family_attrbuf(&nl80211_fam));
Johannes Berg97990a02013-04-19 01:02:55 +0200569 if (IS_ERR(*wdev)) {
570 err = PTR_ERR(*wdev);
571 goto out_unlock;
572 }
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800573 *rdev = wiphy_to_rdev((*wdev)->wiphy);
Johannes Bergc319d502013-07-30 22:34:28 +0200574 /* 0 is the first index - add 1 to parse only once */
575 cb->args[0] = (*rdev)->wiphy_idx + 1;
Johannes Berg97990a02013-04-19 01:02:55 +0200576 cb->args[1] = (*wdev)->identifier;
577 } else {
Johannes Bergc319d502013-07-30 22:34:28 +0200578 /* subtract the 1 again here */
579 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
Johannes Berg97990a02013-04-19 01:02:55 +0200580 struct wireless_dev *tmp;
581
582 if (!wiphy) {
583 err = -ENODEV;
584 goto out_unlock;
585 }
Zhao, Gangf26cbf42014-04-21 12:53:03 +0800586 *rdev = wiphy_to_rdev(wiphy);
Johannes Berg97990a02013-04-19 01:02:55 +0200587 *wdev = NULL;
588
Johannes Berg53873f12016-05-03 16:52:04 +0300589 list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
Johannes Berg97990a02013-04-19 01:02:55 +0200590 if (tmp->identifier == cb->args[1]) {
591 *wdev = tmp;
592 break;
593 }
594 }
Johannes Berg97990a02013-04-19 01:02:55 +0200595
596 if (!*wdev) {
597 err = -ENODEV;
598 goto out_unlock;
599 }
Johannes Berg67748892010-10-04 21:14:06 +0200600 }
601
Johannes Berg67748892010-10-04 21:14:06 +0200602 return 0;
Johannes Berg97990a02013-04-19 01:02:55 +0200603 out_unlock:
Johannes Berg67748892010-10-04 21:14:06 +0200604 rtnl_unlock();
605 return err;
606}
607
Johannes Berg97990a02013-04-19 01:02:55 +0200608static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev)
Johannes Berg67748892010-10-04 21:14:06 +0200609{
Johannes Berg67748892010-10-04 21:14:06 +0200610 rtnl_unlock();
611}
612
Johannes Bergf4a11bb2009-03-27 12:40:28 +0100613/* IE validation */
614static bool is_valid_ie_attr(const struct nlattr *attr)
615{
616 const u8 *pos;
617 int len;
618
619 if (!attr)
620 return true;
621
622 pos = nla_data(attr);
623 len = nla_len(attr);
624
625 while (len) {
626 u8 elemlen;
627
628 if (len < 2)
629 return false;
630 len -= 2;
631
632 elemlen = pos[1];
633 if (elemlen > len)
634 return false;
635
636 len -= elemlen;
637 pos += 2 + elemlen;
638 }
639
640 return true;
641}
642
Johannes Berg55682962007-09-20 13:09:35 -0400643/* message building helper */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000644static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
Johannes Berg55682962007-09-20 13:09:35 -0400645 int flags, u8 cmd)
646{
647 /* since there is no private header just add the generic one */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000648 return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -0400649}
650
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400651static int nl80211_msg_put_channel(struct sk_buff *msg,
Johannes Bergcdc89b92013-02-18 23:54:36 +0100652 struct ieee80211_channel *chan,
653 bool large)
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400654{
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200655 /* Some channels must be completely excluded from the
656 * list to protect old user-space tools from breaking
657 */
658 if (!large && chan->flags &
659 (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
660 return 0;
661
David S. Miller9360ffd2012-03-29 04:41:26 -0400662 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
663 chan->center_freq))
664 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400665
David S. Miller9360ffd2012-03-29 04:41:26 -0400666 if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
667 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
668 goto nla_put_failure;
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200669 if (chan->flags & IEEE80211_CHAN_NO_IR) {
670 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
671 goto nla_put_failure;
672 if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
673 goto nla_put_failure;
674 }
Johannes Bergcdc89b92013-02-18 23:54:36 +0100675 if (chan->flags & IEEE80211_CHAN_RADAR) {
676 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
677 goto nla_put_failure;
678 if (large) {
679 u32 time;
680
681 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
682
683 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
684 chan->dfs_state))
685 goto nla_put_failure;
686 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
687 time))
688 goto nla_put_failure;
Janusz Dziedzic089027e2014-02-21 19:46:12 +0100689 if (nla_put_u32(msg,
690 NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
691 chan->dfs_cac_ms))
692 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +0100693 }
694 }
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400695
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100696 if (large) {
697 if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
698 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
699 goto nla_put_failure;
700 if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
701 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
702 goto nla_put_failure;
703 if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
704 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
705 goto nla_put_failure;
706 if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
707 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
708 goto nla_put_failure;
David Spinadel570dbde2014-02-23 09:12:59 +0200709 if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
710 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
711 goto nla_put_failure;
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300712 if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
713 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
David Spinadel570dbde2014-02-23 09:12:59 +0200714 goto nla_put_failure;
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200715 if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
716 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
717 goto nla_put_failure;
718 if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
719 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
720 goto nla_put_failure;
Johannes Bergfe1abaf2013-02-27 15:39:45 +0100721 }
722
David S. Miller9360ffd2012-03-29 04:41:26 -0400723 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
724 DBM_TO_MBM(chan->max_power)))
725 goto nla_put_failure;
Luis R. Rodriguez5dab3b82009-04-02 14:08:08 -0400726
727 return 0;
728
729 nla_put_failure:
730 return -ENOBUFS;
731}
732
Johannes Berg55682962007-09-20 13:09:35 -0400733/* netlink command implementations */
734
Johannes Bergb9454e82009-07-08 13:29:08 +0200735struct key_parse {
736 struct key_params p;
737 int idx;
Johannes Berge31b8212010-10-05 19:39:30 +0200738 int type;
Johannes Bergb9454e82009-07-08 13:29:08 +0200739 bool def, defmgmt;
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100740 bool def_uni, def_multi;
Johannes Bergb9454e82009-07-08 13:29:08 +0200741};
742
743static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
744{
745 struct nlattr *tb[NL80211_KEY_MAX + 1];
746 int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
747 nl80211_key_policy);
748 if (err)
749 return err;
750
751 k->def = !!tb[NL80211_KEY_DEFAULT];
752 k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
753
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100754 if (k->def) {
755 k->def_uni = true;
756 k->def_multi = true;
757 }
758 if (k->defmgmt)
759 k->def_multi = true;
760
Johannes Bergb9454e82009-07-08 13:29:08 +0200761 if (tb[NL80211_KEY_IDX])
762 k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
763
764 if (tb[NL80211_KEY_DATA]) {
765 k->p.key = nla_data(tb[NL80211_KEY_DATA]);
766 k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
767 }
768
769 if (tb[NL80211_KEY_SEQ]) {
770 k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
771 k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
772 }
773
774 if (tb[NL80211_KEY_CIPHER])
775 k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
776
Johannes Berge31b8212010-10-05 19:39:30 +0200777 if (tb[NL80211_KEY_TYPE]) {
778 k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
779 if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
780 return -EINVAL;
781 }
782
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100783 if (tb[NL80211_KEY_DEFAULT_TYPES]) {
784 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -0700785
Johannes Berg2da8f412012-01-20 13:52:37 +0100786 err = nla_parse_nested(kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
787 tb[NL80211_KEY_DEFAULT_TYPES],
788 nl80211_key_default_policy);
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100789 if (err)
790 return err;
791
792 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
793 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
794 }
795
Johannes Bergb9454e82009-07-08 13:29:08 +0200796 return 0;
797}
798
799static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
800{
801 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
802 k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
803 k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
804 }
805
806 if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
807 k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
808 k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
809 }
810
811 if (info->attrs[NL80211_ATTR_KEY_IDX])
812 k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
813
814 if (info->attrs[NL80211_ATTR_KEY_CIPHER])
815 k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
816
817 k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
818 k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
819
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100820 if (k->def) {
821 k->def_uni = true;
822 k->def_multi = true;
823 }
824 if (k->defmgmt)
825 k->def_multi = true;
826
Johannes Berge31b8212010-10-05 19:39:30 +0200827 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
828 k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
829 if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
830 return -EINVAL;
831 }
832
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100833 if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
834 struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
835 int err = nla_parse_nested(
836 kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
837 info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
838 nl80211_key_default_policy);
839 if (err)
840 return err;
841
842 k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
843 k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
844 }
845
Johannes Bergb9454e82009-07-08 13:29:08 +0200846 return 0;
847}
848
849static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
850{
851 int err;
852
853 memset(k, 0, sizeof(*k));
854 k->idx = -1;
Johannes Berge31b8212010-10-05 19:39:30 +0200855 k->type = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +0200856
857 if (info->attrs[NL80211_ATTR_KEY])
858 err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
859 else
860 err = nl80211_parse_key_old(info, k);
861
862 if (err)
863 return err;
864
865 if (k->def && k->defmgmt)
866 return -EINVAL;
867
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100868 if (k->defmgmt) {
869 if (k->def_uni || !k->def_multi)
870 return -EINVAL;
871 }
872
Johannes Bergb9454e82009-07-08 13:29:08 +0200873 if (k->idx != -1) {
874 if (k->defmgmt) {
875 if (k->idx < 4 || k->idx > 5)
876 return -EINVAL;
877 } else if (k->def) {
878 if (k->idx < 0 || k->idx > 3)
879 return -EINVAL;
880 } else {
881 if (k->idx < 0 || k->idx > 5)
882 return -EINVAL;
883 }
884 }
885
886 return 0;
887}
888
Johannes Bergfffd0932009-07-08 14:22:54 +0200889static struct cfg80211_cached_keys *
890nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +0530891 struct nlattr *keys, bool *no_ht)
Johannes Bergfffd0932009-07-08 14:22:54 +0200892{
893 struct key_parse parse;
894 struct nlattr *key;
895 struct cfg80211_cached_keys *result;
896 int rem, err, def = 0;
Johannes Bergf1c1f172016-09-13 17:08:23 +0200897 bool have_key = false;
898
899 nla_for_each_nested(key, keys, rem) {
900 have_key = true;
901 break;
902 }
903
904 if (!have_key)
905 return NULL;
Johannes Bergfffd0932009-07-08 14:22:54 +0200906
907 result = kzalloc(sizeof(*result), GFP_KERNEL);
908 if (!result)
909 return ERR_PTR(-ENOMEM);
910
911 result->def = -1;
Johannes Bergfffd0932009-07-08 14:22:54 +0200912
913 nla_for_each_nested(key, keys, rem) {
914 memset(&parse, 0, sizeof(parse));
915 parse.idx = -1;
916
917 err = nl80211_parse_key_new(key, &parse);
918 if (err)
919 goto error;
920 err = -EINVAL;
921 if (!parse.p.key)
922 goto error;
Johannes Berg42ee2312016-09-13 15:51:03 +0200923 if (parse.idx < 0 || parse.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +0200924 goto error;
925 if (parse.def) {
926 if (def)
927 goto error;
928 def = 1;
929 result->def = parse.idx;
Johannes Bergdbd2fd62010-12-09 19:58:59 +0100930 if (!parse.def_uni || !parse.def_multi)
931 goto error;
Johannes Bergfffd0932009-07-08 14:22:54 +0200932 } else if (parse.defmgmt)
933 goto error;
934 err = cfg80211_validate_key_settings(rdev, &parse.p,
Johannes Berge31b8212010-10-05 19:39:30 +0200935 parse.idx, false, NULL);
Johannes Bergfffd0932009-07-08 14:22:54 +0200936 if (err)
937 goto error;
Johannes Berg386b1f22016-09-13 16:10:02 +0200938 if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
939 parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) {
940 err = -EINVAL;
941 goto error;
942 }
Johannes Bergfffd0932009-07-08 14:22:54 +0200943 result->params[parse.idx].cipher = parse.p.cipher;
944 result->params[parse.idx].key_len = parse.p.key_len;
945 result->params[parse.idx].key = result->data[parse.idx];
946 memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
Sujith Manoharande7044e2012-10-18 10:19:28 +0530947
Johannes Berg386b1f22016-09-13 16:10:02 +0200948 /* must be WEP key if we got here */
949 if (no_ht)
950 *no_ht = true;
Johannes Bergfffd0932009-07-08 14:22:54 +0200951 }
952
Johannes Bergf1c1f172016-09-13 17:08:23 +0200953 if (result->def < 0) {
954 err = -EINVAL;
955 goto error;
956 }
957
Johannes Bergfffd0932009-07-08 14:22:54 +0200958 return result;
959 error:
960 kfree(result);
961 return ERR_PTR(err);
962}
963
964static int nl80211_key_allowed(struct wireless_dev *wdev)
965{
966 ASSERT_WDEV_LOCK(wdev);
967
Johannes Bergfffd0932009-07-08 14:22:54 +0200968 switch (wdev->iftype) {
969 case NL80211_IFTYPE_AP:
970 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +0200971 case NL80211_IFTYPE_P2P_GO:
Thomas Pedersenff973af2011-05-03 16:57:12 -0700972 case NL80211_IFTYPE_MESH_POINT:
Johannes Bergfffd0932009-07-08 14:22:54 +0200973 break;
974 case NL80211_IFTYPE_ADHOC:
Johannes Bergfffd0932009-07-08 14:22:54 +0200975 case NL80211_IFTYPE_STATION:
Johannes Berg074ac8d2010-09-16 14:58:22 +0200976 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Bergceca7b72013-05-16 00:55:45 +0200977 if (!wdev->current_bss)
Johannes Bergfffd0932009-07-08 14:22:54 +0200978 return -ENOLINK;
979 break;
Johannes Bergde4fcba2014-10-31 14:16:12 +0100980 case NL80211_IFTYPE_UNSPECIFIED:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +0100981 case NL80211_IFTYPE_OCB:
Johannes Bergde4fcba2014-10-31 14:16:12 +0100982 case NL80211_IFTYPE_MONITOR:
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300983 case NL80211_IFTYPE_NAN:
Johannes Bergde4fcba2014-10-31 14:16:12 +0100984 case NL80211_IFTYPE_P2P_DEVICE:
985 case NL80211_IFTYPE_WDS:
986 case NUM_NL80211_IFTYPES:
Johannes Bergfffd0932009-07-08 14:22:54 +0200987 return -EINVAL;
988 }
989
990 return 0;
991}
992
Jouni Malinen664834d2014-01-15 00:01:44 +0200993static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
994 struct nlattr *tb)
995{
996 struct ieee80211_channel *chan;
997
998 if (tb == NULL)
999 return NULL;
1000 chan = ieee80211_get_channel(wiphy, nla_get_u32(tb));
1001 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
1002 return NULL;
1003 return chan;
1004}
1005
Johannes Berg7527a782011-05-13 10:58:57 +02001006static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
1007{
1008 struct nlattr *nl_modes = nla_nest_start(msg, attr);
1009 int i;
1010
1011 if (!nl_modes)
1012 goto nla_put_failure;
1013
1014 i = 0;
1015 while (ifmodes) {
David S. Miller9360ffd2012-03-29 04:41:26 -04001016 if ((ifmodes & 1) && nla_put_flag(msg, i))
1017 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001018 ifmodes >>= 1;
1019 i++;
1020 }
1021
1022 nla_nest_end(msg, nl_modes);
1023 return 0;
1024
1025nla_put_failure:
1026 return -ENOBUFS;
1027}
1028
1029static int nl80211_put_iface_combinations(struct wiphy *wiphy,
Johannes Bergcdc89b92013-02-18 23:54:36 +01001030 struct sk_buff *msg,
1031 bool large)
Johannes Berg7527a782011-05-13 10:58:57 +02001032{
1033 struct nlattr *nl_combis;
1034 int i, j;
1035
1036 nl_combis = nla_nest_start(msg,
1037 NL80211_ATTR_INTERFACE_COMBINATIONS);
1038 if (!nl_combis)
1039 goto nla_put_failure;
1040
1041 for (i = 0; i < wiphy->n_iface_combinations; i++) {
1042 const struct ieee80211_iface_combination *c;
1043 struct nlattr *nl_combi, *nl_limits;
1044
1045 c = &wiphy->iface_combinations[i];
1046
1047 nl_combi = nla_nest_start(msg, i + 1);
1048 if (!nl_combi)
1049 goto nla_put_failure;
1050
1051 nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS);
1052 if (!nl_limits)
1053 goto nla_put_failure;
1054
1055 for (j = 0; j < c->n_limits; j++) {
1056 struct nlattr *nl_limit;
1057
1058 nl_limit = nla_nest_start(msg, j + 1);
1059 if (!nl_limit)
1060 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04001061 if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
1062 c->limits[j].max))
1063 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001064 if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
1065 c->limits[j].types))
1066 goto nla_put_failure;
1067 nla_nest_end(msg, nl_limit);
1068 }
1069
1070 nla_nest_end(msg, nl_limits);
1071
David S. Miller9360ffd2012-03-29 04:41:26 -04001072 if (c->beacon_int_infra_match &&
1073 nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
1074 goto nla_put_failure;
1075 if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
1076 c->num_different_channels) ||
1077 nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
1078 c->max_interfaces))
1079 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +01001080 if (large &&
Felix Fietkau8c48b502014-05-05 11:48:40 +02001081 (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
1082 c->radar_detect_widths) ||
1083 nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
1084 c->radar_detect_regions)))
Johannes Bergcdc89b92013-02-18 23:54:36 +01001085 goto nla_put_failure;
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05301086 if (c->beacon_int_min_gcd &&
1087 nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
1088 c->beacon_int_min_gcd))
1089 goto nla_put_failure;
Johannes Berg7527a782011-05-13 10:58:57 +02001090
1091 nla_nest_end(msg, nl_combi);
1092 }
1093
1094 nla_nest_end(msg, nl_combis);
1095
1096 return 0;
1097nla_put_failure:
1098 return -ENOBUFS;
1099}
1100
Johannes Berg3713b4e2013-02-14 16:19:38 +01001101#ifdef CONFIG_PM
Johannes Bergb56cf722013-02-20 01:02:38 +01001102static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
1103 struct sk_buff *msg)
1104{
Johannes Berg964dc9e2013-06-03 17:25:34 +02001105 const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
Johannes Bergb56cf722013-02-20 01:02:38 +01001106 struct nlattr *nl_tcp;
1107
1108 if (!tcp)
1109 return 0;
1110
1111 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
1112 if (!nl_tcp)
1113 return -ENOBUFS;
1114
1115 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1116 tcp->data_payload_max))
1117 return -ENOBUFS;
1118
1119 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
1120 tcp->data_payload_max))
1121 return -ENOBUFS;
1122
1123 if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
1124 return -ENOBUFS;
1125
1126 if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
1127 sizeof(*tcp->tok), tcp->tok))
1128 return -ENOBUFS;
1129
1130 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
1131 tcp->data_interval_max))
1132 return -ENOBUFS;
1133
1134 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
1135 tcp->wake_payload_max))
1136 return -ENOBUFS;
1137
1138 nla_nest_end(msg, nl_tcp);
1139 return 0;
1140}
1141
Johannes Berg3713b4e2013-02-14 16:19:38 +01001142static int nl80211_send_wowlan(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001143 struct cfg80211_registered_device *rdev,
Johannes Bergb56cf722013-02-20 01:02:38 +01001144 bool large)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001145{
1146 struct nlattr *nl_wowlan;
1147
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001148 if (!rdev->wiphy.wowlan)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001149 return 0;
1150
1151 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
1152 if (!nl_wowlan)
1153 return -ENOBUFS;
1154
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001155 if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001156 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001157 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001158 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001159 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001160 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001161 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001162 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001163 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001164 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001165 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001166 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001167 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001168 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001169 ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001170 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
1171 return -ENOBUFS;
1172
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001173 if (rdev->wiphy.wowlan->n_patterns) {
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07001174 struct nl80211_pattern_support pat = {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001175 .max_patterns = rdev->wiphy.wowlan->n_patterns,
1176 .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
1177 .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
1178 .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001179 };
1180
1181 if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
1182 sizeof(pat), &pat))
1183 return -ENOBUFS;
1184 }
1185
Luciano Coelho75453cc2015-01-09 14:06:37 +02001186 if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
1187 nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
1188 rdev->wiphy.wowlan->max_nd_match_sets))
1189 return -ENOBUFS;
1190
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001191 if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
Johannes Bergb56cf722013-02-20 01:02:38 +01001192 return -ENOBUFS;
1193
Johannes Berg3713b4e2013-02-14 16:19:38 +01001194 nla_nest_end(msg, nl_wowlan);
1195
1196 return 0;
1197}
1198#endif
1199
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001200static int nl80211_send_coalesce(struct sk_buff *msg,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001201 struct cfg80211_registered_device *rdev)
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001202{
1203 struct nl80211_coalesce_rule_support rule;
1204
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001205 if (!rdev->wiphy.coalesce)
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001206 return 0;
1207
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001208 rule.max_rules = rdev->wiphy.coalesce->n_rules;
1209 rule.max_delay = rdev->wiphy.coalesce->max_delay;
1210 rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
1211 rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
1212 rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
1213 rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001214
1215 if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
1216 return -ENOBUFS;
1217
1218 return 0;
1219}
1220
Johannes Berg3713b4e2013-02-14 16:19:38 +01001221static int nl80211_send_band_rateinfo(struct sk_buff *msg,
1222 struct ieee80211_supported_band *sband)
1223{
1224 struct nlattr *nl_rates, *nl_rate;
1225 struct ieee80211_rate *rate;
1226 int i;
1227
1228 /* add HT info */
1229 if (sband->ht_cap.ht_supported &&
1230 (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
1231 sizeof(sband->ht_cap.mcs),
1232 &sband->ht_cap.mcs) ||
1233 nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
1234 sband->ht_cap.cap) ||
1235 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
1236 sband->ht_cap.ampdu_factor) ||
1237 nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
1238 sband->ht_cap.ampdu_density)))
1239 return -ENOBUFS;
1240
1241 /* add VHT info */
1242 if (sband->vht_cap.vht_supported &&
1243 (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
1244 sizeof(sband->vht_cap.vht_mcs),
1245 &sband->vht_cap.vht_mcs) ||
1246 nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
1247 sband->vht_cap.cap)))
1248 return -ENOBUFS;
1249
1250 /* add bitrates */
1251 nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
1252 if (!nl_rates)
1253 return -ENOBUFS;
1254
1255 for (i = 0; i < sband->n_bitrates; i++) {
1256 nl_rate = nla_nest_start(msg, i);
1257 if (!nl_rate)
1258 return -ENOBUFS;
1259
1260 rate = &sband->bitrates[i];
1261 if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
1262 rate->bitrate))
1263 return -ENOBUFS;
1264 if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
1265 nla_put_flag(msg,
1266 NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
1267 return -ENOBUFS;
1268
1269 nla_nest_end(msg, nl_rate);
1270 }
1271
1272 nla_nest_end(msg, nl_rates);
1273
1274 return 0;
1275}
1276
1277static int
1278nl80211_send_mgmt_stypes(struct sk_buff *msg,
1279 const struct ieee80211_txrx_stypes *mgmt_stypes)
1280{
1281 u16 stypes;
1282 struct nlattr *nl_ftypes, *nl_ifs;
1283 enum nl80211_iftype ift;
1284 int i;
1285
1286 if (!mgmt_stypes)
1287 return 0;
1288
1289 nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
1290 if (!nl_ifs)
1291 return -ENOBUFS;
1292
1293 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1294 nl_ftypes = nla_nest_start(msg, ift);
1295 if (!nl_ftypes)
1296 return -ENOBUFS;
1297 i = 0;
1298 stypes = mgmt_stypes[ift].tx;
1299 while (stypes) {
1300 if ((stypes & 1) &&
1301 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1302 (i << 4) | IEEE80211_FTYPE_MGMT))
1303 return -ENOBUFS;
1304 stypes >>= 1;
1305 i++;
1306 }
1307 nla_nest_end(msg, nl_ftypes);
1308 }
1309
1310 nla_nest_end(msg, nl_ifs);
1311
1312 nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
1313 if (!nl_ifs)
1314 return -ENOBUFS;
1315
1316 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1317 nl_ftypes = nla_nest_start(msg, ift);
1318 if (!nl_ftypes)
1319 return -ENOBUFS;
1320 i = 0;
1321 stypes = mgmt_stypes[ift].rx;
1322 while (stypes) {
1323 if ((stypes & 1) &&
1324 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1325 (i << 4) | IEEE80211_FTYPE_MGMT))
1326 return -ENOBUFS;
1327 stypes >>= 1;
1328 i++;
1329 }
1330 nla_nest_end(msg, nl_ftypes);
1331 }
1332 nla_nest_end(msg, nl_ifs);
1333
1334 return 0;
1335}
1336
Johannes Berg17948992016-10-26 11:42:04 +02001337#define CMD(op, n) \
1338 do { \
1339 if (rdev->ops->op) { \
1340 i++; \
1341 if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
1342 goto nla_put_failure; \
1343 } \
1344 } while (0)
1345
1346static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
1347 struct sk_buff *msg)
1348{
1349 int i = 0;
1350
1351 /*
1352 * do *NOT* add anything into this function, new things need to be
1353 * advertised only to new versions of userspace that can deal with
1354 * the split (and they can't possibly care about new features...
1355 */
1356 CMD(add_virtual_intf, NEW_INTERFACE);
1357 CMD(change_virtual_intf, SET_INTERFACE);
1358 CMD(add_key, NEW_KEY);
1359 CMD(start_ap, START_AP);
1360 CMD(add_station, NEW_STATION);
1361 CMD(add_mpath, NEW_MPATH);
1362 CMD(update_mesh_config, SET_MESH_CONFIG);
1363 CMD(change_bss, SET_BSS);
1364 CMD(auth, AUTHENTICATE);
1365 CMD(assoc, ASSOCIATE);
1366 CMD(deauth, DEAUTHENTICATE);
1367 CMD(disassoc, DISASSOCIATE);
1368 CMD(join_ibss, JOIN_IBSS);
1369 CMD(join_mesh, JOIN_MESH);
1370 CMD(set_pmksa, SET_PMKSA);
1371 CMD(del_pmksa, DEL_PMKSA);
1372 CMD(flush_pmksa, FLUSH_PMKSA);
1373 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
1374 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
1375 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
1376 CMD(mgmt_tx, FRAME);
1377 CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
1378 if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
1379 i++;
1380 if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
1381 goto nla_put_failure;
1382 }
1383 if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
1384 rdev->ops->join_mesh) {
1385 i++;
1386 if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
1387 goto nla_put_failure;
1388 }
1389 CMD(set_wds_peer, SET_WDS_PEER);
1390 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
1391 CMD(tdls_mgmt, TDLS_MGMT);
1392 CMD(tdls_oper, TDLS_OPER);
1393 }
1394 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
1395 CMD(sched_scan_start, START_SCHED_SCAN);
1396 CMD(probe_client, PROBE_CLIENT);
1397 CMD(set_noack_map, SET_NOACK_MAP);
1398 if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
1399 i++;
1400 if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1401 goto nla_put_failure;
1402 }
1403 CMD(start_p2p_device, START_P2P_DEVICE);
1404 CMD(set_mcast_rate, SET_MCAST_RATE);
1405#ifdef CONFIG_NL80211_TESTMODE
1406 CMD(testmode_cmd, TESTMODE);
1407#endif
1408
1409 if (rdev->ops->connect || rdev->ops->auth) {
1410 i++;
1411 if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
1412 goto nla_put_failure;
1413 }
1414
1415 if (rdev->ops->disconnect || rdev->ops->deauth) {
1416 i++;
1417 if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
1418 goto nla_put_failure;
1419 }
1420
1421 return i;
1422 nla_put_failure:
1423 return -ENOBUFS;
1424}
1425
Johannes Berg86e8cf92013-06-19 10:57:22 +02001426struct nl80211_dump_wiphy_state {
1427 s64 filter_wiphy;
1428 long start;
Kanchanapally, Vidyullatha019ae3a2016-05-16 10:41:04 +05301429 long split_start, band_start, chan_start, capa_start;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001430 bool split;
1431};
1432
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001433static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
Johannes Berg3bb20552014-05-26 13:52:25 +02001434 enum nl80211_commands cmd,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001435 struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001436 int flags, struct nl80211_dump_wiphy_state *state)
Johannes Berg55682962007-09-20 13:09:35 -04001437{
1438 void *hdr;
Johannes Bergee688b002008-01-24 19:38:39 +01001439 struct nlattr *nl_bands, *nl_band;
1440 struct nlattr *nl_freqs, *nl_freq;
Johannes Berg8fdc6212009-03-14 09:34:01 +01001441 struct nlattr *nl_cmds;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001442 enum nl80211_band band;
Johannes Bergee688b002008-01-24 19:38:39 +01001443 struct ieee80211_channel *chan;
Johannes Bergee688b002008-01-24 19:38:39 +01001444 int i;
Johannes Berg2e161f72010-08-12 15:38:38 +02001445 const struct ieee80211_txrx_stypes *mgmt_stypes =
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001446 rdev->wiphy.mgmt_stypes;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001447 u32 features;
Johannes Berg55682962007-09-20 13:09:35 -04001448
Johannes Berg3bb20552014-05-26 13:52:25 +02001449 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04001450 if (!hdr)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001451 return -ENOBUFS;
1452
Johannes Berg86e8cf92013-06-19 10:57:22 +02001453 if (WARN_ON(!state))
1454 return -EINVAL;
Johannes Berg55682962007-09-20 13:09:35 -04001455
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001456 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001457 nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001458 wiphy_name(&rdev->wiphy)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04001459 nla_put_u32(msg, NL80211_ATTR_GENERATION,
Johannes Berg3713b4e2013-02-14 16:19:38 +01001460 cfg80211_rdev_list_generation))
David S. Miller9360ffd2012-03-29 04:41:26 -04001461 goto nla_put_failure;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02001462
Johannes Berg3bb20552014-05-26 13:52:25 +02001463 if (cmd != NL80211_CMD_NEW_WIPHY)
1464 goto finish;
1465
Johannes Berg86e8cf92013-06-19 10:57:22 +02001466 switch (state->split_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001467 case 0:
1468 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001469 rdev->wiphy.retry_short) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001470 nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001471 rdev->wiphy.retry_long) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001472 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001473 rdev->wiphy.frag_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001474 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001475 rdev->wiphy.rts_threshold) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001476 nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001477 rdev->wiphy.coverage_class) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001478 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001479 rdev->wiphy.max_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001480 nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001481 rdev->wiphy.max_sched_scan_ssids) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001482 nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001483 rdev->wiphy.max_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001484 nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001485 rdev->wiphy.max_sched_scan_ie_len) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001486 nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
Avraham Stern3b06d272015-10-12 09:51:34 +03001487 rdev->wiphy.max_match_sets) ||
1488 nla_put_u32(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
1489 rdev->wiphy.max_sched_scan_plans) ||
1490 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
1491 rdev->wiphy.max_sched_scan_plan_interval) ||
1492 nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
1493 rdev->wiphy.max_sched_scan_plan_iterations))
Johannes Bergee688b002008-01-24 19:38:39 +01001494 goto nla_put_failure;
1495
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001496 if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001497 nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
1498 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001499 if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001500 nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
1501 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001502 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001503 nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
1504 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001505 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001506 nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
1507 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001508 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001509 nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
1510 goto nla_put_failure;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001511 if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001512 nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
David S. Miller9360ffd2012-03-29 04:41:26 -04001513 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001514 state->split_start++;
1515 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001516 break;
1517 case 1:
1518 if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001519 sizeof(u32) * rdev->wiphy.n_cipher_suites,
1520 rdev->wiphy.cipher_suites))
Mahesh Palivelabf0c111e2012-06-22 07:27:46 +00001521 goto nla_put_failure;
1522
Johannes Berg3713b4e2013-02-14 16:19:38 +01001523 if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001524 rdev->wiphy.max_num_pmkids))
Johannes Bergee688b002008-01-24 19:38:39 +01001525 goto nla_put_failure;
1526
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001527 if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001528 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
1529 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001530
Johannes Berg3713b4e2013-02-14 16:19:38 +01001531 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001532 rdev->wiphy.available_antennas_tx) ||
Johannes Berg3713b4e2013-02-14 16:19:38 +01001533 nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001534 rdev->wiphy.available_antennas_rx))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001535 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001536
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001537 if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001538 nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001539 rdev->wiphy.probe_resp_offload))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001540 goto nla_put_failure;
Jouni Malinene2f367f262008-11-21 19:01:30 +02001541
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001542 if ((rdev->wiphy.available_antennas_tx ||
1543 rdev->wiphy.available_antennas_rx) &&
1544 rdev->ops->get_antenna) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001545 u32 tx_ant = 0, rx_ant = 0;
1546 int res;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07001547
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001548 res = rdev_get_antenna(rdev, &tx_ant, &rx_ant);
Johannes Berg3713b4e2013-02-14 16:19:38 +01001549 if (!res) {
1550 if (nla_put_u32(msg,
1551 NL80211_ATTR_WIPHY_ANTENNA_TX,
1552 tx_ant) ||
1553 nla_put_u32(msg,
1554 NL80211_ATTR_WIPHY_ANTENNA_RX,
1555 rx_ant))
1556 goto nla_put_failure;
1557 }
Johannes Bergee688b002008-01-24 19:38:39 +01001558 }
1559
Johannes Berg86e8cf92013-06-19 10:57:22 +02001560 state->split_start++;
1561 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001562 break;
1563 case 2:
1564 if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001565 rdev->wiphy.interface_modes))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001566 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001567 state->split_start++;
1568 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001569 break;
1570 case 3:
1571 nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
1572 if (!nl_bands)
Johannes Bergee688b002008-01-24 19:38:39 +01001573 goto nla_put_failure;
1574
Johannes Berg86e8cf92013-06-19 10:57:22 +02001575 for (band = state->band_start;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001576 band < NUM_NL80211_BANDS; band++) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001577 struct ieee80211_supported_band *sband;
1578
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001579 sband = rdev->wiphy.bands[band];
Johannes Berg3713b4e2013-02-14 16:19:38 +01001580
1581 if (!sband)
1582 continue;
1583
1584 nl_band = nla_nest_start(msg, band);
1585 if (!nl_band)
Johannes Bergee688b002008-01-24 19:38:39 +01001586 goto nla_put_failure;
1587
Johannes Berg86e8cf92013-06-19 10:57:22 +02001588 switch (state->chan_start) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001589 case 0:
1590 if (nl80211_send_band_rateinfo(msg, sband))
1591 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001592 state->chan_start++;
1593 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001594 break;
1595 default:
1596 /* add frequencies */
1597 nl_freqs = nla_nest_start(
1598 msg, NL80211_BAND_ATTR_FREQS);
1599 if (!nl_freqs)
1600 goto nla_put_failure;
Johannes Bergee688b002008-01-24 19:38:39 +01001601
Johannes Berg86e8cf92013-06-19 10:57:22 +02001602 for (i = state->chan_start - 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001603 i < sband->n_channels;
1604 i++) {
1605 nl_freq = nla_nest_start(msg, i);
1606 if (!nl_freq)
1607 goto nla_put_failure;
1608
1609 chan = &sband->channels[i];
1610
Johannes Berg86e8cf92013-06-19 10:57:22 +02001611 if (nl80211_msg_put_channel(
1612 msg, chan,
1613 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001614 goto nla_put_failure;
1615
1616 nla_nest_end(msg, nl_freq);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001617 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001618 break;
1619 }
1620 if (i < sband->n_channels)
Johannes Berg86e8cf92013-06-19 10:57:22 +02001621 state->chan_start = i + 2;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001622 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001623 state->chan_start = 0;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001624 nla_nest_end(msg, nl_freqs);
1625 }
1626
1627 nla_nest_end(msg, nl_band);
1628
Johannes Berg86e8cf92013-06-19 10:57:22 +02001629 if (state->split) {
Johannes Berg3713b4e2013-02-14 16:19:38 +01001630 /* start again here */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001631 if (state->chan_start)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001632 band--;
1633 break;
1634 }
Johannes Bergee688b002008-01-24 19:38:39 +01001635 }
Johannes Berg3713b4e2013-02-14 16:19:38 +01001636 nla_nest_end(msg, nl_bands);
Johannes Bergee688b002008-01-24 19:38:39 +01001637
Johannes Berg57fbcce2016-04-12 15:56:15 +02001638 if (band < NUM_NL80211_BANDS)
Johannes Berg86e8cf92013-06-19 10:57:22 +02001639 state->band_start = band + 1;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001640 else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001641 state->band_start = 0;
Johannes Bergee688b002008-01-24 19:38:39 +01001642
Johannes Berg3713b4e2013-02-14 16:19:38 +01001643 /* if bands & channels are done, continue outside */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001644 if (state->band_start == 0 && state->chan_start == 0)
1645 state->split_start++;
1646 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001647 break;
1648 case 4:
1649 nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
1650 if (!nl_cmds)
David S. Miller9360ffd2012-03-29 04:41:26 -04001651 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001652
Johannes Berg17948992016-10-26 11:42:04 +02001653 i = nl80211_add_commands_unsplit(rdev, msg);
1654 if (i < 0)
1655 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001656 if (state->split) {
Arend van Spriel5de17982013-04-18 15:49:00 +02001657 CMD(crit_proto_start, CRIT_PROTOCOL_START);
1658 CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001659 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02001660 CMD(channel_switch, CHANNEL_SWITCH);
Johannes Berg02df00e2014-06-10 14:06:25 +02001661 CMD(set_qos_map, SET_QOS_MAP);
Johannes Berg723e73a2014-10-22 09:25:06 +02001662 if (rdev->wiphy.features &
1663 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
Johannes Berg960d01a2014-09-09 22:55:35 +03001664 CMD(add_tx_ts, ADD_TX_TS);
Michael Braunce0ce132016-10-10 19:12:22 +02001665 CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
vamsi krishna088e8df2016-10-27 16:51:11 +03001666 CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
Arend van Spriel5de17982013-04-18 15:49:00 +02001667 }
Johannes Berg8fdc6212009-03-14 09:34:01 +01001668#undef CMD
Samuel Ortizb23aa672009-07-01 21:26:54 +02001669
Johannes Berg3713b4e2013-02-14 16:19:38 +01001670 nla_nest_end(msg, nl_cmds);
Johannes Berg86e8cf92013-06-19 10:57:22 +02001671 state->split_start++;
1672 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001673 break;
1674 case 5:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001675 if (rdev->ops->remain_on_channel &&
1676 (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001677 nla_put_u32(msg,
1678 NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001679 rdev->wiphy.max_remain_on_channel_duration))
Johannes Berg2e161f72010-08-12 15:38:38 +02001680 goto nla_put_failure;
1681
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001682 if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001683 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
1684 goto nla_put_failure;
Johannes Berg2e161f72010-08-12 15:38:38 +02001685
Johannes Berg3713b4e2013-02-14 16:19:38 +01001686 if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
1687 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001688 state->split_start++;
1689 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001690 break;
1691 case 6:
Johannes Bergdfb89c52012-06-27 09:23:48 +02001692#ifdef CONFIG_PM
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001693 if (nl80211_send_wowlan(msg, rdev, state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001694 goto nla_put_failure;
Johannes Berg86e8cf92013-06-19 10:57:22 +02001695 state->split_start++;
1696 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001697 break;
1698#else
Johannes Berg86e8cf92013-06-19 10:57:22 +02001699 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001700#endif
1701 case 7:
1702 if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001703 rdev->wiphy.software_iftypes))
Johannes Bergff1b6e62011-05-04 15:37:28 +02001704 goto nla_put_failure;
1705
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001706 if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
Johannes Berg86e8cf92013-06-19 10:57:22 +02001707 state->split))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001708 goto nla_put_failure;
Johannes Bergff1b6e62011-05-04 15:37:28 +02001709
Johannes Berg86e8cf92013-06-19 10:57:22 +02001710 state->split_start++;
1711 if (state->split)
Johannes Berg3713b4e2013-02-14 16:19:38 +01001712 break;
1713 case 8:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001714 if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001715 nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001716 rdev->wiphy.ap_sme_capa))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001717 goto nla_put_failure;
1718
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001719 features = rdev->wiphy.features;
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001720 /*
1721 * We can only add the per-channel limit information if the
1722 * dump is split, otherwise it makes it too big. Therefore
1723 * only advertise it in that case.
1724 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001725 if (state->split)
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001726 features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
1727 if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001728 goto nla_put_failure;
1729
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001730 if (rdev->wiphy.ht_capa_mod_mask &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001731 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001732 sizeof(*rdev->wiphy.ht_capa_mod_mask),
1733 rdev->wiphy.ht_capa_mod_mask))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001734 goto nla_put_failure;
1735
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001736 if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
1737 rdev->wiphy.max_acl_mac_addrs &&
Johannes Berg3713b4e2013-02-14 16:19:38 +01001738 nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001739 rdev->wiphy.max_acl_mac_addrs))
Johannes Berg3713b4e2013-02-14 16:19:38 +01001740 goto nla_put_failure;
1741
1742 /*
1743 * Any information below this point is only available to
1744 * applications that can deal with it being split. This
1745 * helps ensure that newly added capabilities don't break
1746 * older tools by overrunning their buffers.
1747 *
1748 * We still increment split_start so that in the split
1749 * case we'll continue with more data in the next round,
1750 * but break unconditionally so unsplit data stops here.
1751 */
Johannes Berg86e8cf92013-06-19 10:57:22 +02001752 state->split_start++;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001753 break;
1754 case 9:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001755 if (rdev->wiphy.extended_capabilities &&
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001756 (nla_put(msg, NL80211_ATTR_EXT_CAPA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001757 rdev->wiphy.extended_capabilities_len,
1758 rdev->wiphy.extended_capabilities) ||
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001759 nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001760 rdev->wiphy.extended_capabilities_len,
1761 rdev->wiphy.extended_capabilities_mask)))
Johannes Bergfe1abaf2013-02-27 15:39:45 +01001762 goto nla_put_failure;
Johannes Berg3713b4e2013-02-14 16:19:38 +01001763
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001764 if (rdev->wiphy.vht_capa_mod_mask &&
Johannes Bergee2aca32013-02-21 17:36:01 +01001765 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001766 sizeof(*rdev->wiphy.vht_capa_mod_mask),
1767 rdev->wiphy.vht_capa_mod_mask))
Johannes Bergee2aca32013-02-21 17:36:01 +01001768 goto nla_put_failure;
1769
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001770 state->split_start++;
1771 break;
1772 case 10:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001773 if (nl80211_send_coalesce(msg, rdev))
Amitkumar Karwarbe29b992013-06-28 11:51:26 -07001774 goto nla_put_failure;
1775
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001776 if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
Felix Fietkau01e0daa2013-11-09 14:57:54 +01001777 (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
1778 nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
1779 goto nla_put_failure;
Jouni Malinenb43504c2014-01-15 00:01:08 +02001780
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001781 if (rdev->wiphy.max_ap_assoc_sta &&
Jouni Malinenb43504c2014-01-15 00:01:08 +02001782 nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001783 rdev->wiphy.max_ap_assoc_sta))
Jouni Malinenb43504c2014-01-15 00:01:08 +02001784 goto nla_put_failure;
1785
Johannes Bergad7e7182013-11-13 13:37:47 +01001786 state->split_start++;
1787 break;
1788 case 11:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001789 if (rdev->wiphy.n_vendor_commands) {
Johannes Berg567ffc32013-12-18 14:43:31 +01001790 const struct nl80211_vendor_cmd_info *info;
1791 struct nlattr *nested;
Johannes Bergad7e7182013-11-13 13:37:47 +01001792
Johannes Berg567ffc32013-12-18 14:43:31 +01001793 nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
1794 if (!nested)
Johannes Bergad7e7182013-11-13 13:37:47 +01001795 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01001796
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001797 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
1798 info = &rdev->wiphy.vendor_commands[i].info;
Johannes Berg567ffc32013-12-18 14:43:31 +01001799 if (nla_put(msg, i + 1, sizeof(*info), info))
1800 goto nla_put_failure;
1801 }
1802 nla_nest_end(msg, nested);
1803 }
1804
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001805 if (rdev->wiphy.n_vendor_events) {
Johannes Berg567ffc32013-12-18 14:43:31 +01001806 const struct nl80211_vendor_cmd_info *info;
1807 struct nlattr *nested;
1808
1809 nested = nla_nest_start(msg,
1810 NL80211_ATTR_VENDOR_EVENTS);
1811 if (!nested)
1812 goto nla_put_failure;
1813
Zhao, Gang1b8ec872014-04-21 12:53:02 +08001814 for (i = 0; i < rdev->wiphy.n_vendor_events; i++) {
1815 info = &rdev->wiphy.vendor_events[i];
Johannes Berg567ffc32013-12-18 14:43:31 +01001816 if (nla_put(msg, i + 1, sizeof(*info), info))
1817 goto nla_put_failure;
1818 }
1819 nla_nest_end(msg, nested);
1820 }
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03001821 state->split_start++;
1822 break;
1823 case 12:
1824 if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
1825 nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
1826 rdev->wiphy.max_num_csa_counters))
1827 goto nla_put_failure;
Felix Fietkau01e0daa2013-11-09 14:57:54 +01001828
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02001829 if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
1830 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
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 Berg86e8cf92013-06-19 10:57:22 +02001920 int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
1921 tb, nl80211_fam.maxattr, nl80211_policy);
1922 /* 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);
2133 break;
2134 default:
Johannes Berg683b6d32012-11-08 21:25:48 +01002135 return -EINVAL;
Johannes Berg683b6d32012-11-08 21:25:48 +01002136 }
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002137 } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
2138 chandef->width =
2139 nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
2140 if (info->attrs[NL80211_ATTR_CENTER_FREQ1])
2141 chandef->center_freq1 =
2142 nla_get_u32(
2143 info->attrs[NL80211_ATTR_CENTER_FREQ1]);
2144 if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
2145 chandef->center_freq2 =
2146 nla_get_u32(
2147 info->attrs[NL80211_ATTR_CENTER_FREQ2]);
2148 }
2149
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002150 if (!cfg80211_chandef_valid(chandef))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002151 return -EINVAL;
2152
Johannes Berg9f5e8f62012-11-22 16:59:45 +01002153 if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
2154 IEEE80211_CHAN_DISABLED))
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002155 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002156
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02002157 if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
2158 chandef->width == NL80211_CHAN_WIDTH_10) &&
2159 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
2160 return -EINVAL;
2161
Johannes Berg683b6d32012-11-08 21:25:48 +01002162 return 0;
2163}
2164
Johannes Bergf444de02010-05-05 15:25:02 +02002165static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
Jouni Malinene16821b2014-04-28 11:22:08 +03002166 struct net_device *dev,
Johannes Bergf444de02010-05-05 15:25:02 +02002167 struct genl_info *info)
2168{
Johannes Berg683b6d32012-11-08 21:25:48 +01002169 struct cfg80211_chan_def chandef;
Johannes Bergf444de02010-05-05 15:25:02 +02002170 int result;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002171 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
Jouni Malinene16821b2014-04-28 11:22:08 +03002172 struct wireless_dev *wdev = NULL;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002173
Jouni Malinene16821b2014-04-28 11:22:08 +03002174 if (dev)
2175 wdev = dev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002176 if (!nl80211_can_set_dev_channel(wdev))
2177 return -EOPNOTSUPP;
Jouni Malinene16821b2014-04-28 11:22:08 +03002178 if (wdev)
2179 iftype = wdev->iftype;
Johannes Bergf444de02010-05-05 15:25:02 +02002180
Johannes Berg683b6d32012-11-08 21:25:48 +01002181 result = nl80211_parse_chandef(rdev, info, &chandef);
2182 if (result)
2183 return result;
Johannes Bergf444de02010-05-05 15:25:02 +02002184
Johannes Berge8c9bd52012-06-06 08:18:22 +02002185 switch (iftype) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002186 case NL80211_IFTYPE_AP:
2187 case NL80211_IFTYPE_P2P_GO:
Arik Nemtsov923b3522015-07-08 15:41:44 +03002188 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
2189 iftype)) {
Johannes Bergaa430da2012-05-16 23:50:18 +02002190 result = -EINVAL;
2191 break;
2192 }
Jouni Malinene16821b2014-04-28 11:22:08 +03002193 if (wdev->beacon_interval) {
2194 if (!dev || !rdev->ops->set_ap_chanwidth ||
2195 !(rdev->wiphy.features &
2196 NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
2197 result = -EBUSY;
2198 break;
2199 }
2200
2201 /* Only allow dynamic channel width changes */
2202 if (chandef.chan != wdev->preset_chandef.chan) {
2203 result = -EBUSY;
2204 break;
2205 }
2206 result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
2207 if (result)
2208 break;
2209 }
Johannes Berg683b6d32012-11-08 21:25:48 +01002210 wdev->preset_chandef = chandef;
Johannes Bergaa430da2012-05-16 23:50:18 +02002211 result = 0;
2212 break;
Johannes Bergcc1d2802012-05-16 23:50:20 +02002213 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg683b6d32012-11-08 21:25:48 +01002214 result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
Johannes Bergcc1d2802012-05-16 23:50:20 +02002215 break;
Johannes Berge8c9bd52012-06-06 08:18:22 +02002216 case NL80211_IFTYPE_MONITOR:
Johannes Berg683b6d32012-11-08 21:25:48 +01002217 result = cfg80211_set_monitor_channel(rdev, &chandef);
Johannes Berge8c9bd52012-06-06 08:18:22 +02002218 break;
Johannes Bergaa430da2012-05-16 23:50:18 +02002219 default:
Johannes Berge8c9bd52012-06-06 08:18:22 +02002220 result = -EINVAL;
Johannes Bergf444de02010-05-05 15:25:02 +02002221 }
Johannes Bergf444de02010-05-05 15:25:02 +02002222
2223 return result;
2224}
2225
2226static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
2227{
Johannes Berg4c476992010-10-04 21:36:35 +02002228 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2229 struct net_device *netdev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02002230
Jouni Malinene16821b2014-04-28 11:22:08 +03002231 return __nl80211_set_channel(rdev, netdev, info);
Johannes Bergf444de02010-05-05 15:25:02 +02002232}
2233
Bill Jordane8347eb2010-10-01 13:54:28 -04002234static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
2235{
Johannes Berg43b19952010-10-07 13:10:30 +02002236 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2237 struct net_device *dev = info->user_ptr[1];
2238 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg388ac772010-10-07 13:11:09 +02002239 const u8 *bssid;
Bill Jordane8347eb2010-10-01 13:54:28 -04002240
2241 if (!info->attrs[NL80211_ATTR_MAC])
2242 return -EINVAL;
2243
Johannes Berg43b19952010-10-07 13:10:30 +02002244 if (netif_running(dev))
2245 return -EBUSY;
Bill Jordane8347eb2010-10-01 13:54:28 -04002246
Johannes Berg43b19952010-10-07 13:10:30 +02002247 if (!rdev->ops->set_wds_peer)
2248 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002249
Johannes Berg43b19952010-10-07 13:10:30 +02002250 if (wdev->iftype != NL80211_IFTYPE_WDS)
2251 return -EOPNOTSUPP;
Bill Jordane8347eb2010-10-01 13:54:28 -04002252
2253 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Hila Gonene35e4d22012-06-27 17:19:42 +03002254 return rdev_set_wds_peer(rdev, dev, bssid);
Bill Jordane8347eb2010-10-01 13:54:28 -04002255}
2256
Johannes Berg55682962007-09-20 13:09:35 -04002257static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
2258{
2259 struct cfg80211_registered_device *rdev;
Johannes Bergf444de02010-05-05 15:25:02 +02002260 struct net_device *netdev = NULL;
2261 struct wireless_dev *wdev;
Bill Jordana1e567c2010-09-10 11:22:32 -04002262 int result = 0, rem_txq_params = 0;
Jouni Malinen31888482008-10-30 16:59:24 +02002263 struct nlattr *nl_txq_params;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002264 u32 changed;
2265 u8 retry_short = 0, retry_long = 0;
2266 u32 frag_threshold = 0, rts_threshold = 0;
Lukáš Turek81077e82009-12-21 22:50:47 +01002267 u8 coverage_class = 0;
Johannes Berg55682962007-09-20 13:09:35 -04002268
Johannes Berg5fe231e2013-05-08 21:45:15 +02002269 ASSERT_RTNL();
2270
Johannes Bergf444de02010-05-05 15:25:02 +02002271 /*
2272 * Try to find the wiphy and netdev. Normally this
2273 * function shouldn't need the netdev, but this is
2274 * done for backward compatibility -- previously
2275 * setting the channel was done per wiphy, but now
2276 * it is per netdev. Previous userland like hostapd
2277 * also passed a netdev to set_wiphy, so that it is
2278 * possible to let that go to the right netdev!
2279 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002280
Johannes Bergf444de02010-05-05 15:25:02 +02002281 if (info->attrs[NL80211_ATTR_IFINDEX]) {
2282 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
2283
Ying Xue7f2b8562014-01-15 10:23:45 +08002284 netdev = __dev_get_by_index(genl_info_net(info), ifindex);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002285 if (netdev && netdev->ieee80211_ptr)
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002286 rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002287 else
Johannes Bergf444de02010-05-05 15:25:02 +02002288 netdev = NULL;
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002289 }
2290
Johannes Bergf444de02010-05-05 15:25:02 +02002291 if (!netdev) {
Johannes Berg878d9ec2012-06-15 14:18:32 +02002292 rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
2293 info->attrs);
Johannes Berg5fe231e2013-05-08 21:45:15 +02002294 if (IS_ERR(rdev))
Johannes Berg4c476992010-10-04 21:36:35 +02002295 return PTR_ERR(rdev);
Johannes Bergf444de02010-05-05 15:25:02 +02002296 wdev = NULL;
2297 netdev = NULL;
2298 result = 0;
Johannes Berg71fe96b2012-10-24 10:04:58 +02002299 } else
Johannes Bergf444de02010-05-05 15:25:02 +02002300 wdev = netdev->ieee80211_ptr;
Johannes Bergf444de02010-05-05 15:25:02 +02002301
2302 /*
2303 * end workaround code, by now the rdev is available
2304 * and locked, and wdev may or may not be NULL.
2305 */
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002306
2307 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
Jouni Malinen31888482008-10-30 16:59:24 +02002308 result = cfg80211_dev_rename(
2309 rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002310
Johannes Berg4bbf4d52009-03-24 09:35:46 +01002311 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002312 return result;
Johannes Berg55682962007-09-20 13:09:35 -04002313
Jouni Malinen31888482008-10-30 16:59:24 +02002314 if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
2315 struct ieee80211_txq_params txq_params;
2316 struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
2317
Ying Xue7f2b8562014-01-15 10:23:45 +08002318 if (!rdev->ops->set_txq_params)
2319 return -EOPNOTSUPP;
Jouni Malinen31888482008-10-30 16:59:24 +02002320
Ying Xue7f2b8562014-01-15 10:23:45 +08002321 if (!netdev)
2322 return -EINVAL;
Eliad Pellerf70f01c2011-09-25 20:06:53 +03002323
Johannes Berg133a3ff2011-11-03 14:50:13 +01002324 if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002325 netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2326 return -EINVAL;
Johannes Berg133a3ff2011-11-03 14:50:13 +01002327
Ying Xue7f2b8562014-01-15 10:23:45 +08002328 if (!netif_running(netdev))
2329 return -ENETDOWN;
Johannes Berg2b5f8b02012-04-02 10:51:55 +02002330
Jouni Malinen31888482008-10-30 16:59:24 +02002331 nla_for_each_nested(nl_txq_params,
2332 info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
2333 rem_txq_params) {
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02002334 result = nla_parse_nested(tb, NL80211_TXQ_ATTR_MAX,
2335 nl_txq_params,
2336 txq_params_policy);
Johannes Bergae811e22014-01-24 10:17:47 +01002337 if (result)
2338 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002339 result = parse_txq_params(tb, &txq_params);
2340 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002341 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002342
Hila Gonene35e4d22012-06-27 17:19:42 +03002343 result = rdev_set_txq_params(rdev, netdev,
2344 &txq_params);
Jouni Malinen31888482008-10-30 16:59:24 +02002345 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002346 return result;
Jouni Malinen31888482008-10-30 16:59:24 +02002347 }
2348 }
2349
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002350 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinene16821b2014-04-28 11:22:08 +03002351 result = __nl80211_set_channel(
2352 rdev,
2353 nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
2354 info);
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002355 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002356 return result;
Jouni Malinen72bdcf32008-11-26 16:15:24 +02002357 }
2358
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002359 if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
Johannes Bergc8442112012-10-24 10:17:18 +02002360 struct wireless_dev *txp_wdev = wdev;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002361 enum nl80211_tx_power_setting type;
2362 int idx, mbm = 0;
2363
Johannes Bergc8442112012-10-24 10:17:18 +02002364 if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
2365 txp_wdev = NULL;
2366
Ying Xue7f2b8562014-01-15 10:23:45 +08002367 if (!rdev->ops->set_tx_power)
2368 return -EOPNOTSUPP;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002369
2370 idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
2371 type = nla_get_u32(info->attrs[idx]);
2372
2373 if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
Ying Xue7f2b8562014-01-15 10:23:45 +08002374 (type != NL80211_TX_POWER_AUTOMATIC))
2375 return -EINVAL;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002376
2377 if (type != NL80211_TX_POWER_AUTOMATIC) {
2378 idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
2379 mbm = nla_get_u32(info->attrs[idx]);
2380 }
2381
Johannes Bergc8442112012-10-24 10:17:18 +02002382 result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002383 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002384 return result;
Juuso Oikarinen98d2ff82010-06-23 12:12:38 +03002385 }
2386
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002387 if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
2388 info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
2389 u32 tx_ant, rx_ant;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07002390
Bruno Randolf7f531e02010-12-16 11:30:22 +09002391 if ((!rdev->wiphy.available_antennas_tx &&
2392 !rdev->wiphy.available_antennas_rx) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002393 !rdev->ops->set_antenna)
2394 return -EOPNOTSUPP;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002395
2396 tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
2397 rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
2398
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002399 /* reject antenna configurations which don't match the
Bruno Randolf7f531e02010-12-16 11:30:22 +09002400 * available antenna masks, except for the "all" mask */
2401 if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
Ying Xue7f2b8562014-01-15 10:23:45 +08002402 (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
2403 return -EINVAL;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002404
Bruno Randolf7f531e02010-12-16 11:30:22 +09002405 tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
2406 rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
Bruno Randolfa7ffac92010-12-08 13:59:24 +09002407
Hila Gonene35e4d22012-06-27 17:19:42 +03002408 result = rdev_set_antenna(rdev, tx_ant, rx_ant);
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002409 if (result)
Ying Xue7f2b8562014-01-15 10:23:45 +08002410 return result;
Bruno Randolfafe0cbf2010-11-10 12:50:50 +09002411 }
2412
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002413 changed = 0;
2414
2415 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
2416 retry_short = nla_get_u8(
2417 info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002418 if (retry_short == 0)
2419 return -EINVAL;
2420
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002421 changed |= WIPHY_PARAM_RETRY_SHORT;
2422 }
2423
2424 if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
2425 retry_long = nla_get_u8(
2426 info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002427 if (retry_long == 0)
2428 return -EINVAL;
2429
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002430 changed |= WIPHY_PARAM_RETRY_LONG;
2431 }
2432
2433 if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
2434 frag_threshold = nla_get_u32(
2435 info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
Ying Xue7f2b8562014-01-15 10:23:45 +08002436 if (frag_threshold < 256)
2437 return -EINVAL;
2438
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002439 if (frag_threshold != (u32) -1) {
2440 /*
2441 * Fragments (apart from the last one) are required to
2442 * have even length. Make the fragmentation code
2443 * simpler by stripping LSB should someone try to use
2444 * odd threshold value.
2445 */
2446 frag_threshold &= ~0x1;
2447 }
2448 changed |= WIPHY_PARAM_FRAG_THRESHOLD;
2449 }
2450
2451 if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
2452 rts_threshold = nla_get_u32(
2453 info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
2454 changed |= WIPHY_PARAM_RTS_THRESHOLD;
2455 }
2456
Lukáš Turek81077e82009-12-21 22:50:47 +01002457 if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002458 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK])
2459 return -EINVAL;
2460
Lukáš Turek81077e82009-12-21 22:50:47 +01002461 coverage_class = nla_get_u8(
2462 info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
2463 changed |= WIPHY_PARAM_COVERAGE_CLASS;
2464 }
2465
Lorenzo Bianconi3057dbf2014-09-04 23:57:40 +02002466 if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
2467 if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION))
2468 return -EOPNOTSUPP;
2469
2470 changed |= WIPHY_PARAM_DYN_ACK;
2471 }
2472
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002473 if (changed) {
2474 u8 old_retry_short, old_retry_long;
2475 u32 old_frag_threshold, old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002476 u8 old_coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002477
Ying Xue7f2b8562014-01-15 10:23:45 +08002478 if (!rdev->ops->set_wiphy_params)
2479 return -EOPNOTSUPP;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002480
2481 old_retry_short = rdev->wiphy.retry_short;
2482 old_retry_long = rdev->wiphy.retry_long;
2483 old_frag_threshold = rdev->wiphy.frag_threshold;
2484 old_rts_threshold = rdev->wiphy.rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002485 old_coverage_class = rdev->wiphy.coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002486
2487 if (changed & WIPHY_PARAM_RETRY_SHORT)
2488 rdev->wiphy.retry_short = retry_short;
2489 if (changed & WIPHY_PARAM_RETRY_LONG)
2490 rdev->wiphy.retry_long = retry_long;
2491 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
2492 rdev->wiphy.frag_threshold = frag_threshold;
2493 if (changed & WIPHY_PARAM_RTS_THRESHOLD)
2494 rdev->wiphy.rts_threshold = rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002495 if (changed & WIPHY_PARAM_COVERAGE_CLASS)
2496 rdev->wiphy.coverage_class = coverage_class;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002497
Hila Gonene35e4d22012-06-27 17:19:42 +03002498 result = rdev_set_wiphy_params(rdev, changed);
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002499 if (result) {
2500 rdev->wiphy.retry_short = old_retry_short;
2501 rdev->wiphy.retry_long = old_retry_long;
2502 rdev->wiphy.frag_threshold = old_frag_threshold;
2503 rdev->wiphy.rts_threshold = old_rts_threshold;
Lukáš Turek81077e82009-12-21 22:50:47 +01002504 rdev->wiphy.coverage_class = old_coverage_class;
Michal Kazior9189ee32015-08-03 10:55:24 +02002505 return result;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +02002506 }
2507 }
Ying Xue7f2b8562014-01-15 10:23:45 +08002508 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002509}
2510
Johannes Berg71bbc992012-06-15 15:30:18 +02002511static inline u64 wdev_id(struct wireless_dev *wdev)
2512{
2513 return (u64)wdev->identifier |
Zhao, Gangf26cbf42014-04-21 12:53:03 +08002514 ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
Johannes Berg71bbc992012-06-15 15:30:18 +02002515}
Johannes Berg55682962007-09-20 13:09:35 -04002516
Johannes Berg683b6d32012-11-08 21:25:48 +01002517static int nl80211_send_chandef(struct sk_buff *msg,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01002518 const struct cfg80211_chan_def *chandef)
Johannes Berg683b6d32012-11-08 21:25:48 +01002519{
Johannes Berg601555c2014-11-27 17:26:56 +01002520 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
2521 return -EINVAL;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002522
Johannes Berg683b6d32012-11-08 21:25:48 +01002523 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
2524 chandef->chan->center_freq))
2525 return -ENOBUFS;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01002526 switch (chandef->width) {
2527 case NL80211_CHAN_WIDTH_20_NOHT:
2528 case NL80211_CHAN_WIDTH_20:
2529 case NL80211_CHAN_WIDTH_40:
2530 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
2531 cfg80211_get_chandef_type(chandef)))
2532 return -ENOBUFS;
2533 break;
2534 default:
2535 break;
2536 }
2537 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
2538 return -ENOBUFS;
2539 if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
2540 return -ENOBUFS;
2541 if (chandef->center_freq2 &&
2542 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
Johannes Berg683b6d32012-11-08 21:25:48 +01002543 return -ENOBUFS;
2544 return 0;
2545}
2546
Eric W. Biederman15e47302012-09-07 20:12:54 +00002547static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
Johannes Bergd7264052009-04-19 16:23:20 +02002548 struct cfg80211_registered_device *rdev,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002549 struct wireless_dev *wdev, bool removal)
Johannes Berg55682962007-09-20 13:09:35 -04002550{
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002551 struct net_device *dev = wdev->netdev;
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002552 u8 cmd = NL80211_CMD_NEW_INTERFACE;
Johannes Berg55682962007-09-20 13:09:35 -04002553 void *hdr;
2554
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002555 if (removal)
2556 cmd = NL80211_CMD_DEL_INTERFACE;
2557
2558 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg55682962007-09-20 13:09:35 -04002559 if (!hdr)
2560 return -1;
2561
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002562 if (dev &&
2563 (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002564 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002565 goto nla_put_failure;
2566
2567 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
2568 nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02002569 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
2570 NL80211_ATTR_PAD) ||
Johannes Berg98104fde2012-06-16 00:19:54 +02002571 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04002572 nla_put_u32(msg, NL80211_ATTR_GENERATION,
2573 rdev->devlist_generation ^
2574 (cfg80211_rdev_list_generation << 2)))
2575 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002576
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002577 if (rdev->ops->get_channel) {
Johannes Berg683b6d32012-11-08 21:25:48 +01002578 int ret;
2579 struct cfg80211_chan_def chandef;
Johannes Berg5b7ccaf2012-07-12 19:45:08 +02002580
Johannes Berg683b6d32012-11-08 21:25:48 +01002581 ret = rdev_get_channel(rdev, wdev, &chandef);
2582 if (ret == 0) {
2583 if (nl80211_send_chandef(msg, &chandef))
2584 goto nla_put_failure;
2585 }
Pontus Fuchsd91df0e2012-04-03 16:39:58 +02002586 }
2587
Rafał Miłeckid55d0d52015-08-31 22:59:38 +02002588 if (rdev->ops->get_tx_power) {
2589 int dbm, ret;
2590
2591 ret = rdev_get_tx_power(rdev, wdev, &dbm);
2592 if (ret == 0 &&
2593 nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
2594 DBM_TO_MBM(dbm)))
2595 goto nla_put_failure;
2596 }
2597
Antonio Quartullib84e7a02012-11-07 12:52:20 +01002598 if (wdev->ssid_len) {
2599 if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
2600 goto nla_put_failure;
2601 }
2602
Johannes Berg053c0952015-01-16 22:09:00 +01002603 genlmsg_end(msg, hdr);
2604 return 0;
Johannes Berg55682962007-09-20 13:09:35 -04002605
2606 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002607 genlmsg_cancel(msg, hdr);
2608 return -EMSGSIZE;
Johannes Berg55682962007-09-20 13:09:35 -04002609}
2610
2611static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
2612{
2613 int wp_idx = 0;
2614 int if_idx = 0;
2615 int wp_start = cb->args[0];
2616 int if_start = cb->args[1];
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002617 int filter_wiphy = -1;
Johannes Bergf5ea9122009-08-07 16:17:38 +02002618 struct cfg80211_registered_device *rdev;
Johannes Berg55682962007-09-20 13:09:35 -04002619 struct wireless_dev *wdev;
2620
Johannes Berg5fe231e2013-05-08 21:45:15 +02002621 rtnl_lock();
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002622 if (!cb->args[2]) {
2623 struct nl80211_dump_wiphy_state state = {
2624 .filter_wiphy = -1,
2625 };
2626 int ret;
2627
2628 ret = nl80211_dump_wiphy_parse(skb, cb, &state);
2629 if (ret)
2630 return ret;
2631
2632 filter_wiphy = state.filter_wiphy;
2633
2634 /*
2635 * if filtering, set cb->args[2] to +1 since 0 is the default
2636 * value needed to determine that parsing is necessary.
2637 */
2638 if (filter_wiphy >= 0)
2639 cb->args[2] = filter_wiphy + 1;
2640 else
2641 cb->args[2] = -1;
2642 } else if (cb->args[2] > 0) {
2643 filter_wiphy = cb->args[2] - 1;
2644 }
2645
Johannes Bergf5ea9122009-08-07 16:17:38 +02002646 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2647 if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
Johannes Berg463d0182009-07-14 00:33:35 +02002648 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002649 if (wp_idx < wp_start) {
2650 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002651 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002652 }
Denis Kenziorb7fb44d2016-08-03 17:02:15 -05002653
2654 if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx)
2655 continue;
2656
Johannes Berg55682962007-09-20 13:09:35 -04002657 if_idx = 0;
2658
Johannes Berg53873f12016-05-03 16:52:04 +03002659 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002660 if (if_idx < if_start) {
2661 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002662 continue;
Johannes Bergbba95fe2008-07-29 13:22:51 +02002663 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002664 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
Johannes Berg55682962007-09-20 13:09:35 -04002665 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002666 rdev, wdev, false) < 0) {
Johannes Bergbba95fe2008-07-29 13:22:51 +02002667 goto out;
2668 }
2669 if_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002670 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002671
2672 wp_idx++;
Johannes Berg55682962007-09-20 13:09:35 -04002673 }
Johannes Bergbba95fe2008-07-29 13:22:51 +02002674 out:
Johannes Berg5fe231e2013-05-08 21:45:15 +02002675 rtnl_unlock();
Johannes Berg55682962007-09-20 13:09:35 -04002676
2677 cb->args[0] = wp_idx;
2678 cb->args[1] = if_idx;
2679
2680 return skb->len;
2681}
2682
2683static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
2684{
2685 struct sk_buff *msg;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08002686 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg72fb2ab2012-06-15 17:52:47 +02002687 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04002688
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07002689 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -04002690 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02002691 return -ENOMEM;
Johannes Berg55682962007-09-20 13:09:35 -04002692
Eric W. Biederman15e47302012-09-07 20:12:54 +00002693 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002694 rdev, wdev, false) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02002695 nlmsg_free(msg);
2696 return -ENOBUFS;
2697 }
Johannes Berg55682962007-09-20 13:09:35 -04002698
Johannes Berg134e6372009-07-10 09:51:34 +00002699 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002700}
2701
Michael Wu66f7ac52008-01-31 19:48:22 +01002702static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
2703 [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
2704 [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
2705 [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
2706 [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
2707 [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002708 [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
Michael Wu66f7ac52008-01-31 19:48:22 +01002709};
2710
2711static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
2712{
2713 struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
2714 int flag;
2715
2716 *mntrflags = 0;
2717
2718 if (!nla)
2719 return -EINVAL;
2720
2721 if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
2722 nla, mntr_flags_policy))
2723 return -EINVAL;
2724
2725 for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
2726 if (flags[flag])
2727 *mntrflags |= (1<<flag);
2728
2729 return 0;
2730}
2731
Johannes Berg9bc383d2009-11-19 11:55:19 +01002732static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002733 struct net_device *netdev, u8 use_4addr,
2734 enum nl80211_iftype iftype)
Johannes Berg9bc383d2009-11-19 11:55:19 +01002735{
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002736 if (!use_4addr) {
Jiri Pirkof350a0a82010-06-15 06:50:45 +00002737 if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002738 return -EBUSY;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002739 return 0;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002740 }
Johannes Berg9bc383d2009-11-19 11:55:19 +01002741
2742 switch (iftype) {
2743 case NL80211_IFTYPE_AP_VLAN:
2744 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
2745 return 0;
2746 break;
2747 case NL80211_IFTYPE_STATION:
2748 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
2749 return 0;
2750 break;
2751 default:
2752 break;
2753 }
2754
2755 return -EOPNOTSUPP;
2756}
2757
Johannes Berg55682962007-09-20 13:09:35 -04002758static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
2759{
Johannes Berg4c476992010-10-04 21:36:35 +02002760 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002761 struct vif_params params;
Johannes Berge36d56b2009-06-09 21:04:43 +02002762 int err;
Johannes Berg04a773a2009-04-19 21:24:32 +02002763 enum nl80211_iftype otype, ntype;
Johannes Berg4c476992010-10-04 21:36:35 +02002764 struct net_device *dev = info->user_ptr[1];
Johannes Berg92ffe052008-09-16 20:39:36 +02002765 u32 _flags, *flags = NULL;
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002766 bool change = false;
Johannes Berg55682962007-09-20 13:09:35 -04002767
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002768 memset(&params, 0, sizeof(params));
2769
Johannes Berg04a773a2009-04-19 21:24:32 +02002770 otype = ntype = dev->ieee80211_ptr->iftype;
Johannes Berg55682962007-09-20 13:09:35 -04002771
Johannes Berg723b0382008-09-16 20:22:09 +02002772 if (info->attrs[NL80211_ATTR_IFTYPE]) {
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002773 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
Johannes Berg04a773a2009-04-19 21:24:32 +02002774 if (otype != ntype)
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002775 change = true;
Johannes Berg4c476992010-10-04 21:36:35 +02002776 if (ntype > NL80211_IFTYPE_MAX)
2777 return -EINVAL;
Johannes Berg723b0382008-09-16 20:22:09 +02002778 }
2779
Johannes Berg92ffe052008-09-16 20:39:36 +02002780 if (info->attrs[NL80211_ATTR_MESH_ID]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01002781 struct wireless_dev *wdev = dev->ieee80211_ptr;
2782
Johannes Berg4c476992010-10-04 21:36:35 +02002783 if (ntype != NL80211_IFTYPE_MESH_POINT)
2784 return -EINVAL;
Johannes Berg29cbe682010-12-03 09:20:44 +01002785 if (netif_running(dev))
2786 return -EBUSY;
2787
2788 wdev_lock(wdev);
2789 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2790 IEEE80211_MAX_MESH_ID_LEN);
2791 wdev->mesh_id_up_len =
2792 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2793 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2794 wdev->mesh_id_up_len);
2795 wdev_unlock(wdev);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002796 }
2797
Felix Fietkau8b787642009-11-10 18:53:10 +01002798 if (info->attrs[NL80211_ATTR_4ADDR]) {
2799 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
2800 change = true;
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002801 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002802 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002803 return err;
Felix Fietkau8b787642009-11-10 18:53:10 +01002804 } else {
2805 params.use_4addr = -1;
2806 }
2807
Johannes Berg92ffe052008-09-16 20:39:36 +02002808 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
Johannes Berg4c476992010-10-04 21:36:35 +02002809 if (ntype != NL80211_IFTYPE_MONITOR)
2810 return -EINVAL;
Johannes Berg92ffe052008-09-16 20:39:36 +02002811 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
2812 &_flags);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002813 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002814 return err;
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002815
2816 flags = &_flags;
2817 change = true;
Johannes Berg92ffe052008-09-16 20:39:36 +02002818 }
Johannes Berg3b858752009-03-12 09:55:09 +01002819
Aviya Erenfeldc6e6a0c2016-07-05 15:23:08 +03002820 if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
2821 const u8 *mumimo_groups;
2822 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2823
2824 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2825 return -EOPNOTSUPP;
2826
2827 mumimo_groups =
2828 nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
2829
2830 /* bits 0 and 63 are reserved and must be zero */
2831 if ((mumimo_groups[0] & BIT(7)) ||
2832 (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0)))
2833 return -EINVAL;
2834
2835 memcpy(params.vht_mumimo_groups, mumimo_groups,
2836 VHT_MUMIMO_GROUPS_DATA_LEN);
2837 change = true;
2838 }
2839
2840 if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
2841 u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
2842
2843 if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
2844 return -EOPNOTSUPP;
2845
2846 nla_memcpy(params.macaddr,
2847 info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR],
2848 ETH_ALEN);
2849 change = true;
2850 }
2851
Luciano Coelho18003292013-08-29 13:26:57 +03002852 if (flags && (*flags & MONITOR_FLAG_ACTIVE) &&
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002853 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2854 return -EOPNOTSUPP;
2855
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002856 if (change)
Johannes Berg3d54d252009-08-21 14:51:05 +02002857 err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
Johannes Bergac7f9cf2009-03-21 17:07:59 +01002858 else
2859 err = 0;
Johannes Berg60719ff2008-09-16 14:55:09 +02002860
Johannes Berg9bc383d2009-11-19 11:55:19 +01002861 if (!err && params.use_4addr != -1)
2862 dev->ieee80211_ptr->use_4addr = params.use_4addr;
2863
Johannes Berg55682962007-09-20 13:09:35 -04002864 return err;
2865}
2866
2867static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
2868{
Johannes Berg4c476992010-10-04 21:36:35 +02002869 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002870 struct vif_params params;
Johannes Berg84efbb82012-06-16 00:00:26 +02002871 struct wireless_dev *wdev;
Denis Kenzior896ff062016-08-03 16:58:33 -05002872 struct sk_buff *msg;
Johannes Berg55682962007-09-20 13:09:35 -04002873 int err;
2874 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
Michael Wu66f7ac52008-01-31 19:48:22 +01002875 u32 flags;
Johannes Berg55682962007-09-20 13:09:35 -04002876
Johannes Berg78f22b62014-03-24 17:57:27 +01002877 /* to avoid failing a new interface creation due to pending removal */
2878 cfg80211_destroy_ifaces(rdev);
2879
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002880 memset(&params, 0, sizeof(params));
2881
Johannes Berg55682962007-09-20 13:09:35 -04002882 if (!info->attrs[NL80211_ATTR_IFNAME])
2883 return -EINVAL;
2884
2885 if (info->attrs[NL80211_ATTR_IFTYPE]) {
2886 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
2887 if (type > NL80211_IFTYPE_MAX)
2888 return -EINVAL;
2889 }
2890
Johannes Berg79c97e92009-07-07 03:56:12 +02002891 if (!rdev->ops->add_virtual_intf ||
Johannes Berg4c476992010-10-04 21:36:35 +02002892 !(rdev->wiphy.interface_modes & (1 << type)))
2893 return -EOPNOTSUPP;
Johannes Berg55682962007-09-20 13:09:35 -04002894
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002895 if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
Ben Greeare8f479b2014-10-22 12:23:05 -07002896 rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
2897 info->attrs[NL80211_ATTR_MAC]) {
Arend van Spriel1c18f142013-01-08 10:17:27 +01002898 nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
2899 ETH_ALEN);
2900 if (!is_valid_ether_addr(params.macaddr))
2901 return -EADDRNOTAVAIL;
2902 }
2903
Johannes Berg9bc383d2009-11-19 11:55:19 +01002904 if (info->attrs[NL80211_ATTR_4ADDR]) {
Felix Fietkau8b787642009-11-10 18:53:10 +01002905 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
Johannes Bergad4bb6f2009-11-19 00:56:30 +01002906 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
Johannes Berg9bc383d2009-11-19 11:55:19 +01002907 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02002908 return err;
Johannes Berg9bc383d2009-11-19 11:55:19 +01002909 }
Felix Fietkau8b787642009-11-10 18:53:10 +01002910
Michael Wu66f7ac52008-01-31 19:48:22 +01002911 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
2912 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
2913 &flags);
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002914
Luciano Coelho18003292013-08-29 13:26:57 +03002915 if (!err && (flags & MONITOR_FLAG_ACTIVE) &&
Felix Fietkaue057d3c2013-05-28 13:01:52 +02002916 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2917 return -EOPNOTSUPP;
2918
Johannes Berga18c7192015-02-24 10:56:42 +01002919 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2920 if (!msg)
2921 return -ENOMEM;
2922
Hila Gonene35e4d22012-06-27 17:19:42 +03002923 wdev = rdev_add_virtual_intf(rdev,
2924 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
Tom Gundersen6bab2e192015-03-18 11:13:39 +01002925 NET_NAME_USER, type, err ? NULL : &flags,
2926 &params);
Rafał Miłeckid687cbb2014-11-14 18:43:28 +01002927 if (WARN_ON(!wdev)) {
2928 nlmsg_free(msg);
2929 return -EPROTO;
2930 } else if (IS_ERR(wdev)) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002931 nlmsg_free(msg);
Johannes Berg84efbb82012-06-16 00:00:26 +02002932 return PTR_ERR(wdev);
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002933 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01002934
Jukka Rissanen18e5ca62014-11-13 17:25:14 +02002935 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
Johannes Berg78f22b62014-03-24 17:57:27 +01002936 wdev->owner_nlportid = info->snd_portid;
2937
Johannes Berg98104fde2012-06-16 00:19:54 +02002938 switch (type) {
2939 case NL80211_IFTYPE_MESH_POINT:
2940 if (!info->attrs[NL80211_ATTR_MESH_ID])
2941 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01002942 wdev_lock(wdev);
2943 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2944 IEEE80211_MAX_MESH_ID_LEN);
2945 wdev->mesh_id_up_len =
2946 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
2947 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2948 wdev->mesh_id_up_len);
2949 wdev_unlock(wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +02002950 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002951 case NL80211_IFTYPE_NAN:
Johannes Berg98104fde2012-06-16 00:19:54 +02002952 case NL80211_IFTYPE_P2P_DEVICE:
2953 /*
Ayala Bekercb3b7d82016-09-20 17:31:13 +03002954 * P2P Device and NAN do not have a netdev, so don't go
Johannes Berg98104fde2012-06-16 00:19:54 +02002955 * through the netdev notifier and must be added here
2956 */
2957 mutex_init(&wdev->mtx);
2958 INIT_LIST_HEAD(&wdev->event_list);
2959 spin_lock_init(&wdev->event_lock);
2960 INIT_LIST_HEAD(&wdev->mgmt_registrations);
2961 spin_lock_init(&wdev->mgmt_registrations_lock);
2962
Johannes Berg98104fde2012-06-16 00:19:54 +02002963 wdev->identifier = ++rdev->wdev_id;
Johannes Berg53873f12016-05-03 16:52:04 +03002964 list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
Johannes Berg98104fde2012-06-16 00:19:54 +02002965 rdev->devlist_generation++;
Johannes Berg98104fde2012-06-16 00:19:54 +02002966 break;
2967 default:
2968 break;
Johannes Berg29cbe682010-12-03 09:20:44 +01002969 }
2970
Eric W. Biederman15e47302012-09-07 20:12:54 +00002971 if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002972 rdev, wdev, false) < 0) {
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002973 nlmsg_free(msg);
2974 return -ENOBUFS;
2975 }
2976
Denis Kenzior896ff062016-08-03 16:58:33 -05002977 /*
2978 * For wdevs which have no associated netdev object (e.g. of type
2979 * NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here.
2980 * For all other types, the event will be generated from the
2981 * netdev notifier
2982 */
2983 if (!wdev->netdev)
2984 nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
Tomasz Bursztyka8f894be2014-11-12 16:26:45 +02002985
Johannes Berg1c90f9d2012-06-16 00:05:37 +02002986 return genlmsg_reply(msg, info);
Johannes Berg55682962007-09-20 13:09:35 -04002987}
2988
2989static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
2990{
Johannes Berg4c476992010-10-04 21:36:35 +02002991 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg84efbb82012-06-16 00:00:26 +02002992 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg55682962007-09-20 13:09:35 -04002993
Johannes Berg4c476992010-10-04 21:36:35 +02002994 if (!rdev->ops->del_virtual_intf)
2995 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01002996
Johannes Berg84efbb82012-06-16 00:00:26 +02002997 /*
2998 * If we remove a wireless device without a netdev then clear
2999 * user_ptr[1] so that nl80211_post_doit won't dereference it
3000 * to check if it needs to do dev_put(). Otherwise it crashes
3001 * since the wdev has been freed, unlike with a netdev where
3002 * we need the dev_put() for the netdev to really be freed.
3003 */
3004 if (!wdev->netdev)
3005 info->user_ptr[1] = NULL;
3006
Denis Kenzior7f8ed012016-08-03 16:58:35 -05003007 return rdev_del_virtual_intf(rdev, wdev);
Johannes Berg55682962007-09-20 13:09:35 -04003008}
3009
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003010static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
3011{
3012 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3013 struct net_device *dev = info->user_ptr[1];
3014 u16 noack_map;
3015
3016 if (!info->attrs[NL80211_ATTR_NOACK_MAP])
3017 return -EINVAL;
3018
3019 if (!rdev->ops->set_noack_map)
3020 return -EOPNOTSUPP;
3021
3022 noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
3023
Hila Gonene35e4d22012-06-27 17:19:42 +03003024 return rdev_set_noack_map(rdev, dev, noack_map);
Simon Wunderlich1d9d9212011-11-18 14:20:43 +01003025}
3026
Johannes Berg41ade002007-12-19 02:03:29 +01003027struct get_key_cookie {
3028 struct sk_buff *msg;
3029 int error;
Johannes Bergb9454e82009-07-08 13:29:08 +02003030 int idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003031};
3032
3033static void get_key_callback(void *c, struct key_params *params)
3034{
Johannes Bergb9454e82009-07-08 13:29:08 +02003035 struct nlattr *key;
Johannes Berg41ade002007-12-19 02:03:29 +01003036 struct get_key_cookie *cookie = c;
3037
David S. Miller9360ffd2012-03-29 04:41:26 -04003038 if ((params->key &&
3039 nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
3040 params->key_len, params->key)) ||
3041 (params->seq &&
3042 nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
3043 params->seq_len, params->seq)) ||
3044 (params->cipher &&
3045 nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
3046 params->cipher)))
3047 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003048
Johannes Bergb9454e82009-07-08 13:29:08 +02003049 key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
3050 if (!key)
3051 goto nla_put_failure;
3052
David S. Miller9360ffd2012-03-29 04:41:26 -04003053 if ((params->key &&
3054 nla_put(cookie->msg, NL80211_KEY_DATA,
3055 params->key_len, params->key)) ||
3056 (params->seq &&
3057 nla_put(cookie->msg, NL80211_KEY_SEQ,
3058 params->seq_len, params->seq)) ||
3059 (params->cipher &&
3060 nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
3061 params->cipher)))
3062 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003063
David S. Miller9360ffd2012-03-29 04:41:26 -04003064 if (nla_put_u8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx))
3065 goto nla_put_failure;
Johannes Bergb9454e82009-07-08 13:29:08 +02003066
3067 nla_nest_end(cookie->msg, key);
3068
Johannes Berg41ade002007-12-19 02:03:29 +01003069 return;
3070 nla_put_failure:
3071 cookie->error = 1;
3072}
3073
3074static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
3075{
Johannes Berg4c476992010-10-04 21:36:35 +02003076 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003077 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003078 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003079 u8 key_idx = 0;
Johannes Berge31b8212010-10-05 19:39:30 +02003080 const u8 *mac_addr = NULL;
3081 bool pairwise;
Johannes Berg41ade002007-12-19 02:03:29 +01003082 struct get_key_cookie cookie = {
3083 .error = 0,
3084 };
3085 void *hdr;
3086 struct sk_buff *msg;
3087
3088 if (info->attrs[NL80211_ATTR_KEY_IDX])
3089 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
3090
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +02003091 if (key_idx > 5)
Johannes Berg41ade002007-12-19 02:03:29 +01003092 return -EINVAL;
3093
3094 if (info->attrs[NL80211_ATTR_MAC])
3095 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3096
Johannes Berge31b8212010-10-05 19:39:30 +02003097 pairwise = !!mac_addr;
3098 if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
3099 u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07003100
Johannes Berge31b8212010-10-05 19:39:30 +02003101 if (kt >= NUM_NL80211_KEYTYPES)
3102 return -EINVAL;
3103 if (kt != NL80211_KEYTYPE_GROUP &&
3104 kt != NL80211_KEYTYPE_PAIRWISE)
3105 return -EINVAL;
3106 pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
3107 }
3108
Johannes Berg4c476992010-10-04 21:36:35 +02003109 if (!rdev->ops->get_key)
3110 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003111
Johannes Berg0fa7b392015-01-23 11:10:12 +01003112 if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3113 return -ENOENT;
3114
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07003115 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02003116 if (!msg)
3117 return -ENOMEM;
Johannes Berg41ade002007-12-19 02:03:29 +01003118
Eric W. Biederman15e47302012-09-07 20:12:54 +00003119 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg41ade002007-12-19 02:03:29 +01003120 NL80211_CMD_NEW_KEY);
Dan Carpentercb35fba2013-08-14 14:50:01 +03003121 if (!hdr)
Johannes Berg9fe271a2013-10-25 11:15:12 +02003122 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003123
3124 cookie.msg = msg;
Johannes Bergb9454e82009-07-08 13:29:08 +02003125 cookie.idx = key_idx;
Johannes Berg41ade002007-12-19 02:03:29 +01003126
David S. Miller9360ffd2012-03-29 04:41:26 -04003127 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
3128 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
3129 goto nla_put_failure;
3130 if (mac_addr &&
3131 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
3132 goto nla_put_failure;
Johannes Berg41ade002007-12-19 02:03:29 +01003133
Hila Gonene35e4d22012-06-27 17:19:42 +03003134 err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
3135 get_key_callback);
Johannes Berg41ade002007-12-19 02:03:29 +01003136
3137 if (err)
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003138 goto free_msg;
Johannes Berg41ade002007-12-19 02:03:29 +01003139
3140 if (cookie.error)
3141 goto nla_put_failure;
3142
3143 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02003144 return genlmsg_reply(msg, info);
Johannes Berg41ade002007-12-19 02:03:29 +01003145
3146 nla_put_failure:
3147 err = -ENOBUFS;
Niko Jokinen6c95e2a2009-07-15 11:00:53 +03003148 free_msg:
Johannes Berg41ade002007-12-19 02:03:29 +01003149 nlmsg_free(msg);
Johannes Berg41ade002007-12-19 02:03:29 +01003150 return err;
3151}
3152
3153static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
3154{
Johannes Berg4c476992010-10-04 21:36:35 +02003155 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergb9454e82009-07-08 13:29:08 +02003156 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003157 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003158 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003159
Johannes Bergb9454e82009-07-08 13:29:08 +02003160 err = nl80211_parse_key(info, &key);
3161 if (err)
3162 return err;
3163
3164 if (key.idx < 0)
Johannes Berg41ade002007-12-19 02:03:29 +01003165 return -EINVAL;
3166
Johannes Bergb9454e82009-07-08 13:29:08 +02003167 /* only support setting default key */
3168 if (!key.def && !key.defmgmt)
Johannes Berg41ade002007-12-19 02:03:29 +01003169 return -EINVAL;
3170
Johannes Bergfffd0932009-07-08 14:22:54 +02003171 wdev_lock(dev->ieee80211_ptr);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003172
3173 if (key.def) {
3174 if (!rdev->ops->set_default_key) {
3175 err = -EOPNOTSUPP;
3176 goto out;
3177 }
3178
3179 err = nl80211_key_allowed(dev->ieee80211_ptr);
3180 if (err)
3181 goto out;
3182
Hila Gonene35e4d22012-06-27 17:19:42 +03003183 err = rdev_set_default_key(rdev, dev, key.idx,
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003184 key.def_uni, key.def_multi);
3185
3186 if (err)
3187 goto out;
Johannes Bergfffd0932009-07-08 14:22:54 +02003188
Johannes Berg3d23e342009-09-29 23:27:28 +02003189#ifdef CONFIG_CFG80211_WEXT
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003190 dev->ieee80211_ptr->wext.default_key = key.idx;
Johannes Berg08645122009-05-11 13:54:58 +02003191#endif
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003192 } else {
3193 if (key.def_uni || !key.def_multi) {
3194 err = -EINVAL;
3195 goto out;
3196 }
3197
3198 if (!rdev->ops->set_default_mgmt_key) {
3199 err = -EOPNOTSUPP;
3200 goto out;
3201 }
3202
3203 err = nl80211_key_allowed(dev->ieee80211_ptr);
3204 if (err)
3205 goto out;
3206
Hila Gonene35e4d22012-06-27 17:19:42 +03003207 err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
Johannes Bergdbd2fd62010-12-09 19:58:59 +01003208 if (err)
3209 goto out;
3210
3211#ifdef CONFIG_CFG80211_WEXT
3212 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
3213#endif
3214 }
3215
3216 out:
Johannes Bergfffd0932009-07-08 14:22:54 +02003217 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003218
Johannes Berg41ade002007-12-19 02:03:29 +01003219 return err;
3220}
3221
3222static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
3223{
Johannes Berg4c476992010-10-04 21:36:35 +02003224 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfffd0932009-07-08 14:22:54 +02003225 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003226 struct net_device *dev = info->user_ptr[1];
Johannes Bergb9454e82009-07-08 13:29:08 +02003227 struct key_parse key;
Johannes Berge31b8212010-10-05 19:39:30 +02003228 const u8 *mac_addr = NULL;
Johannes Berg41ade002007-12-19 02:03:29 +01003229
Johannes Bergb9454e82009-07-08 13:29:08 +02003230 err = nl80211_parse_key(info, &key);
3231 if (err)
3232 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003233
Johannes Bergb9454e82009-07-08 13:29:08 +02003234 if (!key.p.key)
Johannes Berg41ade002007-12-19 02:03:29 +01003235 return -EINVAL;
3236
Johannes Berg41ade002007-12-19 02:03:29 +01003237 if (info->attrs[NL80211_ATTR_MAC])
3238 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3239
Johannes Berge31b8212010-10-05 19:39:30 +02003240 if (key.type == -1) {
3241 if (mac_addr)
3242 key.type = NL80211_KEYTYPE_PAIRWISE;
3243 else
3244 key.type = NL80211_KEYTYPE_GROUP;
3245 }
3246
3247 /* for now */
3248 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3249 key.type != NL80211_KEYTYPE_GROUP)
3250 return -EINVAL;
3251
Johannes Berg4c476992010-10-04 21:36:35 +02003252 if (!rdev->ops->add_key)
3253 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01003254
Johannes Berge31b8212010-10-05 19:39:30 +02003255 if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
3256 key.type == NL80211_KEYTYPE_PAIRWISE,
3257 mac_addr))
Johannes Berg4c476992010-10-04 21:36:35 +02003258 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02003259
3260 wdev_lock(dev->ieee80211_ptr);
3261 err = nl80211_key_allowed(dev->ieee80211_ptr);
3262 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003263 err = rdev_add_key(rdev, dev, key.idx,
3264 key.type == NL80211_KEYTYPE_PAIRWISE,
3265 mac_addr, &key.p);
Johannes Bergfffd0932009-07-08 14:22:54 +02003266 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg41ade002007-12-19 02:03:29 +01003267
Johannes Berg41ade002007-12-19 02:03:29 +01003268 return err;
3269}
3270
3271static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
3272{
Johannes Berg4c476992010-10-04 21:36:35 +02003273 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg41ade002007-12-19 02:03:29 +01003274 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02003275 struct net_device *dev = info->user_ptr[1];
Johannes Berg41ade002007-12-19 02:03:29 +01003276 u8 *mac_addr = NULL;
Johannes Bergb9454e82009-07-08 13:29:08 +02003277 struct key_parse key;
Johannes Berg41ade002007-12-19 02:03:29 +01003278
Johannes Bergb9454e82009-07-08 13:29:08 +02003279 err = nl80211_parse_key(info, &key);
3280 if (err)
3281 return err;
Johannes Berg41ade002007-12-19 02:03:29 +01003282
3283 if (info->attrs[NL80211_ATTR_MAC])
3284 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
3285
Johannes Berge31b8212010-10-05 19:39:30 +02003286 if (key.type == -1) {
3287 if (mac_addr)
3288 key.type = NL80211_KEYTYPE_PAIRWISE;
3289 else
3290 key.type = NL80211_KEYTYPE_GROUP;
3291 }
3292
3293 /* for now */
3294 if (key.type != NL80211_KEYTYPE_PAIRWISE &&
3295 key.type != NL80211_KEYTYPE_GROUP)
3296 return -EINVAL;
3297
Johannes Berg4c476992010-10-04 21:36:35 +02003298 if (!rdev->ops->del_key)
3299 return -EOPNOTSUPP;
Johannes Berg41ade002007-12-19 02:03:29 +01003300
Johannes Bergfffd0932009-07-08 14:22:54 +02003301 wdev_lock(dev->ieee80211_ptr);
3302 err = nl80211_key_allowed(dev->ieee80211_ptr);
Johannes Berge31b8212010-10-05 19:39:30 +02003303
Johannes Berg0fa7b392015-01-23 11:10:12 +01003304 if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
Johannes Berge31b8212010-10-05 19:39:30 +02003305 !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
3306 err = -ENOENT;
3307
Johannes Bergfffd0932009-07-08 14:22:54 +02003308 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03003309 err = rdev_del_key(rdev, dev, key.idx,
3310 key.type == NL80211_KEYTYPE_PAIRWISE,
3311 mac_addr);
Johannes Berg41ade002007-12-19 02:03:29 +01003312
Johannes Berg3d23e342009-09-29 23:27:28 +02003313#ifdef CONFIG_CFG80211_WEXT
Johannes Berg08645122009-05-11 13:54:58 +02003314 if (!err) {
Johannes Bergb9454e82009-07-08 13:29:08 +02003315 if (key.idx == dev->ieee80211_ptr->wext.default_key)
Johannes Berg08645122009-05-11 13:54:58 +02003316 dev->ieee80211_ptr->wext.default_key = -1;
Johannes Bergb9454e82009-07-08 13:29:08 +02003317 else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
Johannes Berg08645122009-05-11 13:54:58 +02003318 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
3319 }
3320#endif
Johannes Bergfffd0932009-07-08 14:22:54 +02003321 wdev_unlock(dev->ieee80211_ptr);
Johannes Berg08645122009-05-11 13:54:58 +02003322
Johannes Berg41ade002007-12-19 02:03:29 +01003323 return err;
3324}
3325
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05303326/* This function returns an error or the number of nested attributes */
3327static int validate_acl_mac_addrs(struct nlattr *nl_attr)
3328{
3329 struct nlattr *attr;
3330 int n_entries = 0, tmp;
3331
3332 nla_for_each_nested(attr, nl_attr, tmp) {
3333 if (nla_len(attr) != ETH_ALEN)
3334 return -EINVAL;
3335
3336 n_entries++;
3337 }
3338
3339 return n_entries;
3340}
3341
3342/*
3343 * This function parses ACL information and allocates memory for ACL data.
3344 * On successful return, the calling function is responsible to free the
3345 * ACL buffer returned by this function.
3346 */
3347static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
3348 struct genl_info *info)
3349{
3350 enum nl80211_acl_policy acl_policy;
3351 struct nlattr *attr;
3352 struct cfg80211_acl_data *acl;
3353 int i = 0, n_entries, tmp;
3354
3355 if (!wiphy->max_acl_mac_addrs)
3356 return ERR_PTR(-EOPNOTSUPP);
3357
3358 if (!info->attrs[NL80211_ATTR_ACL_POLICY])
3359 return ERR_PTR(-EINVAL);
3360
3361 acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
3362 if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
3363 acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
3364 return ERR_PTR(-EINVAL);
3365
3366 if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
3367 return ERR_PTR(-EINVAL);
3368
3369 n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
3370 if (n_entries < 0)
3371 return ERR_PTR(n_entries);
3372
3373 if (n_entries > wiphy->max_acl_mac_addrs)
3374 return ERR_PTR(-ENOTSUPP);
3375
3376 acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
3377 GFP_KERNEL);
3378 if (!acl)
3379 return ERR_PTR(-ENOMEM);
3380
3381 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
3382 memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
3383 i++;
3384 }
3385
3386 acl->n_acl_entries = n_entries;
3387 acl->acl_policy = acl_policy;
3388
3389 return acl;
3390}
3391
3392static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
3393{
3394 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3395 struct net_device *dev = info->user_ptr[1];
3396 struct cfg80211_acl_data *acl;
3397 int err;
3398
3399 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3400 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3401 return -EOPNOTSUPP;
3402
3403 if (!dev->ieee80211_ptr->beacon_interval)
3404 return -EINVAL;
3405
3406 acl = parse_acl_data(&rdev->wiphy, info);
3407 if (IS_ERR(acl))
3408 return PTR_ERR(acl);
3409
3410 err = rdev_set_mac_acl(rdev, dev, acl);
3411
3412 kfree(acl);
3413
3414 return err;
3415}
3416
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303417static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
3418 u8 *rates, u8 rates_len)
3419{
3420 u8 i;
3421 u32 mask = 0;
3422
3423 for (i = 0; i < rates_len; i++) {
3424 int rate = (rates[i] & 0x7f) * 5;
3425 int ridx;
3426
3427 for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
3428 struct ieee80211_rate *srate =
3429 &sband->bitrates[ridx];
3430 if (rate == srate->bitrate) {
3431 mask |= 1 << ridx;
3432 break;
3433 }
3434 }
3435 if (ridx == sband->n_bitrates)
3436 return 0; /* rate not found */
3437 }
3438
3439 return mask;
3440}
3441
3442static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
3443 u8 *rates, u8 rates_len,
3444 u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
3445{
3446 u8 i;
3447
3448 memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
3449
3450 for (i = 0; i < rates_len; i++) {
3451 int ridx, rbit;
3452
3453 ridx = rates[i] / 8;
3454 rbit = BIT(rates[i] % 8);
3455
3456 /* check validity */
3457 if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
3458 return false;
3459
3460 /* check availability */
3461 if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
3462 mcs[ridx] |= rbit;
3463 else
3464 return false;
3465 }
3466
3467 return true;
3468}
3469
3470static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
3471{
3472 u16 mcs_mask = 0;
3473
3474 switch (vht_mcs_map) {
3475 case IEEE80211_VHT_MCS_NOT_SUPPORTED:
3476 break;
3477 case IEEE80211_VHT_MCS_SUPPORT_0_7:
3478 mcs_mask = 0x00FF;
3479 break;
3480 case IEEE80211_VHT_MCS_SUPPORT_0_8:
3481 mcs_mask = 0x01FF;
3482 break;
3483 case IEEE80211_VHT_MCS_SUPPORT_0_9:
3484 mcs_mask = 0x03FF;
3485 break;
3486 default:
3487 break;
3488 }
3489
3490 return mcs_mask;
3491}
3492
3493static void vht_build_mcs_mask(u16 vht_mcs_map,
3494 u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
3495{
3496 u8 nss;
3497
3498 for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
3499 vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
3500 vht_mcs_map >>= 2;
3501 }
3502}
3503
3504static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
3505 struct nl80211_txrate_vht *txrate,
3506 u16 mcs[NL80211_VHT_NSS_MAX])
3507{
3508 u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3509 u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
3510 u8 i;
3511
3512 if (!sband->vht_cap.vht_supported)
3513 return false;
3514
3515 memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
3516
3517 /* Build vht_mcs_mask from VHT capabilities */
3518 vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
3519
3520 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
3521 if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
3522 mcs[i] = txrate->mcs[i];
3523 else
3524 return false;
3525 }
3526
3527 return true;
3528}
3529
3530static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
3531 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
3532 .len = NL80211_MAX_SUPP_RATES },
3533 [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
3534 .len = NL80211_MAX_SUPP_HT_RATES },
3535 [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
3536 [NL80211_TXRATE_GI] = { .type = NLA_U8 },
3537};
3538
3539static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
3540 struct cfg80211_bitrate_mask *mask)
3541{
3542 struct nlattr *tb[NL80211_TXRATE_MAX + 1];
3543 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3544 int rem, i;
3545 struct nlattr *tx_rates;
3546 struct ieee80211_supported_band *sband;
3547 u16 vht_tx_mcs_map;
3548
3549 memset(mask, 0, sizeof(*mask));
3550 /* Default to all rates enabled */
3551 for (i = 0; i < NUM_NL80211_BANDS; i++) {
3552 sband = rdev->wiphy.bands[i];
3553
3554 if (!sband)
3555 continue;
3556
3557 mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
3558 memcpy(mask->control[i].ht_mcs,
3559 sband->ht_cap.mcs.rx_mask,
3560 sizeof(mask->control[i].ht_mcs));
3561
3562 if (!sband->vht_cap.vht_supported)
3563 continue;
3564
3565 vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
3566 vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
3567 }
3568
3569 /* if no rates are given set it back to the defaults */
3570 if (!info->attrs[NL80211_ATTR_TX_RATES])
3571 goto out;
3572
3573 /* The nested attribute uses enum nl80211_band as the index. This maps
3574 * directly to the enum nl80211_band values used in cfg80211.
3575 */
3576 BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
3577 nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
3578 enum nl80211_band band = nla_type(tx_rates);
3579 int err;
3580
3581 if (band < 0 || band >= NUM_NL80211_BANDS)
3582 return -EINVAL;
3583 sband = rdev->wiphy.bands[band];
3584 if (sband == NULL)
3585 return -EINVAL;
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02003586 err = nla_parse_nested(tb, NL80211_TXRATE_MAX, tx_rates,
3587 nl80211_txattr_policy);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303588 if (err)
3589 return err;
3590 if (tb[NL80211_TXRATE_LEGACY]) {
3591 mask->control[band].legacy = rateset_to_mask(
3592 sband,
3593 nla_data(tb[NL80211_TXRATE_LEGACY]),
3594 nla_len(tb[NL80211_TXRATE_LEGACY]));
3595 if ((mask->control[band].legacy == 0) &&
3596 nla_len(tb[NL80211_TXRATE_LEGACY]))
3597 return -EINVAL;
3598 }
3599 if (tb[NL80211_TXRATE_HT]) {
3600 if (!ht_rateset_to_mask(
3601 sband,
3602 nla_data(tb[NL80211_TXRATE_HT]),
3603 nla_len(tb[NL80211_TXRATE_HT]),
3604 mask->control[band].ht_mcs))
3605 return -EINVAL;
3606 }
3607 if (tb[NL80211_TXRATE_VHT]) {
3608 if (!vht_set_mcs_mask(
3609 sband,
3610 nla_data(tb[NL80211_TXRATE_VHT]),
3611 mask->control[band].vht_mcs))
3612 return -EINVAL;
3613 }
3614 if (tb[NL80211_TXRATE_GI]) {
3615 mask->control[band].gi =
3616 nla_get_u8(tb[NL80211_TXRATE_GI]);
3617 if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
3618 return -EINVAL;
3619 }
3620
3621 if (mask->control[band].legacy == 0) {
3622 /* don't allow empty legacy rates if HT or VHT
3623 * are not even supported.
3624 */
3625 if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
3626 rdev->wiphy.bands[band]->vht_cap.vht_supported))
3627 return -EINVAL;
3628
3629 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
3630 if (mask->control[band].ht_mcs[i])
3631 goto out;
3632
3633 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
3634 if (mask->control[band].vht_mcs[i])
3635 goto out;
3636
3637 /* legacy and mcs rates may not be both empty */
3638 return -EINVAL;
3639 }
3640 }
3641
3642out:
3643 return 0;
3644}
3645
Johannes Berg8564e382016-09-19 09:44:44 +02003646static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
3647 enum nl80211_band band,
3648 struct cfg80211_bitrate_mask *beacon_rate)
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303649{
Johannes Berg8564e382016-09-19 09:44:44 +02003650 u32 count_ht, count_vht, i;
3651 u32 rate = beacon_rate->control[band].legacy;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303652
3653 /* Allow only one rate */
3654 if (hweight32(rate) > 1)
3655 return -EINVAL;
3656
3657 count_ht = 0;
3658 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003659 if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303660 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003661 } else if (beacon_rate->control[band].ht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303662 count_ht++;
3663 if (count_ht > 1)
3664 return -EINVAL;
3665 }
3666 if (count_ht && rate)
3667 return -EINVAL;
3668 }
3669
3670 count_vht = 0;
3671 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
Johannes Berg8564e382016-09-19 09:44:44 +02003672 if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303673 return -EINVAL;
Johannes Berg8564e382016-09-19 09:44:44 +02003674 } else if (beacon_rate->control[band].vht_mcs[i]) {
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303675 count_vht++;
3676 if (count_vht > 1)
3677 return -EINVAL;
3678 }
3679 if (count_vht && rate)
3680 return -EINVAL;
3681 }
3682
3683 if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
3684 return -EINVAL;
3685
Johannes Berg8564e382016-09-19 09:44:44 +02003686 if (rate &&
3687 !wiphy_ext_feature_isset(&rdev->wiphy,
3688 NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
3689 return -EINVAL;
3690 if (count_ht &&
3691 !wiphy_ext_feature_isset(&rdev->wiphy,
3692 NL80211_EXT_FEATURE_BEACON_RATE_HT))
3693 return -EINVAL;
3694 if (count_vht &&
3695 !wiphy_ext_feature_isset(&rdev->wiphy,
3696 NL80211_EXT_FEATURE_BEACON_RATE_VHT))
3697 return -EINVAL;
3698
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303699 return 0;
3700}
3701
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003702static int nl80211_parse_beacon(struct nlattr *attrs[],
Johannes Berg88600202012-02-13 15:17:18 +01003703 struct cfg80211_beacon_data *bcn)
Johannes Berged1b6cc2007-12-19 02:03:32 +01003704{
Johannes Berg88600202012-02-13 15:17:18 +01003705 bool haveinfo = false;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003706
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003707 if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
3708 !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
3709 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
3710 !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
Johannes Bergf4a11bb2009-03-27 12:40:28 +01003711 return -EINVAL;
3712
Johannes Berg88600202012-02-13 15:17:18 +01003713 memset(bcn, 0, sizeof(*bcn));
Johannes Berged1b6cc2007-12-19 02:03:32 +01003714
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003715 if (attrs[NL80211_ATTR_BEACON_HEAD]) {
3716 bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
3717 bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
Johannes Berg88600202012-02-13 15:17:18 +01003718 if (!bcn->head_len)
3719 return -EINVAL;
3720 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003721 }
3722
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003723 if (attrs[NL80211_ATTR_BEACON_TAIL]) {
3724 bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
3725 bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
Johannes Berg88600202012-02-13 15:17:18 +01003726 haveinfo = true;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003727 }
3728
Johannes Berg4c476992010-10-04 21:36:35 +02003729 if (!haveinfo)
3730 return -EINVAL;
Johannes Berged1b6cc2007-12-19 02:03:32 +01003731
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003732 if (attrs[NL80211_ATTR_IE]) {
3733 bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
3734 bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003735 }
3736
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003737 if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003738 bcn->proberesp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003739 nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003740 bcn->proberesp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003741 nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003742 }
3743
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003744 if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
Johannes Berg88600202012-02-13 15:17:18 +01003745 bcn->assocresp_ies =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003746 nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Johannes Berg88600202012-02-13 15:17:18 +01003747 bcn->assocresp_ies_len =
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003748 nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
Jouni Malinen9946ecf2011-08-10 23:55:56 +03003749 }
3750
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003751 if (attrs[NL80211_ATTR_PROBE_RESP]) {
3752 bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
3753 bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
Arik Nemtsov00f740e2011-11-10 11:28:56 +02003754 }
3755
Johannes Berg88600202012-02-13 15:17:18 +01003756 return 0;
3757}
3758
Johannes Berg66cd7942017-02-07 22:40:44 +02003759static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
3760 const u8 *rates)
3761{
3762 int i;
3763
3764 if (!rates)
3765 return;
3766
3767 for (i = 0; i < rates[1]; i++) {
3768 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
3769 params->ht_required = true;
3770 if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
3771 params->vht_required = true;
3772 }
3773}
3774
3775/*
3776 * Since the nl80211 API didn't include, from the beginning, attributes about
3777 * HT/VHT requirements/capabilities, we parse them out of the IEs for the
3778 * benefit of drivers that rebuild IEs in the firmware.
3779 */
3780static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
3781{
3782 const struct cfg80211_beacon_data *bcn = &params->beacon;
3783 size_t ies_len = bcn->beacon_ies_len;
3784 const u8 *ies = bcn->beacon_ies;
3785 const u8 *rates;
3786 const u8 *cap;
3787
3788 rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
3789 nl80211_check_ap_rate_selectors(params, rates);
3790
3791 rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
3792 nl80211_check_ap_rate_selectors(params, rates);
3793
3794 cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
3795 if (cap && cap[1] >= sizeof(*params->ht_cap))
3796 params->ht_cap = (void *)(cap + 2);
3797 cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
3798 if (cap && cap[1] >= sizeof(*params->vht_cap))
3799 params->vht_cap = (void *)(cap + 2);
3800}
3801
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003802static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
3803 struct cfg80211_ap_settings *params)
3804{
3805 struct wireless_dev *wdev;
3806 bool ret = false;
3807
Johannes Berg53873f12016-05-03 16:52:04 +03003808 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003809 if (wdev->iftype != NL80211_IFTYPE_AP &&
3810 wdev->iftype != NL80211_IFTYPE_P2P_GO)
3811 continue;
3812
Johannes Berg683b6d32012-11-08 21:25:48 +01003813 if (!wdev->preset_chandef.chan)
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003814 continue;
3815
Johannes Berg683b6d32012-11-08 21:25:48 +01003816 params->chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003817 ret = true;
3818 break;
3819 }
3820
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003821 return ret;
3822}
3823
Jouni Malinene39e5b52012-09-30 19:29:39 +03003824static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
3825 enum nl80211_auth_type auth_type,
3826 enum nl80211_commands cmd)
3827{
3828 if (auth_type > NL80211_AUTHTYPE_MAX)
3829 return false;
3830
3831 switch (cmd) {
3832 case NL80211_CMD_AUTHENTICATE:
3833 if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
3834 auth_type == NL80211_AUTHTYPE_SAE)
3835 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03003836 if (!wiphy_ext_feature_isset(&rdev->wiphy,
3837 NL80211_EXT_FEATURE_FILS_STA) &&
3838 (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3839 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3840 auth_type == NL80211_AUTHTYPE_FILS_PK))
3841 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003842 return true;
3843 case NL80211_CMD_CONNECT:
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03003844 /* SAE not supported yet */
3845 if (auth_type == NL80211_AUTHTYPE_SAE)
3846 return false;
3847 /* FILS with SK PFS or PK not supported yet */
3848 if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3849 auth_type == NL80211_AUTHTYPE_FILS_PK)
3850 return false;
3851 if (!wiphy_ext_feature_isset(
3852 &rdev->wiphy,
3853 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
3854 auth_type == NL80211_AUTHTYPE_FILS_SK)
3855 return false;
3856 return true;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003857 case NL80211_CMD_START_AP:
3858 /* SAE not supported yet */
3859 if (auth_type == NL80211_AUTHTYPE_SAE)
3860 return false;
Jouni Malinen63181062016-10-27 00:42:02 +03003861 /* FILS not supported yet */
3862 if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
3863 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
3864 auth_type == NL80211_AUTHTYPE_FILS_PK)
3865 return false;
Jouni Malinene39e5b52012-09-30 19:29:39 +03003866 return true;
3867 default:
3868 return false;
3869 }
3870}
3871
Johannes Berg88600202012-02-13 15:17:18 +01003872static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
3873{
3874 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3875 struct net_device *dev = info->user_ptr[1];
3876 struct wireless_dev *wdev = dev->ieee80211_ptr;
3877 struct cfg80211_ap_settings params;
3878 int err;
3879
3880 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
3881 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3882 return -EOPNOTSUPP;
3883
3884 if (!rdev->ops->start_ap)
3885 return -EOPNOTSUPP;
3886
3887 if (wdev->beacon_interval)
3888 return -EALREADY;
3889
3890 memset(&params, 0, sizeof(params));
3891
3892 /* these are required for START_AP */
3893 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
3894 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
3895 !info->attrs[NL80211_ATTR_BEACON_HEAD])
3896 return -EINVAL;
3897
Simon Wunderlicha1193be2013-06-14 14:15:19 +02003898 err = nl80211_parse_beacon(info->attrs, &params.beacon);
Johannes Berg88600202012-02-13 15:17:18 +01003899 if (err)
3900 return err;
3901
3902 params.beacon_interval =
3903 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
3904 params.dtim_period =
3905 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
3906
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05303907 err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
3908 params.beacon_interval);
Johannes Berg88600202012-02-13 15:17:18 +01003909 if (err)
3910 return err;
3911
3912 /*
3913 * In theory, some of these attributes should be required here
3914 * but since they were not used when the command was originally
3915 * added, keep them optional for old user space programs to let
3916 * them continue to work with drivers that do not need the
3917 * additional information -- drivers must check!
3918 */
3919 if (info->attrs[NL80211_ATTR_SSID]) {
3920 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3921 params.ssid_len =
3922 nla_len(info->attrs[NL80211_ATTR_SSID]);
3923 if (params.ssid_len == 0 ||
3924 params.ssid_len > IEEE80211_MAX_SSID_LEN)
3925 return -EINVAL;
3926 }
3927
3928 if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
3929 params.hidden_ssid = nla_get_u32(
3930 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
3931 if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
3932 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
3933 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
3934 return -EINVAL;
3935 }
3936
3937 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
3938
3939 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
3940 params.auth_type = nla_get_u32(
3941 info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03003942 if (!nl80211_valid_auth_type(rdev, params.auth_type,
3943 NL80211_CMD_START_AP))
Johannes Berg88600202012-02-13 15:17:18 +01003944 return -EINVAL;
3945 } else
3946 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
3947
3948 err = nl80211_crypto_settings(rdev, info, &params.crypto,
3949 NL80211_MAX_NR_CIPHER_SUITES);
3950 if (err)
3951 return err;
3952
Vasanthakumar Thiagarajan1b658f12012-03-02 15:50:02 +05303953 if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
3954 if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
3955 return -EOPNOTSUPP;
3956 params.inactivity_timeout = nla_get_u16(
3957 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
3958 }
3959
Johannes Berg53cabad2012-11-14 15:17:28 +01003960 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
3961 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3962 return -EINVAL;
3963 params.p2p_ctwindow =
3964 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
3965 if (params.p2p_ctwindow > 127)
3966 return -EINVAL;
3967 if (params.p2p_ctwindow != 0 &&
3968 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
3969 return -EINVAL;
3970 }
3971
3972 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
3973 u8 tmp;
3974
3975 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3976 return -EINVAL;
3977 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
3978 if (tmp > 1)
3979 return -EINVAL;
3980 params.p2p_opp_ps = tmp;
3981 if (params.p2p_opp_ps != 0 &&
3982 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
3983 return -EINVAL;
3984 }
3985
Johannes Bergaa430da2012-05-16 23:50:18 +02003986 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01003987 err = nl80211_parse_chandef(rdev, info, &params.chandef);
3988 if (err)
3989 return err;
3990 } else if (wdev->preset_chandef.chan) {
3991 params.chandef = wdev->preset_chandef;
Felix Fietkau46c1dd02012-06-19 02:50:57 +02003992 } else if (!nl80211_get_ap_channel(rdev, &params))
Johannes Bergaa430da2012-05-16 23:50:18 +02003993 return -EINVAL;
3994
Arik Nemtsov923b3522015-07-08 15:41:44 +03003995 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
3996 wdev->iftype))
Johannes Bergaa430da2012-05-16 23:50:18 +02003997 return -EINVAL;
3998
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05303999 if (info->attrs[NL80211_ATTR_TX_RATES]) {
4000 err = nl80211_parse_tx_bitrate_mask(info, &params.beacon_rate);
4001 if (err)
4002 return err;
4003
Johannes Berg8564e382016-09-19 09:44:44 +02004004 err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
4005 &params.beacon_rate);
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05304006 if (err)
4007 return err;
4008 }
4009
Eliad Peller18998c32014-09-10 14:07:34 +03004010 if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
4011 params.smps_mode =
4012 nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
4013 switch (params.smps_mode) {
4014 case NL80211_SMPS_OFF:
4015 break;
4016 case NL80211_SMPS_STATIC:
4017 if (!(rdev->wiphy.features &
4018 NL80211_FEATURE_STATIC_SMPS))
4019 return -EINVAL;
4020 break;
4021 case NL80211_SMPS_DYNAMIC:
4022 if (!(rdev->wiphy.features &
4023 NL80211_FEATURE_DYNAMIC_SMPS))
4024 return -EINVAL;
4025 break;
4026 default:
4027 return -EINVAL;
4028 }
4029 } else {
4030 params.smps_mode = NL80211_SMPS_OFF;
4031 }
4032
Purushottam Kushwaha6e8ef842016-07-05 13:44:51 +05304033 params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
4034 if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
4035 return -EOPNOTSUPP;
4036
Ola Olsson4baf6be2015-10-29 07:04:58 +01004037 if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
4038 params.acl = parse_acl_data(&rdev->wiphy, info);
4039 if (IS_ERR(params.acl))
4040 return PTR_ERR(params.acl);
4041 }
4042
Johannes Berg66cd7942017-02-07 22:40:44 +02004043 nl80211_calculate_ap_params(&params);
4044
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004045 wdev_lock(wdev);
Hila Gonene35e4d22012-06-27 17:19:42 +03004046 err = rdev_start_ap(rdev, dev, &params);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004047 if (!err) {
Johannes Berg683b6d32012-11-08 21:25:48 +01004048 wdev->preset_chandef = params.chandef;
Johannes Berg88600202012-02-13 15:17:18 +01004049 wdev->beacon_interval = params.beacon_interval;
Michal Kazior9e0e2962014-01-29 14:22:27 +01004050 wdev->chandef = params.chandef;
Antonio Quartulli06e191e2012-11-07 12:52:19 +01004051 wdev->ssid_len = params.ssid_len;
4052 memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
Felix Fietkau46c1dd02012-06-19 02:50:57 +02004053 }
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004054 wdev_unlock(wdev);
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +05304055
4056 kfree(params.acl);
4057
Johannes Berg56d18932011-05-09 18:41:15 +02004058 return err;
Johannes Berged1b6cc2007-12-19 02:03:32 +01004059}
4060
Johannes Berg88600202012-02-13 15:17:18 +01004061static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
4062{
4063 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4064 struct net_device *dev = info->user_ptr[1];
4065 struct wireless_dev *wdev = dev->ieee80211_ptr;
4066 struct cfg80211_beacon_data params;
4067 int err;
4068
4069 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4070 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
4071 return -EOPNOTSUPP;
4072
4073 if (!rdev->ops->change_beacon)
4074 return -EOPNOTSUPP;
4075
4076 if (!wdev->beacon_interval)
4077 return -EINVAL;
4078
Simon Wunderlicha1193be2013-06-14 14:15:19 +02004079 err = nl80211_parse_beacon(info->attrs, &params);
Johannes Berg88600202012-02-13 15:17:18 +01004080 if (err)
4081 return err;
4082
Simon Wunderlichc56589e2013-11-21 18:19:49 +01004083 wdev_lock(wdev);
4084 err = rdev_change_beacon(rdev, dev, &params);
4085 wdev_unlock(wdev);
4086
4087 return err;
Johannes Berg88600202012-02-13 15:17:18 +01004088}
4089
4090static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
Johannes Berged1b6cc2007-12-19 02:03:32 +01004091{
Johannes Berg4c476992010-10-04 21:36:35 +02004092 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4093 struct net_device *dev = info->user_ptr[1];
Johannes Berged1b6cc2007-12-19 02:03:32 +01004094
Ilan Peer7c8d5e02014-02-25 15:33:38 +02004095 return cfg80211_stop_ap(rdev, dev, false);
Johannes Berged1b6cc2007-12-19 02:03:32 +01004096}
4097
Johannes Berg5727ef12007-12-19 02:03:34 +01004098static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
4099 [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
4100 [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
4101 [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
Jouni Malinen0e467242009-05-11 21:57:55 +03004102 [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
Javier Cardonab39c48f2011-04-07 15:08:30 -07004103 [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
Johannes Bergd83023d2011-12-14 09:29:15 +01004104 [NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },
Johannes Berg5727ef12007-12-19 02:03:34 +01004105};
4106
Johannes Bergeccb8e82009-05-11 21:57:56 +03004107static int parse_station_flags(struct genl_info *info,
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004108 enum nl80211_iftype iftype,
Johannes Bergeccb8e82009-05-11 21:57:56 +03004109 struct station_parameters *params)
Johannes Berg5727ef12007-12-19 02:03:34 +01004110{
4111 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
Johannes Bergeccb8e82009-05-11 21:57:56 +03004112 struct nlattr *nla;
Johannes Berg5727ef12007-12-19 02:03:34 +01004113 int flag;
4114
Johannes Bergeccb8e82009-05-11 21:57:56 +03004115 /*
4116 * Try parsing the new attribute first so userspace
4117 * can specify both for older kernels.
4118 */
4119 nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
4120 if (nla) {
4121 struct nl80211_sta_flag_update *sta_flags;
Johannes Berg5727ef12007-12-19 02:03:34 +01004122
Johannes Bergeccb8e82009-05-11 21:57:56 +03004123 sta_flags = nla_data(nla);
4124 params->sta_flags_mask = sta_flags->mask;
4125 params->sta_flags_set = sta_flags->set;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004126 params->sta_flags_set &= params->sta_flags_mask;
Johannes Bergeccb8e82009-05-11 21:57:56 +03004127 if ((params->sta_flags_mask |
4128 params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
4129 return -EINVAL;
4130 return 0;
4131 }
4132
4133 /* if present, parse the old attribute */
4134
4135 nla = info->attrs[NL80211_ATTR_STA_FLAGS];
Johannes Berg5727ef12007-12-19 02:03:34 +01004136 if (!nla)
4137 return 0;
4138
4139 if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
4140 nla, sta_flags_policy))
4141 return -EINVAL;
4142
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004143 /*
4144 * Only allow certain flags for interface types so that
4145 * other attributes are silently ignored. Remember that
4146 * this is backward compatibility code with old userspace
4147 * and shouldn't be hit in other cases anyway.
4148 */
4149 switch (iftype) {
4150 case NL80211_IFTYPE_AP:
4151 case NL80211_IFTYPE_AP_VLAN:
4152 case NL80211_IFTYPE_P2P_GO:
4153 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4154 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4155 BIT(NL80211_STA_FLAG_WME) |
4156 BIT(NL80211_STA_FLAG_MFP);
4157 break;
4158 case NL80211_IFTYPE_P2P_CLIENT:
4159 case NL80211_IFTYPE_STATION:
4160 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
4161 BIT(NL80211_STA_FLAG_TDLS_PEER);
4162 break;
4163 case NL80211_IFTYPE_MESH_POINT:
4164 params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4165 BIT(NL80211_STA_FLAG_MFP) |
4166 BIT(NL80211_STA_FLAG_AUTHORIZED);
4167 default:
4168 return -EINVAL;
4169 }
Johannes Berg5727ef12007-12-19 02:03:34 +01004170
Johannes Berg3383b5a2012-05-10 20:14:43 +02004171 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
4172 if (flags[flag]) {
Johannes Bergeccb8e82009-05-11 21:57:56 +03004173 params->sta_flags_set |= (1<<flag);
Johannes Berg5727ef12007-12-19 02:03:34 +01004174
Johannes Berg3383b5a2012-05-10 20:14:43 +02004175 /* no longer support new API additions in old API */
4176 if (flag > NL80211_STA_FLAG_MAX_OLD_API)
4177 return -EINVAL;
4178 }
4179 }
4180
Johannes Berg5727ef12007-12-19 02:03:34 +01004181 return 0;
4182}
4183
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004184static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
4185 int attr)
4186{
4187 struct nlattr *rate;
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004188 u32 bitrate;
4189 u16 bitrate_compat;
Johannes Bergb51f3be2015-01-15 16:14:02 +01004190 enum nl80211_attrs rate_flg;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004191
4192 rate = nla_nest_start(msg, attr);
4193 if (!rate)
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004194 return false;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004195
4196 /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
4197 bitrate = cfg80211_calculate_bitrate(info);
Vladimir Kondratiev8eb41c82012-07-05 14:25:49 +03004198 /* report 16-bit bitrate only if we can */
4199 bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004200 if (bitrate > 0 &&
4201 nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
4202 return false;
4203 if (bitrate_compat > 0 &&
4204 nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
4205 return false;
4206
Johannes Bergb51f3be2015-01-15 16:14:02 +01004207 switch (info->bw) {
4208 case RATE_INFO_BW_5:
4209 rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
4210 break;
4211 case RATE_INFO_BW_10:
4212 rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
4213 break;
4214 default:
4215 WARN_ON(1);
4216 /* fall through */
4217 case RATE_INFO_BW_20:
4218 rate_flg = 0;
4219 break;
4220 case RATE_INFO_BW_40:
4221 rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
4222 break;
4223 case RATE_INFO_BW_80:
4224 rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
4225 break;
4226 case RATE_INFO_BW_160:
4227 rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
4228 break;
4229 }
4230
4231 if (rate_flg && nla_put_flag(msg, rate_flg))
4232 return false;
4233
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004234 if (info->flags & RATE_INFO_FLAGS_MCS) {
4235 if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
4236 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004237 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4238 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4239 return false;
4240 } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
4241 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
4242 return false;
4243 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
4244 return false;
Johannes Bergdb9c64c2012-11-09 14:56:41 +01004245 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
4246 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
4247 return false;
4248 }
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004249
4250 nla_nest_end(msg, rate);
4251 return true;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004252}
4253
Felix Fietkau119363c2013-04-22 16:29:30 +02004254static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
4255 int id)
4256{
4257 void *attr;
4258 int i = 0;
4259
4260 if (!mask)
4261 return true;
4262
4263 attr = nla_nest_start(msg, id);
4264 if (!attr)
4265 return false;
4266
4267 for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
4268 if (!(mask & BIT(i)))
4269 continue;
4270
4271 if (nla_put_u8(msg, i, signal[i]))
4272 return false;
4273 }
4274
4275 nla_nest_end(msg, attr);
4276
4277 return true;
4278}
4279
Johannes Bergcf5ead82014-11-14 17:14:00 +01004280static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
4281 u32 seq, int flags,
John W. Linville66266b32012-03-15 13:25:41 -04004282 struct cfg80211_registered_device *rdev,
4283 struct net_device *dev,
Johannes Berg98b62182009-12-23 13:15:44 +01004284 const u8 *mac_addr, struct station_info *sinfo)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004285{
4286 void *hdr;
Paul Stewartf4263c92011-03-31 09:25:41 -07004287 struct nlattr *sinfoattr, *bss_param;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004288
Johannes Bergcf5ead82014-11-14 17:14:00 +01004289 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004290 if (!hdr)
4291 return -1;
4292
David S. Miller9360ffd2012-03-29 04:41:26 -04004293 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
4294 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
4295 nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
4296 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02004297
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004298 sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
4299 if (!sinfoattr)
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004300 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004301
4302#define PUT_SINFO(attr, memb, type) do { \
Johannes Bergd686b922016-04-26 09:54:11 +02004303 BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
Mohammed Shafi Shajakhan739960f2016-04-07 19:59:34 +05304304 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
Johannes Berg319090b2014-11-17 14:08:11 +01004305 nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
4306 sinfo->memb)) \
4307 goto nla_put_failure; \
4308 } while (0)
Johannes Bergd686b922016-04-26 09:54:11 +02004309#define PUT_SINFO_U64(attr, memb) do { \
4310 if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
4311 nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
4312 sinfo->memb, NL80211_STA_INFO_PAD)) \
4313 goto nla_put_failure; \
4314 } while (0)
Johannes Berg319090b2014-11-17 14:08:11 +01004315
4316 PUT_SINFO(CONNECTED_TIME, connected_time, u32);
4317 PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
4318
4319 if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) |
4320 BIT(NL80211_STA_INFO_RX_BYTES64)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004321 nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004322 (u32)sinfo->rx_bytes))
4323 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004324
4325 if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) |
4326 BIT(NL80211_STA_INFO_TX_BYTES64)) &&
Vladimir Kondratiev42745e02013-02-04 13:53:11 +02004327 nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
4328 (u32)sinfo->tx_bytes))
4329 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004330
Johannes Bergd686b922016-04-26 09:54:11 +02004331 PUT_SINFO_U64(RX_BYTES64, rx_bytes);
4332 PUT_SINFO_U64(TX_BYTES64, tx_bytes);
Johannes Berg319090b2014-11-17 14:08:11 +01004333 PUT_SINFO(LLID, llid, u16);
4334 PUT_SINFO(PLID, plid, u16);
4335 PUT_SINFO(PLINK_STATE, plink_state, u8);
Johannes Bergd686b922016-04-26 09:54:11 +02004336 PUT_SINFO_U64(RX_DURATION, rx_duration);
Johannes Berg319090b2014-11-17 14:08:11 +01004337
John W. Linville66266b32012-03-15 13:25:41 -04004338 switch (rdev->wiphy.signal_type) {
4339 case CFG80211_SIGNAL_TYPE_MBM:
Johannes Berg319090b2014-11-17 14:08:11 +01004340 PUT_SINFO(SIGNAL, signal, u8);
4341 PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
John W. Linville66266b32012-03-15 13:25:41 -04004342 break;
4343 default:
4344 break;
4345 }
Johannes Berg319090b2014-11-17 14:08:11 +01004346 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004347 if (!nl80211_put_signal(msg, sinfo->chains,
4348 sinfo->chain_signal,
4349 NL80211_STA_INFO_CHAIN_SIGNAL))
4350 goto nla_put_failure;
4351 }
Johannes Berg319090b2014-11-17 14:08:11 +01004352 if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
Felix Fietkau119363c2013-04-22 16:29:30 +02004353 if (!nl80211_put_signal(msg, sinfo->chains,
4354 sinfo->chain_signal_avg,
4355 NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
4356 goto nla_put_failure;
4357 }
Johannes Berg319090b2014-11-17 14:08:11 +01004358 if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004359 if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
4360 NL80211_STA_INFO_TX_BITRATE))
Henning Rogge420e7fa2008-12-11 22:04:19 +01004361 goto nla_put_failure;
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004362 }
Johannes Berg319090b2014-11-17 14:08:11 +01004363 if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
Felix Fietkauc8dcfd82011-02-27 22:08:00 +01004364 if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
4365 NL80211_STA_INFO_RX_BITRATE))
4366 goto nla_put_failure;
Henning Rogge420e7fa2008-12-11 22:04:19 +01004367 }
Johannes Berg319090b2014-11-17 14:08:11 +01004368
4369 PUT_SINFO(RX_PACKETS, rx_packets, u32);
4370 PUT_SINFO(TX_PACKETS, tx_packets, u32);
4371 PUT_SINFO(TX_RETRIES, tx_retries, u32);
4372 PUT_SINFO(TX_FAILED, tx_failed, u32);
4373 PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
4374 PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
4375 PUT_SINFO(LOCAL_PM, local_pm, u32);
4376 PUT_SINFO(PEER_PM, peer_pm, u32);
4377 PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
4378
4379 if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) {
Paul Stewartf4263c92011-03-31 09:25:41 -07004380 bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
4381 if (!bss_param)
4382 goto nla_put_failure;
4383
David S. Miller9360ffd2012-03-29 04:41:26 -04004384 if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
4385 nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
4386 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
4387 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
4388 ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
4389 nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
4390 nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
4391 sinfo->bss_param.dtim_period) ||
4392 nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
4393 sinfo->bss_param.beacon_interval))
4394 goto nla_put_failure;
Paul Stewartf4263c92011-03-31 09:25:41 -07004395
4396 nla_nest_end(msg, bss_param);
4397 }
Johannes Berg319090b2014-11-17 14:08:11 +01004398 if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004399 nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
4400 sizeof(struct nl80211_sta_flag_update),
4401 &sinfo->sta_flags))
4402 goto nla_put_failure;
Johannes Berg319090b2014-11-17 14:08:11 +01004403
Johannes Bergd686b922016-04-26 09:54:11 +02004404 PUT_SINFO_U64(T_OFFSET, t_offset);
4405 PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
4406 PUT_SINFO_U64(BEACON_RX, rx_beacon);
Johannes Berga76b1942014-11-17 14:12:22 +01004407 PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
Johannes Berg319090b2014-11-17 14:08:11 +01004408
4409#undef PUT_SINFO
Johannes Bergd686b922016-04-26 09:54:11 +02004410#undef PUT_SINFO_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004411
4412 if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) {
4413 struct nlattr *tidsattr;
4414 int tid;
4415
4416 tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS);
4417 if (!tidsattr)
4418 goto nla_put_failure;
4419
4420 for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
4421 struct cfg80211_tid_stats *tidstats;
4422 struct nlattr *tidattr;
4423
4424 tidstats = &sinfo->pertid[tid];
4425
4426 if (!tidstats->filled)
4427 continue;
4428
4429 tidattr = nla_nest_start(msg, tid + 1);
4430 if (!tidattr)
4431 goto nla_put_failure;
4432
Johannes Bergd686b922016-04-26 09:54:11 +02004433#define PUT_TIDVAL_U64(attr, memb) do { \
Johannes Berg6de39802014-12-19 12:34:00 +01004434 if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
Johannes Bergd686b922016-04-26 09:54:11 +02004435 nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
4436 tidstats->memb, NL80211_TID_STATS_PAD)) \
Johannes Berg6de39802014-12-19 12:34:00 +01004437 goto nla_put_failure; \
4438 } while (0)
4439
Johannes Bergd686b922016-04-26 09:54:11 +02004440 PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
4441 PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
4442 PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
4443 PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
Johannes Berg6de39802014-12-19 12:34:00 +01004444
Johannes Bergd686b922016-04-26 09:54:11 +02004445#undef PUT_TIDVAL_U64
Johannes Berg6de39802014-12-19 12:34:00 +01004446 nla_nest_end(msg, tidattr);
4447 }
4448
4449 nla_nest_end(msg, tidsattr);
4450 }
4451
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004452 nla_nest_end(msg, sinfoattr);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004453
Johannes Berg319090b2014-11-17 14:08:11 +01004454 if (sinfo->assoc_req_ies_len &&
David S. Miller9360ffd2012-03-29 04:41:26 -04004455 nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
4456 sinfo->assoc_req_ies))
4457 goto nla_put_failure;
Jouni Malinen50d3dfb2011-08-08 12:11:52 +03004458
Johannes Berg053c0952015-01-16 22:09:00 +01004459 genlmsg_end(msg, hdr);
4460 return 0;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004461
4462 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07004463 genlmsg_cancel(msg, hdr);
4464 return -EMSGSIZE;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004465}
4466
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004467static int nl80211_dump_station(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004468 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004469{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004470 struct station_info sinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004471 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02004472 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004473 u8 mac_addr[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02004474 int sta_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004475 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004476
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004477 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02004478 if (err)
4479 return err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004480
Johannes Berg97990a02013-04-19 01:02:55 +02004481 if (!wdev->netdev) {
4482 err = -EINVAL;
4483 goto out_err;
4484 }
4485
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004486 if (!rdev->ops->dump_station) {
Jouni Malineneec60b02009-03-20 21:21:19 +02004487 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004488 goto out_err;
4489 }
4490
Johannes Bergbba95fe2008-07-29 13:22:51 +02004491 while (1) {
Jouni Malinenf612ced2011-08-11 11:46:22 +03004492 memset(&sinfo, 0, sizeof(sinfo));
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004493 err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
Hila Gonene35e4d22012-06-27 17:19:42 +03004494 mac_addr, &sinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02004495 if (err == -ENOENT)
4496 break;
4497 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01004498 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004499
Johannes Bergcf5ead82014-11-14 17:14:00 +01004500 if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004501 NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004502 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004503 rdev, wdev->netdev, mac_addr,
Johannes Bergbba95fe2008-07-29 13:22:51 +02004504 &sinfo) < 0)
4505 goto out;
4506
4507 sta_idx++;
4508 }
4509
Johannes Bergbba95fe2008-07-29 13:22:51 +02004510 out:
Johannes Berg97990a02013-04-19 01:02:55 +02004511 cb->args[2] = sta_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004512 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02004513 out_err:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08004514 nl80211_finish_wdev_dump(rdev);
Johannes Bergbba95fe2008-07-29 13:22:51 +02004515
4516 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004517}
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004518
Johannes Berg5727ef12007-12-19 02:03:34 +01004519static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
4520{
Johannes Berg4c476992010-10-04 21:36:35 +02004521 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4522 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004523 struct station_info sinfo;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004524 struct sk_buff *msg;
4525 u8 *mac_addr = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02004526 int err;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004527
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004528 memset(&sinfo, 0, sizeof(sinfo));
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004529
4530 if (!info->attrs[NL80211_ATTR_MAC])
4531 return -EINVAL;
4532
4533 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4534
Johannes Berg4c476992010-10-04 21:36:35 +02004535 if (!rdev->ops->get_station)
4536 return -EOPNOTSUPP;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004537
Hila Gonene35e4d22012-06-27 17:19:42 +03004538 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004539 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02004540 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004541
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07004542 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004543 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02004544 return -ENOMEM;
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004545
Johannes Bergcf5ead82014-11-14 17:14:00 +01004546 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
4547 info->snd_portid, info->snd_seq, 0,
John W. Linville66266b32012-03-15 13:25:41 -04004548 rdev, dev, mac_addr, &sinfo) < 0) {
Johannes Berg4c476992010-10-04 21:36:35 +02004549 nlmsg_free(msg);
4550 return -ENOBUFS;
4551 }
Johannes Bergfd5b74d2007-12-19 02:03:36 +01004552
Johannes Berg4c476992010-10-04 21:36:35 +02004553 return genlmsg_reply(msg, info);
Johannes Berg5727ef12007-12-19 02:03:34 +01004554}
4555
Johannes Berg77ee7c82013-02-15 00:48:33 +01004556int cfg80211_check_station_change(struct wiphy *wiphy,
4557 struct station_parameters *params,
4558 enum cfg80211_station_type statype)
4559{
Ayala Bekere4208422015-10-23 11:20:06 +03004560 if (params->listen_interval != -1 &&
4561 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004562 return -EINVAL;
Ayala Bekere4208422015-10-23 11:20:06 +03004563
Ayala Beker17b94242016-03-17 15:41:38 +02004564 if (params->support_p2p_ps != -1 &&
4565 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
4566 return -EINVAL;
4567
Arik Nemtsovc72e1142014-07-17 17:14:29 +03004568 if (params->aid &&
Ayala Bekere4208422015-10-23 11:20:06 +03004569 !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
4570 statype != CFG80211_STA_AP_CLIENT_UNASSOC)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004571 return -EINVAL;
4572
4573 /* When you run into this, adjust the code below for the new flag */
4574 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
4575
4576 switch (statype) {
Thomas Pederseneef941e2013-03-04 13:06:11 -08004577 case CFG80211_STA_MESH_PEER_KERNEL:
4578 case CFG80211_STA_MESH_PEER_USER:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004579 /*
4580 * No ignoring the TDLS flag here -- the userspace mesh
4581 * code doesn't have the bug of including TDLS in the
4582 * mask everywhere.
4583 */
4584 if (params->sta_flags_mask &
4585 ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4586 BIT(NL80211_STA_FLAG_MFP) |
4587 BIT(NL80211_STA_FLAG_AUTHORIZED)))
4588 return -EINVAL;
4589 break;
4590 case CFG80211_STA_TDLS_PEER_SETUP:
4591 case CFG80211_STA_TDLS_PEER_ACTIVE:
4592 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
4593 return -EINVAL;
4594 /* ignore since it can't change */
4595 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4596 break;
4597 default:
4598 /* disallow mesh-specific things */
4599 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
4600 return -EINVAL;
4601 if (params->local_pm)
4602 return -EINVAL;
4603 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4604 return -EINVAL;
4605 }
4606
4607 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4608 statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
4609 /* TDLS can't be set, ... */
4610 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
4611 return -EINVAL;
4612 /*
4613 * ... but don't bother the driver with it. This works around
4614 * a hostapd/wpa_supplicant issue -- it always includes the
4615 * TLDS_PEER flag in the mask even for AP mode.
4616 */
4617 params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
4618 }
4619
Ayala Beker47edb112015-09-21 15:49:53 +03004620 if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
4621 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004622 /* reject other things that can't change */
4623 if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
4624 return -EINVAL;
4625 if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
4626 return -EINVAL;
4627 if (params->supported_rates)
4628 return -EINVAL;
4629 if (params->ext_capab || params->ht_capa || params->vht_capa)
4630 return -EINVAL;
4631 }
4632
Ayala Beker47edb112015-09-21 15:49:53 +03004633 if (statype != CFG80211_STA_AP_CLIENT &&
4634 statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
Johannes Berg77ee7c82013-02-15 00:48:33 +01004635 if (params->vlan)
4636 return -EINVAL;
4637 }
4638
4639 switch (statype) {
4640 case CFG80211_STA_AP_MLME_CLIENT:
4641 /* Use this only for authorizing/unauthorizing a station */
4642 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
4643 return -EOPNOTSUPP;
4644 break;
4645 case CFG80211_STA_AP_CLIENT:
Ayala Beker47edb112015-09-21 15:49:53 +03004646 case CFG80211_STA_AP_CLIENT_UNASSOC:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004647 /* accept only the listed bits */
4648 if (params->sta_flags_mask &
4649 ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4650 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4651 BIT(NL80211_STA_FLAG_ASSOCIATED) |
4652 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
4653 BIT(NL80211_STA_FLAG_WME) |
4654 BIT(NL80211_STA_FLAG_MFP)))
4655 return -EINVAL;
4656
4657 /* but authenticated/associated only if driver handles it */
4658 if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
4659 params->sta_flags_mask &
4660 (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4661 BIT(NL80211_STA_FLAG_ASSOCIATED)))
4662 return -EINVAL;
4663 break;
4664 case CFG80211_STA_IBSS:
4665 case CFG80211_STA_AP_STA:
4666 /* reject any changes other than AUTHORIZED */
4667 if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
4668 return -EINVAL;
4669 break;
4670 case CFG80211_STA_TDLS_PEER_SETUP:
4671 /* reject any changes other than AUTHORIZED or WME */
4672 if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
4673 BIT(NL80211_STA_FLAG_WME)))
4674 return -EINVAL;
4675 /* force (at least) rates when authorizing */
4676 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
4677 !params->supported_rates)
4678 return -EINVAL;
4679 break;
4680 case CFG80211_STA_TDLS_PEER_ACTIVE:
4681 /* reject any changes */
4682 return -EINVAL;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004683 case CFG80211_STA_MESH_PEER_KERNEL:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004684 if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
4685 return -EINVAL;
4686 break;
Thomas Pederseneef941e2013-03-04 13:06:11 -08004687 case CFG80211_STA_MESH_PEER_USER:
Chun-Yeow Yeoh42925042015-04-18 01:30:02 +08004688 if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
4689 params->plink_action != NL80211_PLINK_ACTION_BLOCK)
Johannes Berg77ee7c82013-02-15 00:48:33 +01004690 return -EINVAL;
4691 break;
4692 }
4693
Beni Lev06f7c882016-07-19 19:28:56 +03004694 /*
4695 * Older kernel versions ignored this attribute entirely, so don't
4696 * reject attempts to update it but mark it as unused instead so the
4697 * driver won't look at the data.
4698 */
4699 if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
4700 statype != CFG80211_STA_TDLS_PEER_SETUP)
4701 params->opmode_notif_used = false;
4702
Johannes Berg77ee7c82013-02-15 00:48:33 +01004703 return 0;
4704}
4705EXPORT_SYMBOL(cfg80211_check_station_change);
4706
Johannes Berg5727ef12007-12-19 02:03:34 +01004707/*
Felix Fietkauc258d2d2009-11-11 17:23:31 +01004708 * Get vlan interface making sure it is running and on the right wiphy.
Johannes Berg5727ef12007-12-19 02:03:34 +01004709 */
Johannes Berg80b99892011-11-18 16:23:01 +01004710static struct net_device *get_vlan(struct genl_info *info,
4711 struct cfg80211_registered_device *rdev)
Johannes Berg5727ef12007-12-19 02:03:34 +01004712{
Johannes Berg463d0182009-07-14 00:33:35 +02004713 struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
Johannes Berg80b99892011-11-18 16:23:01 +01004714 struct net_device *v;
4715 int ret;
Johannes Berg5727ef12007-12-19 02:03:34 +01004716
Johannes Berg80b99892011-11-18 16:23:01 +01004717 if (!vlanattr)
4718 return NULL;
4719
4720 v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
4721 if (!v)
4722 return ERR_PTR(-ENODEV);
4723
4724 if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
4725 ret = -EINVAL;
4726 goto error;
Johannes Berg5727ef12007-12-19 02:03:34 +01004727 }
Johannes Berg80b99892011-11-18 16:23:01 +01004728
Johannes Berg77ee7c82013-02-15 00:48:33 +01004729 if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
4730 v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
4731 v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
4732 ret = -EINVAL;
4733 goto error;
4734 }
4735
Johannes Berg80b99892011-11-18 16:23:01 +01004736 if (!netif_running(v)) {
4737 ret = -ENETDOWN;
4738 goto error;
4739 }
4740
4741 return v;
4742 error:
4743 dev_put(v);
4744 return ERR_PTR(ret);
Johannes Berg5727ef12007-12-19 02:03:34 +01004745}
4746
Johannes Berg94e860f2014-01-20 23:58:15 +01004747static const struct nla_policy
4748nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
Jouni Malinendf881292013-02-14 21:10:54 +02004749 [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
4750 [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
4751};
4752
Johannes Bergff276692013-02-15 00:09:01 +01004753static int nl80211_parse_sta_wme(struct genl_info *info,
4754 struct station_parameters *params)
Jouni Malinendf881292013-02-14 21:10:54 +02004755{
Jouni Malinendf881292013-02-14 21:10:54 +02004756 struct nlattr *tb[NL80211_STA_WME_MAX + 1];
4757 struct nlattr *nla;
4758 int err;
4759
Jouni Malinendf881292013-02-14 21:10:54 +02004760 /* parse WME attributes if present */
4761 if (!info->attrs[NL80211_ATTR_STA_WME])
4762 return 0;
4763
4764 nla = info->attrs[NL80211_ATTR_STA_WME];
4765 err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
4766 nl80211_sta_wme_policy);
4767 if (err)
4768 return err;
4769
4770 if (tb[NL80211_STA_WME_UAPSD_QUEUES])
4771 params->uapsd_queues = nla_get_u8(
4772 tb[NL80211_STA_WME_UAPSD_QUEUES]);
4773 if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
4774 return -EINVAL;
4775
4776 if (tb[NL80211_STA_WME_MAX_SP])
4777 params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
4778
4779 if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
4780 return -EINVAL;
4781
4782 params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
4783
4784 return 0;
4785}
4786
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304787static int nl80211_parse_sta_channel_info(struct genl_info *info,
4788 struct station_parameters *params)
4789{
4790 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
4791 params->supported_channels =
4792 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4793 params->supported_channels_len =
4794 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
4795 /*
4796 * Need to include at least one (first channel, number of
4797 * channels) tuple for each subband, and must have proper
4798 * tuples for the rest of the data as well.
4799 */
4800 if (params->supported_channels_len < 2)
4801 return -EINVAL;
4802 if (params->supported_channels_len % 2)
4803 return -EINVAL;
4804 }
4805
4806 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
4807 params->supported_oper_classes =
4808 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4809 params->supported_oper_classes_len =
4810 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
4811 /*
4812 * The value of the Length field of the Supported Operating
4813 * Classes element is between 2 and 253.
4814 */
4815 if (params->supported_oper_classes_len < 2 ||
4816 params->supported_oper_classes_len > 253)
4817 return -EINVAL;
4818 }
4819 return 0;
4820}
4821
Johannes Bergff276692013-02-15 00:09:01 +01004822static int nl80211_set_station_tdls(struct genl_info *info,
4823 struct station_parameters *params)
4824{
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304825 int err;
Johannes Bergff276692013-02-15 00:09:01 +01004826 /* Dummy STA entry gets updated once the peer capabilities are known */
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03004827 if (info->attrs[NL80211_ATTR_PEER_AID])
4828 params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Johannes Bergff276692013-02-15 00:09:01 +01004829 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
4830 params->ht_capa =
4831 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
4832 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
4833 params->vht_capa =
4834 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
4835
Sunil Duttc01fc9a2013-10-09 20:45:21 +05304836 err = nl80211_parse_sta_channel_info(info, params);
4837 if (err)
4838 return err;
4839
Johannes Bergff276692013-02-15 00:09:01 +01004840 return nl80211_parse_sta_wme(info, params);
4841}
4842
Johannes Berg5727ef12007-12-19 02:03:34 +01004843static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
4844{
Johannes Berg4c476992010-10-04 21:36:35 +02004845 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02004846 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01004847 struct station_parameters params;
Johannes Berg77ee7c82013-02-15 00:48:33 +01004848 u8 *mac_addr;
4849 int err;
Johannes Berg5727ef12007-12-19 02:03:34 +01004850
4851 memset(&params, 0, sizeof(params));
4852
Johannes Berg77ee7c82013-02-15 00:48:33 +01004853 if (!rdev->ops->change_station)
4854 return -EOPNOTSUPP;
4855
Ayala Bekere4208422015-10-23 11:20:06 +03004856 /*
4857 * AID and listen_interval properties can be set only for unassociated
4858 * station. Include these parameters here and will check them in
4859 * cfg80211_check_station_change().
4860 */
Ayala Bekera9bc31e2015-11-26 16:26:12 +01004861 if (info->attrs[NL80211_ATTR_STA_AID])
4862 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Ayala Bekere4208422015-10-23 11:20:06 +03004863
4864 if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
4865 params.listen_interval =
4866 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
4867 else
4868 params.listen_interval = -1;
Johannes Berg5727ef12007-12-19 02:03:34 +01004869
Ayala Beker17b94242016-03-17 15:41:38 +02004870 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
4871 u8 tmp;
4872
4873 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
4874 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
4875 return -EINVAL;
4876
4877 params.support_p2p_ps = tmp;
4878 } else {
4879 params.support_p2p_ps = -1;
4880 }
4881
Johannes Berg5727ef12007-12-19 02:03:34 +01004882 if (!info->attrs[NL80211_ATTR_MAC])
4883 return -EINVAL;
4884
4885 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
4886
4887 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
4888 params.supported_rates =
4889 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4890 params.supported_rates_len =
4891 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
4892 }
4893
Jouni Malinen9d62a982013-02-14 21:10:13 +02004894 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
4895 params.capability =
4896 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
4897 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
4898 }
4899
4900 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
4901 params.ext_capab =
4902 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4903 params.ext_capab_len =
4904 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
4905 }
4906
Johannes Bergbdd3ae32012-01-02 13:30:03 +01004907 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01004908 return -EINVAL;
4909
Johannes Bergf8bacc22013-02-14 23:27:01 +01004910 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004911 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01004912 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
4913 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
4914 return -EINVAL;
4915 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01004916
Johannes Bergf8bacc22013-02-14 23:27:01 +01004917 if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
Javier Cardona9c3990a2011-05-03 16:57:11 -07004918 params.plink_state =
Johannes Bergf8bacc22013-02-14 23:27:01 +01004919 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
4920 if (params.plink_state >= NUM_NL80211_PLINK_STATES)
4921 return -EINVAL;
Masashi Honma7d27a0b2016-07-01 10:19:34 +09004922 if (info->attrs[NL80211_ATTR_MESH_PEER_AID]) {
4923 params.peer_aid = nla_get_u16(
4924 info->attrs[NL80211_ATTR_MESH_PEER_AID]);
4925 if (params.peer_aid > IEEE80211_MAX_AID)
4926 return -EINVAL;
4927 }
Johannes Bergf8bacc22013-02-14 23:27:01 +01004928 params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
4929 }
Javier Cardona9c3990a2011-05-03 16:57:11 -07004930
Marco Porsch3b1c5a52013-01-07 16:04:52 +01004931 if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
4932 enum nl80211_mesh_power_mode pm = nla_get_u32(
4933 info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
4934
4935 if (pm <= NL80211_MESH_POWER_UNKNOWN ||
4936 pm > NL80211_MESH_POWER_MAX)
4937 return -EINVAL;
4938
4939 params.local_pm = pm;
4940 }
4941
Beni Lev06f7c882016-07-19 19:28:56 +03004942 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
4943 params.opmode_notif_used = true;
4944 params.opmode_notif =
4945 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
4946 }
4947
Johannes Berg77ee7c82013-02-15 00:48:33 +01004948 /* Include parameters for TDLS peer (will check later) */
4949 err = nl80211_set_station_tdls(info, &params);
4950 if (err)
4951 return err;
4952
4953 params.vlan = get_vlan(info, rdev);
4954 if (IS_ERR(params.vlan))
4955 return PTR_ERR(params.vlan);
4956
Johannes Berga97f4422009-06-18 17:23:43 +02004957 switch (dev->ieee80211_ptr->iftype) {
4958 case NL80211_IFTYPE_AP:
4959 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg074ac8d2010-09-16 14:58:22 +02004960 case NL80211_IFTYPE_P2P_GO:
Johannes Berg074ac8d2010-09-16 14:58:22 +02004961 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berga97f4422009-06-18 17:23:43 +02004962 case NL80211_IFTYPE_STATION:
Antonio Quartulli267335d2012-01-31 20:25:47 +01004963 case NL80211_IFTYPE_ADHOC:
Johannes Berga97f4422009-06-18 17:23:43 +02004964 case NL80211_IFTYPE_MESH_POINT:
Johannes Berga97f4422009-06-18 17:23:43 +02004965 break;
4966 default:
Johannes Berg77ee7c82013-02-15 00:48:33 +01004967 err = -EOPNOTSUPP;
4968 goto out_put_vlan;
Johannes Berg034d6552009-05-27 10:35:29 +02004969 }
4970
Johannes Berg77ee7c82013-02-15 00:48:33 +01004971 /* driver will call cfg80211_check_station_change() */
Hila Gonene35e4d22012-06-27 17:19:42 +03004972 err = rdev_change_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01004973
Johannes Berg77ee7c82013-02-15 00:48:33 +01004974 out_put_vlan:
Johannes Berg5727ef12007-12-19 02:03:34 +01004975 if (params.vlan)
4976 dev_put(params.vlan);
Johannes Berg3b858752009-03-12 09:55:09 +01004977
Johannes Berg5727ef12007-12-19 02:03:34 +01004978 return err;
4979}
4980
4981static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
4982{
Johannes Berg4c476992010-10-04 21:36:35 +02004983 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg5727ef12007-12-19 02:03:34 +01004984 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02004985 struct net_device *dev = info->user_ptr[1];
Johannes Berg5727ef12007-12-19 02:03:34 +01004986 struct station_parameters params;
4987 u8 *mac_addr = NULL;
Johannes Bergbda95eb2015-11-26 16:26:13 +01004988 u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
4989 BIT(NL80211_STA_FLAG_ASSOCIATED);
Johannes Berg5727ef12007-12-19 02:03:34 +01004990
4991 memset(&params, 0, sizeof(params));
4992
Johannes Berg984c3112013-02-14 23:43:25 +01004993 if (!rdev->ops->add_station)
4994 return -EOPNOTSUPP;
4995
Johannes Berg5727ef12007-12-19 02:03:34 +01004996 if (!info->attrs[NL80211_ATTR_MAC])
4997 return -EINVAL;
4998
Johannes Berg5727ef12007-12-19 02:03:34 +01004999 if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
5000 return -EINVAL;
5001
5002 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
5003 return -EINVAL;
5004
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03005005 if (!info->attrs[NL80211_ATTR_STA_AID] &&
5006 !info->attrs[NL80211_ATTR_PEER_AID])
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02005007 return -EINVAL;
5008
Johannes Berg5727ef12007-12-19 02:03:34 +01005009 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
5010 params.supported_rates =
5011 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5012 params.supported_rates_len =
5013 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
5014 params.listen_interval =
5015 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
Johannes Berg51b50fb2009-05-24 16:42:30 +02005016
Ayala Beker17b94242016-03-17 15:41:38 +02005017 if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
5018 u8 tmp;
5019
5020 tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
5021 if (tmp >= NUM_NL80211_P2P_PS_STATUS)
5022 return -EINVAL;
5023
5024 params.support_p2p_ps = tmp;
5025 } else {
5026 /*
5027 * if not specified, assume it's supported for P2P GO interface,
5028 * and is NOT supported for AP interface
5029 */
5030 params.support_p2p_ps =
5031 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO;
5032 }
5033
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005034 if (info->attrs[NL80211_ATTR_PEER_AID])
Jouni Malinen5e4b6f52013-05-16 20:11:08 +03005035 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005036 else
5037 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
Thadeu Lima de Souza Cascardo0e956c12010-02-12 12:34:50 -02005038 if (!params.aid || params.aid > IEEE80211_MAX_AID)
5039 return -EINVAL;
Johannes Berg51b50fb2009-05-24 16:42:30 +02005040
Jouni Malinen9d62a982013-02-14 21:10:13 +02005041 if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
5042 params.capability =
5043 nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
5044 params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
5045 }
5046
5047 if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
5048 params.ext_capab =
5049 nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5050 params.ext_capab_len =
5051 nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
5052 }
5053
Jouni Malinen36aedc92008-08-25 11:58:58 +03005054 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
5055 params.ht_capa =
5056 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005057
Mahesh Palivelaf461be3e2012-10-11 08:04:52 +00005058 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
5059 params.vht_capa =
5060 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
5061
Marek Kwaczynski60f4a7b2013-12-03 10:04:59 +01005062 if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
5063 params.opmode_notif_used = true;
5064 params.opmode_notif =
5065 nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
5066 }
5067
Johannes Bergf8bacc22013-02-14 23:27:01 +01005068 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
Javier Cardona96b78df2011-04-07 15:08:33 -07005069 params.plink_action =
Johannes Bergf8bacc22013-02-14 23:27:01 +01005070 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
5071 if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
5072 return -EINVAL;
5073 }
Javier Cardona96b78df2011-04-07 15:08:33 -07005074
Sunil Duttc01fc9a2013-10-09 20:45:21 +05305075 err = nl80211_parse_sta_channel_info(info, &params);
5076 if (err)
5077 return err;
5078
Johannes Bergff276692013-02-15 00:09:01 +01005079 err = nl80211_parse_sta_wme(info, &params);
5080 if (err)
5081 return err;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005082
Johannes Bergbdd3ae32012-01-02 13:30:03 +01005083 if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
Johannes Berg5727ef12007-12-19 02:03:34 +01005084 return -EINVAL;
5085
Johannes Berg496fcc22015-03-12 08:53:27 +02005086 /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
5087 * as userspace might just pass through the capabilities from the IEs
5088 * directly, rather than enforcing this restriction and returning an
5089 * error in this case.
5090 */
5091 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
5092 params.ht_capa = NULL;
5093 params.vht_capa = NULL;
5094 }
5095
Johannes Berg77ee7c82013-02-15 00:48:33 +01005096 /* When you run into this, adjust the code below for the new flag */
5097 BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
5098
Johannes Bergbdd90d52011-12-14 12:20:27 +01005099 switch (dev->ieee80211_ptr->iftype) {
5100 case NL80211_IFTYPE_AP:
5101 case NL80211_IFTYPE_AP_VLAN:
5102 case NL80211_IFTYPE_P2P_GO:
Johannes Berg984c3112013-02-14 23:43:25 +01005103 /* ignore WME attributes if iface/sta is not capable */
5104 if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
5105 !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
5106 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005107
Johannes Bergbdd90d52011-12-14 12:20:27 +01005108 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005109 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5110 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005111 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005112 /* but don't bother the driver with it */
5113 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
Eliad Pellerc75786c2011-08-23 14:37:46 +03005114
Johannes Bergd582cff2012-10-26 17:53:44 +02005115 /* allow authenticated/associated only if driver handles it */
5116 if (!(rdev->wiphy.features &
5117 NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
Johannes Bergbda95eb2015-11-26 16:26:13 +01005118 params.sta_flags_mask & auth_assoc)
Johannes Bergd582cff2012-10-26 17:53:44 +02005119 return -EINVAL;
5120
Johannes Bergbda95eb2015-11-26 16:26:13 +01005121 /* Older userspace, or userspace wanting to be compatible with
5122 * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
5123 * and assoc flags in the mask, but assumes the station will be
5124 * added as associated anyway since this was the required driver
5125 * behaviour before NL80211_FEATURE_FULL_AP_CLIENT_STATE was
5126 * introduced.
5127 * In order to not bother drivers with this quirk in the API
5128 * set the flags in both the mask and set for new stations in
5129 * this case.
5130 */
5131 if (!(params.sta_flags_mask & auth_assoc)) {
5132 params.sta_flags_mask |= auth_assoc;
5133 params.sta_flags_set |= auth_assoc;
5134 }
5135
Johannes Bergbdd90d52011-12-14 12:20:27 +01005136 /* must be last in here for error handling */
5137 params.vlan = get_vlan(info, rdev);
5138 if (IS_ERR(params.vlan))
5139 return PTR_ERR(params.vlan);
5140 break;
5141 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg984c3112013-02-14 23:43:25 +01005142 /* ignore uAPSD data */
5143 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5144
Johannes Bergd582cff2012-10-26 17:53:44 +02005145 /* associated is disallowed */
5146 if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
5147 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005148 /* TDLS peers cannot be added */
Jouni Malinen3d124ea2013-05-27 18:24:02 +03005149 if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
5150 info->attrs[NL80211_ATTR_PEER_AID])
Johannes Berg4319e192011-09-07 11:50:48 +02005151 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005152 break;
5153 case NL80211_IFTYPE_STATION:
Johannes Berg93d08f02013-03-04 09:29:46 +01005154 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg984c3112013-02-14 23:43:25 +01005155 /* ignore uAPSD data */
5156 params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
5157
Johannes Berg77ee7c82013-02-15 00:48:33 +01005158 /* these are disallowed */
5159 if (params.sta_flags_mask &
5160 (BIT(NL80211_STA_FLAG_ASSOCIATED) |
5161 BIT(NL80211_STA_FLAG_AUTHENTICATED)))
Johannes Bergd582cff2012-10-26 17:53:44 +02005162 return -EINVAL;
Johannes Bergbdd90d52011-12-14 12:20:27 +01005163 /* Only TDLS peers can be added */
5164 if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
5165 return -EINVAL;
5166 /* Can only add if TDLS ... */
5167 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
5168 return -EOPNOTSUPP;
5169 /* ... with external setup is supported */
5170 if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
5171 return -EOPNOTSUPP;
Johannes Berg77ee7c82013-02-15 00:48:33 +01005172 /*
5173 * Older wpa_supplicant versions always mark the TDLS peer
5174 * as authorized, but it shouldn't yet be.
5175 */
5176 params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
Johannes Bergbdd90d52011-12-14 12:20:27 +01005177 break;
5178 default:
5179 return -EOPNOTSUPP;
Eliad Pellerc75786c2011-08-23 14:37:46 +03005180 }
5181
Johannes Bergbdd90d52011-12-14 12:20:27 +01005182 /* be aware of params.vlan when changing code here */
Johannes Berg5727ef12007-12-19 02:03:34 +01005183
Hila Gonene35e4d22012-06-27 17:19:42 +03005184 err = rdev_add_station(rdev, dev, mac_addr, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005185
Johannes Berg5727ef12007-12-19 02:03:34 +01005186 if (params.vlan)
5187 dev_put(params.vlan);
Johannes Berg5727ef12007-12-19 02:03:34 +01005188 return err;
5189}
5190
5191static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
5192{
Johannes Berg4c476992010-10-04 21:36:35 +02005193 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5194 struct net_device *dev = info->user_ptr[1];
Jouni Malinen89c771e2014-10-10 20:52:40 +03005195 struct station_del_parameters params;
5196
5197 memset(&params, 0, sizeof(params));
Johannes Berg5727ef12007-12-19 02:03:34 +01005198
5199 if (info->attrs[NL80211_ATTR_MAC])
Jouni Malinen89c771e2014-10-10 20:52:40 +03005200 params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg5727ef12007-12-19 02:03:34 +01005201
Johannes Berge80cf852009-05-11 14:43:13 +02005202 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Marco Porschd5d9de02010-03-30 10:00:16 +02005203 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
Johannes Berg074ac8d2010-09-16 14:58:22 +02005204 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
Johannes Berg4c476992010-10-04 21:36:35 +02005205 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5206 return -EINVAL;
Johannes Berge80cf852009-05-11 14:43:13 +02005207
Johannes Berg4c476992010-10-04 21:36:35 +02005208 if (!rdev->ops->del_station)
5209 return -EOPNOTSUPP;
Johannes Berg5727ef12007-12-19 02:03:34 +01005210
Jouni Malinen98856862014-10-20 13:20:45 +03005211 if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
5212 params.subtype =
5213 nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
5214 if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
5215 params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
5216 return -EINVAL;
5217 } else {
5218 /* Default to Deauthentication frame */
5219 params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
5220 }
5221
5222 if (info->attrs[NL80211_ATTR_REASON_CODE]) {
5223 params.reason_code =
5224 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
5225 if (params.reason_code == 0)
5226 return -EINVAL; /* 0 is reserved */
5227 } else {
5228 /* Default to reason code 2 */
5229 params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
5230 }
5231
Jouni Malinen89c771e2014-10-10 20:52:40 +03005232 return rdev_del_station(rdev, dev, &params);
Johannes Berg5727ef12007-12-19 02:03:34 +01005233}
5234
Eric W. Biederman15e47302012-09-07 20:12:54 +00005235static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005236 int flags, struct net_device *dev,
5237 u8 *dst, u8 *next_hop,
5238 struct mpath_info *pinfo)
5239{
5240 void *hdr;
5241 struct nlattr *pinfoattr;
5242
Henning Rogge1ef4c852014-11-04 16:14:58 +01005243 hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005244 if (!hdr)
5245 return -1;
5246
David S. Miller9360ffd2012-03-29 04:41:26 -04005247 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5248 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
5249 nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
5250 nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
5251 goto nla_put_failure;
Johannes Bergf5ea9122009-08-07 16:17:38 +02005252
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005253 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
5254 if (!pinfoattr)
5255 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005256 if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
5257 nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
5258 pinfo->frame_qlen))
5259 goto nla_put_failure;
5260 if (((pinfo->filled & MPATH_INFO_SN) &&
5261 nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
5262 ((pinfo->filled & MPATH_INFO_METRIC) &&
5263 nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
5264 pinfo->metric)) ||
5265 ((pinfo->filled & MPATH_INFO_EXPTIME) &&
5266 nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
5267 pinfo->exptime)) ||
5268 ((pinfo->filled & MPATH_INFO_FLAGS) &&
5269 nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
5270 pinfo->flags)) ||
5271 ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
5272 nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
5273 pinfo->discovery_timeout)) ||
5274 ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
5275 nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
5276 pinfo->discovery_retries)))
5277 goto nla_put_failure;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005278
5279 nla_nest_end(msg, pinfoattr);
5280
Johannes Berg053c0952015-01-16 22:09:00 +01005281 genlmsg_end(msg, hdr);
5282 return 0;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005283
5284 nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07005285 genlmsg_cancel(msg, hdr);
5286 return -EMSGSIZE;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005287}
5288
5289static int nl80211_dump_mpath(struct sk_buff *skb,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005290 struct netlink_callback *cb)
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005291{
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005292 struct mpath_info pinfo;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005293 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02005294 struct wireless_dev *wdev;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005295 u8 dst[ETH_ALEN];
5296 u8 next_hop[ETH_ALEN];
Johannes Berg97990a02013-04-19 01:02:55 +02005297 int path_idx = cb->args[2];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005298 int err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005299
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005300 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02005301 if (err)
5302 return err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005303
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005304 if (!rdev->ops->dump_mpath) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005305 err = -EOPNOTSUPP;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005306 goto out_err;
5307 }
5308
Johannes Berg97990a02013-04-19 01:02:55 +02005309 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
Jouni Malineneec60b02009-03-20 21:21:19 +02005310 err = -EOPNOTSUPP;
Roel Kluin0448b5f2009-08-22 21:15:49 +02005311 goto out_err;
Jouni Malineneec60b02009-03-20 21:21:19 +02005312 }
5313
Johannes Bergbba95fe2008-07-29 13:22:51 +02005314 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005315 err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
Johannes Berg97990a02013-04-19 01:02:55 +02005316 next_hop, &pinfo);
Johannes Bergbba95fe2008-07-29 13:22:51 +02005317 if (err == -ENOENT)
5318 break;
5319 if (err)
Johannes Berg3b858752009-03-12 09:55:09 +01005320 goto out_err;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005321
Eric W. Biederman15e47302012-09-07 20:12:54 +00005322 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005323 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg97990a02013-04-19 01:02:55 +02005324 wdev->netdev, dst, next_hop,
Johannes Bergbba95fe2008-07-29 13:22:51 +02005325 &pinfo) < 0)
5326 goto out;
5327
5328 path_idx++;
5329 }
5330
Johannes Bergbba95fe2008-07-29 13:22:51 +02005331 out:
Johannes Berg97990a02013-04-19 01:02:55 +02005332 cb->args[2] = path_idx;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005333 err = skb->len;
Johannes Bergbba95fe2008-07-29 13:22:51 +02005334 out_err:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08005335 nl80211_finish_wdev_dump(rdev);
Johannes Bergbba95fe2008-07-29 13:22:51 +02005336 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005337}
5338
5339static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
5340{
Johannes Berg4c476992010-10-04 21:36:35 +02005341 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005342 int err;
Johannes Berg4c476992010-10-04 21:36:35 +02005343 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005344 struct mpath_info pinfo;
5345 struct sk_buff *msg;
5346 u8 *dst = NULL;
5347 u8 next_hop[ETH_ALEN];
5348
5349 memset(&pinfo, 0, sizeof(pinfo));
5350
5351 if (!info->attrs[NL80211_ATTR_MAC])
5352 return -EINVAL;
5353
5354 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5355
Johannes Berg4c476992010-10-04 21:36:35 +02005356 if (!rdev->ops->get_mpath)
5357 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005358
Johannes Berg4c476992010-10-04 21:36:35 +02005359 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5360 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005361
Hila Gonene35e4d22012-06-27 17:19:42 +03005362 err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005363 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005364 return err;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005365
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005366 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005367 if (!msg)
Johannes Berg4c476992010-10-04 21:36:35 +02005368 return -ENOMEM;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005369
Eric W. Biederman15e47302012-09-07 20:12:54 +00005370 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg4c476992010-10-04 21:36:35 +02005371 dev, dst, next_hop, &pinfo) < 0) {
5372 nlmsg_free(msg);
5373 return -ENOBUFS;
5374 }
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005375
Johannes Berg4c476992010-10-04 21:36:35 +02005376 return genlmsg_reply(msg, info);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005377}
5378
5379static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
5380{
Johannes Berg4c476992010-10-04 21:36:35 +02005381 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5382 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005383 u8 *dst = NULL;
5384 u8 *next_hop = NULL;
5385
5386 if (!info->attrs[NL80211_ATTR_MAC])
5387 return -EINVAL;
5388
5389 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5390 return -EINVAL;
5391
5392 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5393 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5394
Johannes Berg4c476992010-10-04 21:36:35 +02005395 if (!rdev->ops->change_mpath)
5396 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005397
Johannes Berg4c476992010-10-04 21:36:35 +02005398 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5399 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005400
Hila Gonene35e4d22012-06-27 17:19:42 +03005401 return rdev_change_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005402}
Johannes Berg4c476992010-10-04 21:36:35 +02005403
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005404static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
5405{
Johannes Berg4c476992010-10-04 21:36:35 +02005406 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5407 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005408 u8 *dst = NULL;
5409 u8 *next_hop = NULL;
5410
5411 if (!info->attrs[NL80211_ATTR_MAC])
5412 return -EINVAL;
5413
5414 if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
5415 return -EINVAL;
5416
5417 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5418 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
5419
Johannes Berg4c476992010-10-04 21:36:35 +02005420 if (!rdev->ops->add_mpath)
5421 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005422
Johannes Berg4c476992010-10-04 21:36:35 +02005423 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5424 return -EOPNOTSUPP;
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005425
Hila Gonene35e4d22012-06-27 17:19:42 +03005426 return rdev_add_mpath(rdev, dev, dst, next_hop);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005427}
5428
5429static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
5430{
Johannes Berg4c476992010-10-04 21:36:35 +02005431 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5432 struct net_device *dev = info->user_ptr[1];
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005433 u8 *dst = NULL;
5434
5435 if (info->attrs[NL80211_ATTR_MAC])
5436 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5437
Johannes Berg4c476992010-10-04 21:36:35 +02005438 if (!rdev->ops->del_mpath)
5439 return -EOPNOTSUPP;
Johannes Berg3b858752009-03-12 09:55:09 +01005440
Hila Gonene35e4d22012-06-27 17:19:42 +03005441 return rdev_del_mpath(rdev, dev, dst);
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +01005442}
5443
Henning Rogge66be7d22014-09-12 08:58:49 +02005444static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
5445{
5446 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5447 int err;
5448 struct net_device *dev = info->user_ptr[1];
5449 struct mpath_info pinfo;
5450 struct sk_buff *msg;
5451 u8 *dst = NULL;
5452 u8 mpp[ETH_ALEN];
5453
5454 memset(&pinfo, 0, sizeof(pinfo));
5455
5456 if (!info->attrs[NL80211_ATTR_MAC])
5457 return -EINVAL;
5458
5459 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
5460
5461 if (!rdev->ops->get_mpp)
5462 return -EOPNOTSUPP;
5463
5464 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
5465 return -EOPNOTSUPP;
5466
5467 err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
5468 if (err)
5469 return err;
5470
5471 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5472 if (!msg)
5473 return -ENOMEM;
5474
5475 if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
5476 dev, dst, mpp, &pinfo) < 0) {
5477 nlmsg_free(msg);
5478 return -ENOBUFS;
5479 }
5480
5481 return genlmsg_reply(msg, info);
5482}
5483
5484static int nl80211_dump_mpp(struct sk_buff *skb,
5485 struct netlink_callback *cb)
5486{
5487 struct mpath_info pinfo;
5488 struct cfg80211_registered_device *rdev;
5489 struct wireless_dev *wdev;
5490 u8 dst[ETH_ALEN];
5491 u8 mpp[ETH_ALEN];
5492 int path_idx = cb->args[2];
5493 int err;
5494
5495 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
5496 if (err)
5497 return err;
5498
5499 if (!rdev->ops->dump_mpp) {
5500 err = -EOPNOTSUPP;
5501 goto out_err;
5502 }
5503
5504 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
5505 err = -EOPNOTSUPP;
5506 goto out_err;
5507 }
5508
5509 while (1) {
5510 err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
5511 mpp, &pinfo);
5512 if (err == -ENOENT)
5513 break;
5514 if (err)
5515 goto out_err;
5516
5517 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
5518 cb->nlh->nlmsg_seq, NLM_F_MULTI,
5519 wdev->netdev, dst, mpp,
5520 &pinfo) < 0)
5521 goto out;
5522
5523 path_idx++;
5524 }
5525
5526 out:
5527 cb->args[2] = path_idx;
5528 err = skb->len;
5529 out_err:
5530 nl80211_finish_wdev_dump(rdev);
5531 return err;
5532}
5533
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005534static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
5535{
Johannes Berg4c476992010-10-04 21:36:35 +02005536 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5537 struct net_device *dev = info->user_ptr[1];
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005538 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005539 struct bss_parameters params;
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005540 int err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005541
5542 memset(&params, 0, sizeof(params));
5543 /* default to not changing parameters */
5544 params.use_cts_prot = -1;
5545 params.use_short_preamble = -1;
5546 params.use_short_slot_time = -1;
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005547 params.ap_isolate = -1;
Helmut Schaa50b12f52010-11-19 12:40:25 +01005548 params.ht_opmode = -1;
Johannes Berg53cabad2012-11-14 15:17:28 +01005549 params.p2p_ctwindow = -1;
5550 params.p2p_opp_ps = -1;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005551
5552 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
5553 params.use_cts_prot =
5554 nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
5555 if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
5556 params.use_short_preamble =
5557 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
5558 if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
5559 params.use_short_slot_time =
5560 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
Jouni Malinen90c97a02008-10-30 16:59:22 +02005561 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
5562 params.basic_rates =
5563 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5564 params.basic_rates_len =
5565 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
5566 }
Felix Fietkaufd8aaaf2010-04-27 01:23:35 +02005567 if (info->attrs[NL80211_ATTR_AP_ISOLATE])
5568 params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
Helmut Schaa50b12f52010-11-19 12:40:25 +01005569 if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
5570 params.ht_opmode =
5571 nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005572
Johannes Berg53cabad2012-11-14 15:17:28 +01005573 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
5574 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5575 return -EINVAL;
5576 params.p2p_ctwindow =
5577 nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
5578 if (params.p2p_ctwindow < 0)
5579 return -EINVAL;
5580 if (params.p2p_ctwindow != 0 &&
5581 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
5582 return -EINVAL;
5583 }
5584
5585 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
5586 u8 tmp;
5587
5588 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5589 return -EINVAL;
5590 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
5591 if (tmp > 1)
5592 return -EINVAL;
5593 params.p2p_opp_ps = tmp;
5594 if (params.p2p_opp_ps &&
5595 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
5596 return -EINVAL;
5597 }
5598
Johannes Berg4c476992010-10-04 21:36:35 +02005599 if (!rdev->ops->change_bss)
5600 return -EOPNOTSUPP;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005601
Johannes Berg074ac8d2010-09-16 14:58:22 +02005602 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
Johannes Berg4c476992010-10-04 21:36:35 +02005603 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
5604 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02005605
Simon Wunderlichc56589e2013-11-21 18:19:49 +01005606 wdev_lock(wdev);
5607 err = rdev_change_bss(rdev, dev, &params);
5608 wdev_unlock(wdev);
5609
5610 return err;
Jouni Malinen9f1ba902008-08-07 20:07:01 +03005611}
5612
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005613static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
5614{
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005615 char *data = NULL;
Ilan peer05050752015-03-04 00:32:06 -05005616 bool is_indoor;
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005617 enum nl80211_user_reg_hint_type user_reg_hint_type;
Ilan peer05050752015-03-04 00:32:06 -05005618 u32 owner_nlportid;
5619
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005620 /*
5621 * You should only get this when cfg80211 hasn't yet initialized
5622 * completely when built-in to the kernel right between the time
5623 * window between nl80211_init() and regulatory_init(), if that is
5624 * even possible.
5625 */
Johannes Berg458f4f92012-12-06 15:47:38 +01005626 if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
Luis R. Rodriguezfe33eb32009-02-21 00:04:30 -05005627 return -EINPROGRESS;
Luis R. Rodriguez80778f12009-02-21 00:04:22 -05005628
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005629 if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
5630 user_reg_hint_type =
5631 nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
5632 else
5633 user_reg_hint_type = NL80211_USER_REG_HINT_USER;
5634
5635 switch (user_reg_hint_type) {
5636 case NL80211_USER_REG_HINT_USER:
5637 case NL80211_USER_REG_HINT_CELL_BASE:
Ilan Peer52616f22014-02-25 16:26:00 +02005638 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
5639 return -EINVAL;
5640
5641 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
5642 return regulatory_hint_user(data, user_reg_hint_type);
5643 case NL80211_USER_REG_HINT_INDOOR:
Ilan peer05050752015-03-04 00:32:06 -05005644 if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
5645 owner_nlportid = info->snd_portid;
5646 is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
5647 } else {
5648 owner_nlportid = 0;
5649 is_indoor = true;
5650 }
5651
5652 return regulatory_hint_indoor(is_indoor, owner_nlportid);
Luis R. Rodriguez57b5ce02012-07-12 11:49:18 -07005653 default:
5654 return -EINVAL;
5655 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07005656}
5657
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005658static int nl80211_get_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01005659 struct genl_info *info)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005660{
Johannes Berg4c476992010-10-04 21:36:35 +02005661 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02005662 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01005663 struct wireless_dev *wdev = dev->ieee80211_ptr;
5664 struct mesh_config cur_params;
5665 int err = 0;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005666 void *hdr;
5667 struct nlattr *pinfoattr;
5668 struct sk_buff *msg;
5669
Johannes Berg29cbe682010-12-03 09:20:44 +01005670 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
5671 return -EOPNOTSUPP;
5672
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005673 if (!rdev->ops->get_mesh_config)
Johannes Berg4c476992010-10-04 21:36:35 +02005674 return -EOPNOTSUPP;
Jouni Malinenf3f92582009-03-20 17:57:36 +02005675
Johannes Berg29cbe682010-12-03 09:20:44 +01005676 wdev_lock(wdev);
5677 /* If not connected, get default parameters */
5678 if (!wdev->mesh_id_len)
5679 memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
5680 else
Hila Gonene35e4d22012-06-27 17:19:42 +03005681 err = rdev_get_mesh_config(rdev, dev, &cur_params);
Johannes Berg29cbe682010-12-03 09:20:44 +01005682 wdev_unlock(wdev);
5683
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005684 if (err)
Johannes Berg4c476992010-10-04 21:36:35 +02005685 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005686
5687 /* Draw up a netlink message to send back */
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -07005688 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02005689 if (!msg)
5690 return -ENOMEM;
Eric W. Biederman15e47302012-09-07 20:12:54 +00005691 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005692 NL80211_CMD_GET_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005693 if (!hdr)
Julia Lawallefe1cf02011-01-28 15:17:11 +01005694 goto out;
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005695 pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005696 if (!pinfoattr)
5697 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04005698 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
5699 nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
5700 cur_params.dot11MeshRetryTimeout) ||
5701 nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
5702 cur_params.dot11MeshConfirmTimeout) ||
5703 nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
5704 cur_params.dot11MeshHoldingTimeout) ||
5705 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
5706 cur_params.dot11MeshMaxPeerLinks) ||
5707 nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
5708 cur_params.dot11MeshMaxRetries) ||
5709 nla_put_u8(msg, NL80211_MESHCONF_TTL,
5710 cur_params.dot11MeshTTL) ||
5711 nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
5712 cur_params.element_ttl) ||
5713 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
5714 cur_params.auto_open_plinks) ||
John W. Linville7eab0f62012-04-12 14:25:14 -04005715 nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
5716 cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04005717 nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
5718 cur_params.dot11MeshHWMPmaxPREQretries) ||
5719 nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
5720 cur_params.path_refresh_time) ||
5721 nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
5722 cur_params.min_discovery_timeout) ||
5723 nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
5724 cur_params.dot11MeshHWMPactivePathTimeout) ||
5725 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
5726 cur_params.dot11MeshHWMPpreqMinInterval) ||
5727 nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
5728 cur_params.dot11MeshHWMPperrMinInterval) ||
5729 nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
5730 cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
5731 nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
5732 cur_params.dot11MeshHWMPRootMode) ||
5733 nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
5734 cur_params.dot11MeshHWMPRannInterval) ||
5735 nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
5736 cur_params.dot11MeshGateAnnouncementProtocol) ||
5737 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
5738 cur_params.dot11MeshForwarding) ||
Masashi Honma335d5342017-03-16 10:57:17 +09005739 nla_put_s32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
Ashok Nagarajan70c33ea2012-04-30 14:20:32 -07005740 cur_params.rssi_threshold) ||
5741 nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005742 cur_params.ht_opmode) ||
5743 nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
5744 cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
5745 nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005746 cur_params.dot11MeshHWMProotInterval) ||
5747 nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005748 cur_params.dot11MeshHWMPconfirmationInterval) ||
5749 nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
5750 cur_params.power_mode) ||
5751 nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005752 cur_params.dot11MeshAwakeWindowDuration) ||
5753 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
5754 cur_params.plink_timeout))
David S. Miller9360ffd2012-03-29 04:41:26 -04005755 goto nla_put_failure;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005756 nla_nest_end(msg, pinfoattr);
5757 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02005758 return genlmsg_reply(msg, info);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005759
Johannes Berg3b858752009-03-12 09:55:09 +01005760 nla_put_failure:
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005761 genlmsg_cancel(msg, hdr);
Julia Lawallefe1cf02011-01-28 15:17:11 +01005762 out:
Yuri Ershovd080e272010-06-29 15:08:07 +04005763 nlmsg_free(msg);
Johannes Berg4c476992010-10-04 21:36:35 +02005764 return -ENOBUFS;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005765}
5766
Alexey Dobriyanb54452b2010-02-18 08:14:31 +00005767static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005768 [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
5769 [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
5770 [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
5771 [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
5772 [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
5773 [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
Javier Cardona45904f22010-12-03 09:20:40 +01005774 [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005775 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
Javier Cardonad299a1f2012-03-31 11:31:33 -07005776 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005777 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
5778 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
5779 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
5780 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
5781 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
Thomas Pedersendca7e942011-11-24 17:15:24 -08005782 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005783 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
Javier Cardona699403d2011-08-09 16:45:09 -07005784 [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
Javier Cardona0507e152011-08-09 16:45:10 -07005785 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
Javier Cardona16dd7262011-08-09 16:45:11 -07005786 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
Chun-Yeow Yeoh94f90652012-01-21 01:02:16 +08005787 [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005788 [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
5789 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005790 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
5791 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08005792 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
Marco Porsch3b1c5a52013-01-07 16:04:52 +01005793 [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
5794 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
Colleen Twitty8e7c0532013-06-03 09:53:39 -07005795 [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005796};
5797
Javier Cardonac80d5452010-12-16 17:37:49 -08005798static const struct nla_policy
5799 nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
Javier Cardonad299a1f2012-03-31 11:31:33 -07005800 [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
Javier Cardonac80d5452010-12-16 17:37:49 -08005801 [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
5802 [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
Javier Cardona15d5dda2011-04-07 15:08:28 -07005803 [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
Colleen Twitty6e16d902013-05-08 11:45:59 -07005804 [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 },
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08005805 [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
Javier Cardona581a8b02011-04-07 15:08:27 -07005806 [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005807 .len = IEEE80211_MAX_DATA_LEN },
Javier Cardonab130e5c2011-05-03 16:57:07 -07005808 [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
Javier Cardonac80d5452010-12-16 17:37:49 -08005809};
5810
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005811static int nl80211_check_bool(const struct nlattr *nla, u8 min, u8 max, bool *out)
5812{
5813 u8 val = nla_get_u8(nla);
5814 if (val < min || val > max)
5815 return -EINVAL;
5816 *out = val;
5817 return 0;
5818}
5819
5820static int nl80211_check_u8(const struct nlattr *nla, u8 min, u8 max, u8 *out)
5821{
5822 u8 val = nla_get_u8(nla);
5823 if (val < min || val > max)
5824 return -EINVAL;
5825 *out = val;
5826 return 0;
5827}
5828
5829static int nl80211_check_u16(const struct nlattr *nla, u16 min, u16 max, u16 *out)
5830{
5831 u16 val = nla_get_u16(nla);
5832 if (val < min || val > max)
5833 return -EINVAL;
5834 *out = val;
5835 return 0;
5836}
5837
5838static int nl80211_check_u32(const struct nlattr *nla, u32 min, u32 max, u32 *out)
5839{
5840 u32 val = nla_get_u32(nla);
5841 if (val < min || val > max)
5842 return -EINVAL;
5843 *out = val;
5844 return 0;
5845}
5846
5847static int nl80211_check_s32(const struct nlattr *nla, s32 min, s32 max, s32 *out)
5848{
5849 s32 val = nla_get_s32(nla);
5850 if (val < min || val > max)
5851 return -EINVAL;
5852 *out = val;
5853 return 0;
5854}
5855
Johannes Bergff9a71a2016-08-11 14:59:53 +02005856static int nl80211_check_power_mode(const struct nlattr *nla,
5857 enum nl80211_mesh_power_mode min,
5858 enum nl80211_mesh_power_mode max,
5859 enum nl80211_mesh_power_mode *out)
5860{
5861 u32 val = nla_get_u32(nla);
5862 if (val < min || val > max)
5863 return -EINVAL;
5864 *out = val;
5865 return 0;
5866}
5867
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005868static int nl80211_parse_mesh_config(struct genl_info *info,
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005869 struct mesh_config *cfg,
5870 u32 *mask_out)
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005871{
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005872 struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005873 u32 mask = 0;
Masashi Honma97572352016-08-03 10:07:44 +09005874 u16 ht_opmode;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005875
Marco Porschea54fba2013-01-07 16:04:48 +01005876#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \
5877do { \
5878 if (tb[attr]) { \
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005879 if (fn(tb[attr], min, max, &cfg->param)) \
Marco Porschea54fba2013-01-07 16:04:48 +01005880 return -EINVAL; \
Marco Porschea54fba2013-01-07 16:04:48 +01005881 mask |= (1 << (attr - 1)); \
5882 } \
5883} while (0)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005884
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005885 if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005886 return -EINVAL;
5887 if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX,
Javier Cardona24bdd9f2010-12-16 17:37:48 -08005888 info->attrs[NL80211_ATTR_MESH_CONFIG],
Johannes Bergbd90fdc2010-12-03 09:20:43 +01005889 nl80211_meshconf_params_policy))
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005890 return -EINVAL;
5891
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005892 /* This makes sure that there aren't more than 32 mesh config
5893 * parameters (otherwise our bitfield scheme would not work.) */
5894 BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
5895
5896 /* Fill in the params struct */
Marco Porschea54fba2013-01-07 16:04:48 +01005897 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005898 mask, NL80211_MESHCONF_RETRY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005899 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005900 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005901 mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005902 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005903 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005904 mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005905 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005906 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005907 mask, NL80211_MESHCONF_MAX_PEER_LINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005908 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005909 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005910 mask, NL80211_MESHCONF_MAX_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005911 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005912 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005913 mask, NL80211_MESHCONF_TTL, nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005914 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005915 mask, NL80211_MESHCONF_ELEMENT_TTL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005916 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005917 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005918 mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005919 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01005920 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
5921 1, 255, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005922 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005923 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005924 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005925 mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005926 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005927 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005928 mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005929 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01005930 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005931 mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005932 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005933 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
5934 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005935 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005936 nl80211_check_u32);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005937 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01005938 1, 65535, mask,
5939 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005940 nl80211_check_u16);
Thomas Pedersendca7e942011-11-24 17:15:24 -08005941 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
Marco Porschea54fba2013-01-07 16:04:48 +01005942 1, 65535, mask,
5943 NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005944 nl80211_check_u16);
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07005945 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005946 dot11MeshHWMPnetDiameterTraversalTime,
5947 1, 65535, mask,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005948 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005949 nl80211_check_u16);
Marco Porschea54fba2013-01-07 16:04:48 +01005950 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4,
5951 mask, NL80211_MESHCONF_HWMP_ROOTMODE,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005952 nl80211_check_u8);
Marco Porschea54fba2013-01-07 16:04:48 +01005953 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, 1, 65535,
5954 mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005955 nl80211_check_u16);
Rui Paulo63c57232009-11-09 23:46:57 +00005956 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01005957 dot11MeshGateAnnouncementProtocol, 0, 1,
5958 mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005959 nl80211_check_bool);
Marco Porschea54fba2013-01-07 16:04:48 +01005960 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005961 mask, NL80211_MESHCONF_FORWARDING,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005962 nl80211_check_bool);
Chun-Yeow Yeoh83374fe2013-07-11 18:24:03 +08005963 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
Chun-Yeow Yeoha4f606e2012-06-11 11:59:36 +08005964 mask, NL80211_MESHCONF_RSSI_THRESHOLD,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02005965 nl80211_check_s32);
Masashi Honma97572352016-08-03 10:07:44 +09005966 /*
5967 * Check HT operation mode based on
5968 * IEEE 802.11 2012 8.4.2.59 HT Operation element.
5969 */
5970 if (tb[NL80211_MESHCONF_HT_OPMODE]) {
5971 ht_opmode = nla_get_u16(tb[NL80211_MESHCONF_HT_OPMODE]);
5972
5973 if (ht_opmode & ~(IEEE80211_HT_OP_MODE_PROTECTION |
5974 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
5975 IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5976 return -EINVAL;
5977
5978 if ((ht_opmode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) &&
5979 (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5980 return -EINVAL;
5981
5982 switch (ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION) {
5983 case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
5984 case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
5985 if (ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT)
5986 return -EINVAL;
5987 break;
5988 case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
5989 case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
5990 if (!(ht_opmode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT))
5991 return -EINVAL;
5992 break;
5993 }
5994 cfg->ht_opmode = ht_opmode;
Masashi Honmafd551ba2017-01-26 08:56:13 +09005995 mask |= (1 << (NL80211_MESHCONF_HT_OPMODE - 1));
Masashi Honma97572352016-08-03 10:07:44 +09005996 }
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005997 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
Marco Porschea54fba2013-01-07 16:04:48 +01005998 1, 65535, mask,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08005999 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006000 nl80211_check_u32);
Marco Porschea54fba2013-01-07 16:04:48 +01006001 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535,
Chun-Yeow Yeohac1073a2012-06-14 02:06:06 +08006002 mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006003 nl80211_check_u16);
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08006004 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
Marco Porschea54fba2013-01-07 16:04:48 +01006005 dot11MeshHWMPconfirmationInterval,
6006 1, 65535, mask,
Chun-Yeow Yeoh728b19e2012-06-14 02:06:10 +08006007 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006008 nl80211_check_u16);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01006009 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode,
6010 NL80211_MESH_POWER_ACTIVE,
6011 NL80211_MESH_POWER_MAX,
6012 mask, NL80211_MESHCONF_POWER_MODE,
Johannes Bergff9a71a2016-08-11 14:59:53 +02006013 nl80211_check_power_mode);
Marco Porsch3b1c5a52013-01-07 16:04:52 +01006014 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
6015 0, 65535, mask,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006016 NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16);
Masashi Honma31f909a2015-02-24 22:42:16 +09006017 FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
Colleen Twitty8e7c0532013-06-03 09:53:39 -07006018 mask, NL80211_MESHCONF_PLINK_TIMEOUT,
Arnd Bergmannf151d9d2016-06-15 22:29:41 +02006019 nl80211_check_u32);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006020 if (mask_out)
6021 *mask_out = mask;
Javier Cardonac80d5452010-12-16 17:37:49 -08006022
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006023 return 0;
6024
6025#undef FILL_IN_MESH_PARAM_IF_SET
6026}
6027
Javier Cardonac80d5452010-12-16 17:37:49 -08006028static int nl80211_parse_mesh_setup(struct genl_info *info,
6029 struct mesh_setup *setup)
6030{
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006031 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Javier Cardonac80d5452010-12-16 17:37:49 -08006032 struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
6033
6034 if (!info->attrs[NL80211_ATTR_MESH_SETUP])
6035 return -EINVAL;
6036 if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX,
6037 info->attrs[NL80211_ATTR_MESH_SETUP],
6038 nl80211_mesh_setup_params_policy))
6039 return -EINVAL;
6040
Javier Cardonad299a1f2012-03-31 11:31:33 -07006041 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
6042 setup->sync_method =
6043 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
6044 IEEE80211_SYNC_METHOD_VENDOR :
6045 IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
6046
Javier Cardonac80d5452010-12-16 17:37:49 -08006047 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
6048 setup->path_sel_proto =
6049 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
6050 IEEE80211_PATH_PROTOCOL_VENDOR :
6051 IEEE80211_PATH_PROTOCOL_HWMP;
6052
6053 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
6054 setup->path_metric =
6055 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
6056 IEEE80211_PATH_METRIC_VENDOR :
6057 IEEE80211_PATH_METRIC_AIRTIME;
6058
Javier Cardona581a8b02011-04-07 15:08:27 -07006059 if (tb[NL80211_MESH_SETUP_IE]) {
Javier Cardonac80d5452010-12-16 17:37:49 -08006060 struct nlattr *ieattr =
Javier Cardona581a8b02011-04-07 15:08:27 -07006061 tb[NL80211_MESH_SETUP_IE];
Javier Cardonac80d5452010-12-16 17:37:49 -08006062 if (!is_valid_ie_attr(ieattr))
6063 return -EINVAL;
Javier Cardona581a8b02011-04-07 15:08:27 -07006064 setup->ie = nla_data(ieattr);
6065 setup->ie_len = nla_len(ieattr);
Javier Cardonac80d5452010-12-16 17:37:49 -08006066 }
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006067 if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
6068 !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
6069 return -EINVAL;
6070 setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
Javier Cardonab130e5c2011-05-03 16:57:07 -07006071 setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
6072 setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
Thomas Pedersenbb2798d2013-03-04 13:06:10 -08006073 if (setup->is_secure)
6074 setup->user_mpm = true;
Javier Cardonac80d5452010-12-16 17:37:49 -08006075
Colleen Twitty6e16d902013-05-08 11:45:59 -07006076 if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) {
6077 if (!setup->user_mpm)
6078 return -EINVAL;
6079 setup->auth_id =
6080 nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]);
6081 }
6082
Javier Cardonac80d5452010-12-16 17:37:49 -08006083 return 0;
6084}
6085
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006086static int nl80211_update_mesh_config(struct sk_buff *skb,
Johannes Berg29cbe682010-12-03 09:20:44 +01006087 struct genl_info *info)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006088{
6089 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6090 struct net_device *dev = info->user_ptr[1];
Johannes Berg29cbe682010-12-03 09:20:44 +01006091 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006092 struct mesh_config cfg;
6093 u32 mask;
6094 int err;
6095
Johannes Berg29cbe682010-12-03 09:20:44 +01006096 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
6097 return -EOPNOTSUPP;
6098
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006099 if (!rdev->ops->update_mesh_config)
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006100 return -EOPNOTSUPP;
6101
Javier Cardona24bdd9f2010-12-16 17:37:48 -08006102 err = nl80211_parse_mesh_config(info, &cfg, &mask);
Johannes Bergbd90fdc2010-12-03 09:20:43 +01006103 if (err)
6104 return err;
6105
Johannes Berg29cbe682010-12-03 09:20:44 +01006106 wdev_lock(wdev);
6107 if (!wdev->mesh_id_len)
6108 err = -ENOLINK;
6109
6110 if (!err)
Hila Gonene35e4d22012-06-27 17:19:42 +03006111 err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01006112
6113 wdev_unlock(wdev);
6114
6115 return err;
colin@cozybit.com93da9cc2008-10-21 12:03:48 -07006116}
6117
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006118static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
6119 struct sk_buff *msg)
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006120{
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006121 struct nlattr *nl_reg_rules;
6122 unsigned int i;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006123
Johannes Berg458f4f92012-12-06 15:47:38 +01006124 if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
6125 (regdom->dfs_region &&
6126 nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006127 goto nla_put_failure;
Johannes Berg458f4f92012-12-06 15:47:38 +01006128
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006129 nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
6130 if (!nl_reg_rules)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006131 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006132
Johannes Berg458f4f92012-12-06 15:47:38 +01006133 for (i = 0; i < regdom->n_reg_rules; i++) {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006134 struct nlattr *nl_reg_rule;
6135 const struct ieee80211_reg_rule *reg_rule;
6136 const struct ieee80211_freq_range *freq_range;
6137 const struct ieee80211_power_rule *power_rule;
Janusz Dziedzic97524822014-01-30 09:52:20 +01006138 unsigned int max_bandwidth_khz;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006139
Johannes Berg458f4f92012-12-06 15:47:38 +01006140 reg_rule = &regdom->reg_rules[i];
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006141 freq_range = &reg_rule->freq_range;
6142 power_rule = &reg_rule->power_rule;
6143
6144 nl_reg_rule = nla_nest_start(msg, i);
6145 if (!nl_reg_rule)
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006146 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006147
Janusz Dziedzic97524822014-01-30 09:52:20 +01006148 max_bandwidth_khz = freq_range->max_bandwidth_khz;
6149 if (!max_bandwidth_khz)
6150 max_bandwidth_khz = reg_get_max_bandwidth(regdom,
6151 reg_rule);
6152
David S. Miller9360ffd2012-03-29 04:41:26 -04006153 if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
6154 reg_rule->flags) ||
6155 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
6156 freq_range->start_freq_khz) ||
6157 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
6158 freq_range->end_freq_khz) ||
6159 nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
Janusz Dziedzic97524822014-01-30 09:52:20 +01006160 max_bandwidth_khz) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04006161 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
6162 power_rule->max_antenna_gain) ||
6163 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
Janusz Dziedzic089027e2014-02-21 19:46:12 +01006164 power_rule->max_eirp) ||
6165 nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
6166 reg_rule->dfs_cac_ms))
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006167 goto nla_put_failure;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006168
6169 nla_nest_end(msg, nl_reg_rule);
6170 }
6171
6172 nla_nest_end(msg, nl_reg_rules);
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006173 return 0;
6174
6175nla_put_failure:
6176 return -EMSGSIZE;
6177}
6178
6179static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
6180{
6181 const struct ieee80211_regdomain *regdom = NULL;
6182 struct cfg80211_registered_device *rdev;
6183 struct wiphy *wiphy = NULL;
6184 struct sk_buff *msg;
6185 void *hdr;
6186
6187 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6188 if (!msg)
6189 return -ENOBUFS;
6190
6191 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
6192 NL80211_CMD_GET_REG);
6193 if (!hdr)
6194 goto put_failure;
6195
6196 if (info->attrs[NL80211_ATTR_WIPHY]) {
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006197 bool self_managed;
6198
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006199 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
6200 if (IS_ERR(rdev)) {
6201 nlmsg_free(msg);
6202 return PTR_ERR(rdev);
6203 }
6204
6205 wiphy = &rdev->wiphy;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006206 self_managed = wiphy->regulatory_flags &
6207 REGULATORY_WIPHY_SELF_MANAGED;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006208 regdom = get_wiphy_regdom(wiphy);
6209
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006210 /* a self-managed-reg device must have a private regdom */
6211 if (WARN_ON(!regdom && self_managed)) {
6212 nlmsg_free(msg);
6213 return -EINVAL;
6214 }
6215
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006216 if (regdom &&
6217 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6218 goto nla_put_failure;
6219 }
6220
6221 if (!wiphy && reg_last_request_cell_base() &&
6222 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6223 NL80211_USER_REG_HINT_CELL_BASE))
6224 goto nla_put_failure;
6225
6226 rcu_read_lock();
6227
6228 if (!regdom)
6229 regdom = rcu_dereference(cfg80211_regdomain);
6230
6231 if (nl80211_put_regdom(regdom, msg))
6232 goto nla_put_failure_rcu;
6233
6234 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006235
6236 genlmsg_end(msg, hdr);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006237 return genlmsg_reply(msg, info);
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006238
Johannes Berg458f4f92012-12-06 15:47:38 +01006239nla_put_failure_rcu:
6240 rcu_read_unlock();
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006241nla_put_failure:
6242 genlmsg_cancel(msg, hdr);
Julia Lawallefe1cf02011-01-28 15:17:11 +01006243put_failure:
Yuri Ershovd080e272010-06-29 15:08:07 +04006244 nlmsg_free(msg);
Johannes Berg5fe231e2013-05-08 21:45:15 +02006245 return -EMSGSIZE;
Luis R. Rodriguezf1303472009-01-30 09:26:42 -08006246}
6247
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006248static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
6249 u32 seq, int flags, struct wiphy *wiphy,
6250 const struct ieee80211_regdomain *regdom)
6251{
6252 void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
6253 NL80211_CMD_GET_REG);
6254
6255 if (!hdr)
6256 return -1;
6257
6258 genl_dump_check_consistent(cb, hdr, &nl80211_fam);
6259
6260 if (nl80211_put_regdom(regdom, msg))
6261 goto nla_put_failure;
6262
6263 if (!wiphy && reg_last_request_cell_base() &&
6264 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
6265 NL80211_USER_REG_HINT_CELL_BASE))
6266 goto nla_put_failure;
6267
6268 if (wiphy &&
6269 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
6270 goto nla_put_failure;
6271
Arik Nemtsov1bdd7162014-12-15 19:26:01 +02006272 if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
6273 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
6274 goto nla_put_failure;
6275
Johannes Berg053c0952015-01-16 22:09:00 +01006276 genlmsg_end(msg, hdr);
6277 return 0;
Arik Nemtsovad30ca22014-12-15 19:25:59 +02006278
6279nla_put_failure:
6280 genlmsg_cancel(msg, hdr);
6281 return -EMSGSIZE;
6282}
6283
6284static int nl80211_get_reg_dump(struct sk_buff *skb,
6285 struct netlink_callback *cb)
6286{
6287 const struct ieee80211_regdomain *regdom = NULL;
6288 struct cfg80211_registered_device *rdev;
6289 int err, reg_idx, start = cb->args[2];
6290
6291 rtnl_lock();
6292
6293 if (cfg80211_regdomain && start == 0) {
6294 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6295 NLM_F_MULTI, NULL,
6296 rtnl_dereference(cfg80211_regdomain));
6297 if (err < 0)
6298 goto out_err;
6299 }
6300
6301 /* the global regdom is idx 0 */
6302 reg_idx = 1;
6303 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
6304 regdom = get_wiphy_regdom(&rdev->wiphy);
6305 if (!regdom)
6306 continue;
6307
6308 if (++reg_idx <= start)
6309 continue;
6310
6311 err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
6312 NLM_F_MULTI, &rdev->wiphy, regdom);
6313 if (err < 0) {
6314 reg_idx--;
6315 break;
6316 }
6317 }
6318
6319 cb->args[2] = reg_idx;
6320 err = skb->len;
6321out_err:
6322 rtnl_unlock();
6323 return err;
6324}
6325
Johannes Bergb6863032015-10-15 09:25:18 +02006326#ifdef CONFIG_CFG80211_CRDA_SUPPORT
6327static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
6328 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
6329 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
6330 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
6331 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
6332 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
6333 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
6334 [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
6335};
6336
6337static int parse_reg_rule(struct nlattr *tb[],
6338 struct ieee80211_reg_rule *reg_rule)
6339{
6340 struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
6341 struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
6342
6343 if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
6344 return -EINVAL;
6345 if (!tb[NL80211_ATTR_FREQ_RANGE_START])
6346 return -EINVAL;
6347 if (!tb[NL80211_ATTR_FREQ_RANGE_END])
6348 return -EINVAL;
6349 if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
6350 return -EINVAL;
6351 if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
6352 return -EINVAL;
6353
6354 reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
6355
6356 freq_range->start_freq_khz =
6357 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
6358 freq_range->end_freq_khz =
6359 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
6360 freq_range->max_bandwidth_khz =
6361 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
6362
6363 power_rule->max_eirp =
6364 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
6365
6366 if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
6367 power_rule->max_antenna_gain =
6368 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
6369
6370 if (tb[NL80211_ATTR_DFS_CAC_TIME])
6371 reg_rule->dfs_cac_ms =
6372 nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
6373
6374 return 0;
6375}
6376
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006377static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
6378{
6379 struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
6380 struct nlattr *nl_reg_rule;
Johannes Bergea372c52014-11-28 14:54:31 +01006381 char *alpha2;
6382 int rem_reg_rules, r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006383 u32 num_rules = 0, rule_idx = 0, size_of_regd;
Luis R. Rodriguez4c7d3982013-11-13 18:54:02 +01006384 enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
Johannes Bergea372c52014-11-28 14:54:31 +01006385 struct ieee80211_regdomain *rd;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006386
6387 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
6388 return -EINVAL;
6389
6390 if (!info->attrs[NL80211_ATTR_REG_RULES])
6391 return -EINVAL;
6392
6393 alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
6394
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006395 if (info->attrs[NL80211_ATTR_DFS_REGION])
6396 dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
6397
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006398 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006399 rem_reg_rules) {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006400 num_rules++;
6401 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
Luis R. Rodriguez4776c6e2009-05-13 17:04:39 -04006402 return -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006403 }
6404
Luis R. Rodrigueze4387682013-11-05 09:18:01 -08006405 if (!reg_is_valid_request(alpha2))
6406 return -EINVAL;
6407
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006408 size_of_regd = sizeof(struct ieee80211_regdomain) +
Johannes Berg1a919312012-12-03 17:21:11 +01006409 num_rules * sizeof(struct ieee80211_reg_rule);
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006410
6411 rd = kzalloc(size_of_regd, GFP_KERNEL);
Johannes Berg6913b492012-12-04 00:48:59 +01006412 if (!rd)
6413 return -ENOMEM;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006414
6415 rd->n_reg_rules = num_rules;
6416 rd->alpha2[0] = alpha2[0];
6417 rd->alpha2[1] = alpha2[1];
6418
Luis R. Rodriguez8b60b072011-10-11 10:59:02 -07006419 /*
6420 * Disable DFS master mode if the DFS region was
6421 * not supported or known on this kernel.
6422 */
6423 if (reg_supported_dfs_region(dfs_region))
6424 rd->dfs_region = dfs_region;
6425
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006426 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
Johannes Berg1a919312012-12-03 17:21:11 +01006427 rem_reg_rules) {
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006428 r = nla_parse_nested(tb, NL80211_REG_RULE_ATTR_MAX,
6429 nl_reg_rule, reg_rule_policy);
Johannes Bergae811e22014-01-24 10:17:47 +01006430 if (r)
6431 goto bad_reg;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006432 r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
6433 if (r)
6434 goto bad_reg;
6435
6436 rule_idx++;
6437
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006438 if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
6439 r = -EINVAL;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006440 goto bad_reg;
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006441 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006442 }
6443
Johannes Berg06627992016-06-09 10:40:09 +02006444 /* set_regdom takes ownership of rd */
6445 return set_regdom(rd, REGD_SOURCE_CRDA);
Johannes Bergd2372b32008-10-24 20:32:20 +02006446 bad_reg:
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006447 kfree(rd);
Luis R. Rodriguezd0e18f82009-05-13 17:04:40 -04006448 return r;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006449}
Johannes Bergb6863032015-10-15 09:25:18 +02006450#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006451
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006452static int validate_scan_freqs(struct nlattr *freqs)
6453{
6454 struct nlattr *attr1, *attr2;
6455 int n_channels = 0, tmp1, tmp2;
6456
6457 nla_for_each_nested(attr1, freqs, tmp1) {
6458 n_channels++;
6459 /*
6460 * Some hardware has a limited channel list for
6461 * scanning, and it is pretty much nonsensical
6462 * to scan for a channel twice, so disallow that
6463 * and don't require drivers to check that the
6464 * channel list they get isn't longer than what
6465 * they can scan, as long as they can scan all
6466 * the channels they registered at once.
6467 */
6468 nla_for_each_nested(attr2, freqs, tmp2)
6469 if (attr1 != attr2 &&
6470 nla_get_u32(attr1) == nla_get_u32(attr2))
6471 return 0;
6472 }
6473
6474 return n_channels;
6475}
6476
Johannes Berg57fbcce2016-04-12 15:56:15 +02006477static bool is_band_valid(struct wiphy *wiphy, enum nl80211_band b)
Arend van Spriel38de03d2016-03-02 20:37:18 +01006478{
Johannes Berg57fbcce2016-04-12 15:56:15 +02006479 return b < NUM_NL80211_BANDS && wiphy->bands[b];
Arend van Spriel38de03d2016-03-02 20:37:18 +01006480}
6481
6482static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
6483 struct cfg80211_bss_selection *bss_select)
6484{
6485 struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
6486 struct nlattr *nest;
6487 int err;
6488 bool found = false;
6489 int i;
6490
6491 /* only process one nested attribute */
6492 nest = nla_data(nla);
6493 if (!nla_ok(nest, nla_len(nest)))
6494 return -EINVAL;
6495
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006496 err = nla_parse_nested(attr, NL80211_BSS_SELECT_ATTR_MAX, nest,
6497 nl80211_bss_select_policy);
Arend van Spriel38de03d2016-03-02 20:37:18 +01006498 if (err)
6499 return err;
6500
6501 /* only one attribute may be given */
6502 for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
6503 if (attr[i]) {
6504 if (found)
6505 return -EINVAL;
6506 found = true;
6507 }
6508 }
6509
6510 bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
6511
6512 if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
6513 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
6514
6515 if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
6516 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
6517 bss_select->param.band_pref =
6518 nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
6519 if (!is_band_valid(wiphy, bss_select->param.band_pref))
6520 return -EINVAL;
6521 }
6522
6523 if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
6524 struct nl80211_bss_select_rssi_adjust *adj_param;
6525
6526 adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
6527 bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
6528 bss_select->param.adjust.band = adj_param->band;
6529 bss_select->param.adjust.delta = adj_param->delta;
6530 if (!is_band_valid(wiphy, bss_select->param.adjust.band))
6531 return -EINVAL;
6532 }
6533
6534 /* user-space did not provide behaviour attribute */
6535 if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
6536 return -EINVAL;
6537
6538 if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
6539 return -EINVAL;
6540
6541 return 0;
6542}
6543
Johannes Bergad2b26a2014-06-12 21:39:05 +02006544static int nl80211_parse_random_mac(struct nlattr **attrs,
6545 u8 *mac_addr, u8 *mac_addr_mask)
6546{
6547 int i;
6548
6549 if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
Joe Perchesd2beae12015-03-02 19:54:58 -08006550 eth_zero_addr(mac_addr);
6551 eth_zero_addr(mac_addr_mask);
Johannes Bergad2b26a2014-06-12 21:39:05 +02006552 mac_addr[0] = 0x2;
6553 mac_addr_mask[0] = 0x3;
6554
6555 return 0;
6556 }
6557
6558 /* need both or none */
6559 if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
6560 return -EINVAL;
6561
6562 memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
6563 memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
6564
6565 /* don't allow or configure an mcast address */
6566 if (!is_multicast_ether_addr(mac_addr_mask) ||
6567 is_multicast_ether_addr(mac_addr))
6568 return -EINVAL;
6569
6570 /*
6571 * allow users to pass a MAC address that has bits set outside
6572 * of the mask, but don't bother drivers with having to deal
6573 * with such bits
6574 */
6575 for (i = 0; i < ETH_ALEN; i++)
6576 mac_addr[i] &= mac_addr_mask[i];
6577
6578 return 0;
6579}
6580
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05306581static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
6582{
6583 ASSERT_WDEV_LOCK(wdev);
6584
6585 if (!cfg80211_beaconing_iface_active(wdev))
6586 return true;
6587
6588 if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
6589 return true;
6590
6591 return regulatory_pre_cac_allowed(wdev->wiphy);
6592}
6593
Johannes Berg2a519312009-02-10 21:25:55 +01006594static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
6595{
Johannes Berg4c476992010-10-04 21:36:35 +02006596 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Bergfd014282012-06-18 19:17:03 +02006597 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2a519312009-02-10 21:25:55 +01006598 struct cfg80211_scan_request *request;
Johannes Berg2a519312009-02-10 21:25:55 +01006599 struct nlattr *attr;
6600 struct wiphy *wiphy;
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006601 int err, tmp, n_ssids = 0, n_channels, i;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006602 size_t ie_len;
Johannes Berg2a519312009-02-10 21:25:55 +01006603
Johannes Bergf4a11bb2009-03-27 12:40:28 +01006604 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
6605 return -EINVAL;
6606
Johannes Berg79c97e92009-07-07 03:56:12 +02006607 wiphy = &rdev->wiphy;
Johannes Berg2a519312009-02-10 21:25:55 +01006608
Ayala Bekercb3b7d82016-09-20 17:31:13 +03006609 if (wdev->iftype == NL80211_IFTYPE_NAN)
6610 return -EOPNOTSUPP;
6611
Johannes Berg4c476992010-10-04 21:36:35 +02006612 if (!rdev->ops->scan)
6613 return -EOPNOTSUPP;
Johannes Berg2a519312009-02-10 21:25:55 +01006614
Johannes Bergf9d15d12014-01-22 11:14:19 +02006615 if (rdev->scan_req || rdev->scan_msg) {
Johannes Bergf9f47522013-03-19 15:04:07 +01006616 err = -EBUSY;
6617 goto unlock;
6618 }
Johannes Berg2a519312009-02-10 21:25:55 +01006619
6620 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Johannes Berg83f5e2c2009-06-17 17:41:49 +02006621 n_channels = validate_scan_freqs(
6622 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Johannes Bergf9f47522013-03-19 15:04:07 +01006623 if (!n_channels) {
6624 err = -EINVAL;
6625 goto unlock;
6626 }
Johannes Berg2a519312009-02-10 21:25:55 +01006627 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02006628 n_channels = ieee80211_get_num_supported_channels(wiphy);
Johannes Berg2a519312009-02-10 21:25:55 +01006629 }
6630
6631 if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
6632 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
6633 n_ssids++;
6634
Johannes Bergf9f47522013-03-19 15:04:07 +01006635 if (n_ssids > wiphy->max_scan_ssids) {
6636 err = -EINVAL;
6637 goto unlock;
6638 }
Johannes Berg2a519312009-02-10 21:25:55 +01006639
Jouni Malinen70692ad2009-02-16 19:39:13 +02006640 if (info->attrs[NL80211_ATTR_IE])
6641 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
6642 else
6643 ie_len = 0;
6644
Johannes Bergf9f47522013-03-19 15:04:07 +01006645 if (ie_len > wiphy->max_scan_ie_len) {
6646 err = -EINVAL;
6647 goto unlock;
6648 }
Johannes Berg18a83652009-03-31 12:12:05 +02006649
Johannes Berg2a519312009-02-10 21:25:55 +01006650 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03006651 + sizeof(*request->ssids) * n_ssids
6652 + sizeof(*request->channels) * n_channels
Jouni Malinen70692ad2009-02-16 19:39:13 +02006653 + ie_len, GFP_KERNEL);
Johannes Bergf9f47522013-03-19 15:04:07 +01006654 if (!request) {
6655 err = -ENOMEM;
6656 goto unlock;
6657 }
Johannes Berg2a519312009-02-10 21:25:55 +01006658
Johannes Berg2a519312009-02-10 21:25:55 +01006659 if (n_ssids)
Johannes Berg5ba63532009-08-07 17:54:07 +02006660 request->ssids = (void *)&request->channels[n_channels];
Johannes Berg2a519312009-02-10 21:25:55 +01006661 request->n_ssids = n_ssids;
Jouni Malinen70692ad2009-02-16 19:39:13 +02006662 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01006663 if (n_ssids)
Jouni Malinen70692ad2009-02-16 19:39:13 +02006664 request->ie = (void *)(request->ssids + n_ssids);
6665 else
6666 request->ie = (void *)(request->channels + n_channels);
6667 }
Johannes Berg2a519312009-02-10 21:25:55 +01006668
Johannes Berg584991d2009-11-02 13:32:03 +01006669 i = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01006670 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
6671 /* user specified, bail out if channel not found */
Johannes Berg2a519312009-02-10 21:25:55 +01006672 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
Johannes Berg584991d2009-11-02 13:32:03 +01006673 struct ieee80211_channel *chan;
6674
6675 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
6676
6677 if (!chan) {
Johannes Berg2a519312009-02-10 21:25:55 +01006678 err = -EINVAL;
6679 goto out_free;
6680 }
Johannes Berg584991d2009-11-02 13:32:03 +01006681
6682 /* ignore disabled channels */
6683 if (chan->flags & IEEE80211_CHAN_DISABLED)
6684 continue;
6685
6686 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006687 i++;
6688 }
6689 } else {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006690 enum nl80211_band band;
Johannes Berg34850ab2011-07-18 18:08:35 +02006691
Johannes Berg2a519312009-02-10 21:25:55 +01006692 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02006693 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Johannes Berg2a519312009-02-10 21:25:55 +01006694 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07006695
Johannes Berg2a519312009-02-10 21:25:55 +01006696 if (!wiphy->bands[band])
6697 continue;
6698 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
Johannes Berg584991d2009-11-02 13:32:03 +01006699 struct ieee80211_channel *chan;
6700
6701 chan = &wiphy->bands[band]->channels[j];
6702
6703 if (chan->flags & IEEE80211_CHAN_DISABLED)
6704 continue;
6705
6706 request->channels[i] = chan;
Johannes Berg2a519312009-02-10 21:25:55 +01006707 i++;
6708 }
6709 }
6710 }
6711
Johannes Berg584991d2009-11-02 13:32:03 +01006712 if (!i) {
6713 err = -EINVAL;
6714 goto out_free;
6715 }
6716
6717 request->n_channels = i;
6718
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05306719 wdev_lock(wdev);
6720 if (!cfg80211_off_channel_oper_allowed(wdev)) {
6721 struct ieee80211_channel *chan;
6722
6723 if (request->n_channels != 1) {
6724 wdev_unlock(wdev);
6725 err = -EBUSY;
6726 goto out_free;
6727 }
6728
6729 chan = request->channels[0];
6730 if (chan->center_freq != wdev->chandef.chan->center_freq) {
6731 wdev_unlock(wdev);
6732 err = -EBUSY;
6733 goto out_free;
6734 }
6735 }
6736 wdev_unlock(wdev);
6737
Johannes Berg2a519312009-02-10 21:25:55 +01006738 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01006739 if (n_ssids) {
Johannes Berg2a519312009-02-10 21:25:55 +01006740 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03006741 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Johannes Berg2a519312009-02-10 21:25:55 +01006742 err = -EINVAL;
6743 goto out_free;
6744 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03006745 request->ssids[i].ssid_len = nla_len(attr);
Johannes Berg2a519312009-02-10 21:25:55 +01006746 memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
Johannes Berg2a519312009-02-10 21:25:55 +01006747 i++;
6748 }
6749 }
6750
Jouni Malinen70692ad2009-02-16 19:39:13 +02006751 if (info->attrs[NL80211_ATTR_IE]) {
6752 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Johannes Bergde95a542009-04-01 11:58:36 +02006753 memcpy((void *)request->ie,
6754 nla_data(info->attrs[NL80211_ATTR_IE]),
Jouni Malinen70692ad2009-02-16 19:39:13 +02006755 request->ie_len);
6756 }
6757
Johannes Berg57fbcce2016-04-12 15:56:15 +02006758 for (i = 0; i < NUM_NL80211_BANDS; i++)
Johannes Berga401d2b2011-07-20 00:52:16 +02006759 if (wiphy->bands[i])
6760 request->rates[i] =
6761 (1 << wiphy->bands[i]->n_bitrates) - 1;
Johannes Berg34850ab2011-07-18 18:08:35 +02006762
6763 if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
6764 nla_for_each_nested(attr,
6765 info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
6766 tmp) {
Johannes Berg57fbcce2016-04-12 15:56:15 +02006767 enum nl80211_band band = nla_type(attr);
Johannes Berg34850ab2011-07-18 18:08:35 +02006768
Johannes Berg57fbcce2016-04-12 15:56:15 +02006769 if (band < 0 || band >= NUM_NL80211_BANDS) {
Johannes Berg34850ab2011-07-18 18:08:35 +02006770 err = -EINVAL;
6771 goto out_free;
6772 }
Felix Fietkau1b09cd82013-11-20 19:40:41 +01006773
6774 if (!wiphy->bands[band])
6775 continue;
6776
Johannes Berg34850ab2011-07-18 18:08:35 +02006777 err = ieee80211_get_ratemask(wiphy->bands[band],
6778 nla_data(attr),
6779 nla_len(attr),
6780 &request->rates[band]);
6781 if (err)
6782 goto out_free;
6783 }
6784 }
6785
Avraham Stern1d762502016-07-05 17:10:13 +03006786 if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
6787 if (!wiphy_ext_feature_isset(wiphy,
6788 NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
6789 err = -EOPNOTSUPP;
6790 goto out_free;
6791 }
6792
6793 request->duration =
6794 nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
6795 request->duration_mandatory =
6796 nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
6797 }
6798
Sam Leffler46856bb2012-10-11 21:03:32 -07006799 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
Sam Lefflered4737712012-10-11 21:03:31 -07006800 request->flags = nla_get_u32(
6801 info->attrs[NL80211_ATTR_SCAN_FLAGS]);
Johannes Berg00c3a6e2013-10-26 17:14:38 +02006802 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
6803 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
Sam Leffler46856bb2012-10-11 21:03:32 -07006804 err = -EOPNOTSUPP;
6805 goto out_free;
6806 }
Johannes Bergad2b26a2014-06-12 21:39:05 +02006807
6808 if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
6809 if (!(wiphy->features &
6810 NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)) {
6811 err = -EOPNOTSUPP;
6812 goto out_free;
6813 }
6814
6815 if (wdev->current_bss) {
6816 err = -EOPNOTSUPP;
6817 goto out_free;
6818 }
6819
6820 err = nl80211_parse_random_mac(info->attrs,
6821 request->mac_addr,
6822 request->mac_addr_mask);
6823 if (err)
6824 goto out_free;
6825 }
Sam Leffler46856bb2012-10-11 21:03:32 -07006826 }
Sam Lefflered4737712012-10-11 21:03:31 -07006827
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05306828 request->no_cck =
6829 nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
6830
Vamsi Krishna2fa436b2016-12-02 23:59:08 +02006831 /* Initial implementation used NL80211_ATTR_MAC to set the specific
6832 * BSSID to scan for. This was problematic because that same attribute
6833 * was already used for another purpose (local random MAC address). The
6834 * NL80211_ATTR_BSSID attribute was added to fix this. For backwards
6835 * compatibility with older userspace components, also use the
6836 * NL80211_ATTR_MAC value here if it can be determined to be used for
6837 * the specific BSSID use case instead of the random MAC address
6838 * (NL80211_ATTR_SCAN_FLAGS is used to enable random MAC address use).
6839 */
6840 if (info->attrs[NL80211_ATTR_BSSID])
6841 memcpy(request->bssid,
6842 nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
6843 else if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
6844 info->attrs[NL80211_ATTR_MAC])
Jouni Malinen818965d2016-02-26 22:12:47 +02006845 memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
6846 ETH_ALEN);
6847 else
6848 eth_broadcast_addr(request->bssid);
6849
Johannes Bergfd014282012-06-18 19:17:03 +02006850 request->wdev = wdev;
Johannes Berg79c97e92009-07-07 03:56:12 +02006851 request->wiphy = &rdev->wiphy;
Sam Leffler15d60302012-10-11 21:03:34 -07006852 request->scan_start = jiffies;
Johannes Berg2a519312009-02-10 21:25:55 +01006853
Johannes Berg79c97e92009-07-07 03:56:12 +02006854 rdev->scan_req = request;
Hila Gonene35e4d22012-06-27 17:19:42 +03006855 err = rdev_scan(rdev, request);
Johannes Berg2a519312009-02-10 21:25:55 +01006856
Johannes Berg463d0182009-07-14 00:33:35 +02006857 if (!err) {
Johannes Bergfd014282012-06-18 19:17:03 +02006858 nl80211_send_scan_start(rdev, wdev);
6859 if (wdev->netdev)
6860 dev_hold(wdev->netdev);
Johannes Berg4c476992010-10-04 21:36:35 +02006861 } else {
Johannes Berg2a519312009-02-10 21:25:55 +01006862 out_free:
Johannes Berg79c97e92009-07-07 03:56:12 +02006863 rdev->scan_req = NULL;
Johannes Berg2a519312009-02-10 21:25:55 +01006864 kfree(request);
6865 }
Johannes Berg3b858752009-03-12 09:55:09 +01006866
Johannes Bergf9f47522013-03-19 15:04:07 +01006867 unlock:
Johannes Berg2a519312009-02-10 21:25:55 +01006868 return err;
6869}
6870
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +05306871static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
6872{
6873 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6874 struct wireless_dev *wdev = info->user_ptr[1];
6875
6876 if (!rdev->ops->abort_scan)
6877 return -EOPNOTSUPP;
6878
6879 if (rdev->scan_msg)
6880 return 0;
6881
6882 if (!rdev->scan_req)
6883 return -ENOENT;
6884
6885 rdev_abort_scan(rdev, wdev);
6886 return 0;
6887}
6888
Avraham Stern3b06d272015-10-12 09:51:34 +03006889static int
6890nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
6891 struct cfg80211_sched_scan_request *request,
6892 struct nlattr **attrs)
6893{
6894 int tmp, err, i = 0;
6895 struct nlattr *attr;
6896
6897 if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
6898 u32 interval;
6899
6900 /*
6901 * If scan plans are not specified,
Arend Van Spriel5a88de532016-11-17 09:02:40 +00006902 * %NL80211_ATTR_SCHED_SCAN_INTERVAL will be specified. In this
Avraham Stern3b06d272015-10-12 09:51:34 +03006903 * case one scan plan will be set with the specified scan
6904 * interval and infinite number of iterations.
6905 */
Avraham Stern3b06d272015-10-12 09:51:34 +03006906 interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
6907 if (!interval)
6908 return -EINVAL;
6909
6910 request->scan_plans[0].interval =
6911 DIV_ROUND_UP(interval, MSEC_PER_SEC);
6912 if (!request->scan_plans[0].interval)
6913 return -EINVAL;
6914
6915 if (request->scan_plans[0].interval >
6916 wiphy->max_sched_scan_plan_interval)
6917 request->scan_plans[0].interval =
6918 wiphy->max_sched_scan_plan_interval;
6919
6920 return 0;
6921 }
6922
6923 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
6924 struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
6925
6926 if (WARN_ON(i >= n_plans))
6927 return -EINVAL;
6928
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02006929 err = nla_parse_nested(plan, NL80211_SCHED_SCAN_PLAN_MAX,
6930 attr, nl80211_plan_policy);
Avraham Stern3b06d272015-10-12 09:51:34 +03006931 if (err)
6932 return err;
6933
6934 if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
6935 return -EINVAL;
6936
6937 request->scan_plans[i].interval =
6938 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
6939 if (!request->scan_plans[i].interval ||
6940 request->scan_plans[i].interval >
6941 wiphy->max_sched_scan_plan_interval)
6942 return -EINVAL;
6943
6944 if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
6945 request->scan_plans[i].iterations =
6946 nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
6947 if (!request->scan_plans[i].iterations ||
6948 (request->scan_plans[i].iterations >
6949 wiphy->max_sched_scan_plan_iterations))
6950 return -EINVAL;
6951 } else if (i < n_plans - 1) {
6952 /*
6953 * All scan plans but the last one must specify
6954 * a finite number of iterations
6955 */
6956 return -EINVAL;
6957 }
6958
6959 i++;
6960 }
6961
6962 /*
6963 * The last scan plan must not specify the number of
6964 * iterations, it is supposed to run infinitely
6965 */
6966 if (request->scan_plans[n_plans - 1].iterations)
6967 return -EINVAL;
6968
6969 return 0;
6970}
6971
Luciano Coelho256da022014-11-10 16:13:46 +02006972static struct cfg80211_sched_scan_request *
Johannes Bergad2b26a2014-06-12 21:39:05 +02006973nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00006974 struct nlattr **attrs, int max_match_sets)
Luciano Coelho807f8a82011-05-11 17:09:35 +03006975{
6976 struct cfg80211_sched_scan_request *request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006977 struct nlattr *attr;
Avraham Stern3b06d272015-10-12 09:51:34 +03006978 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
Johannes Berg57fbcce2016-04-12 15:56:15 +02006979 enum nl80211_band band;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006980 size_t ie_len;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03006981 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
Johannes Bergea73cbc2014-01-24 10:53:53 +01006982 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelho807f8a82011-05-11 17:09:35 +03006983
Luciano Coelho256da022014-11-10 16:13:46 +02006984 if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE]))
6985 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006986
Luciano Coelho256da022014-11-10 16:13:46 +02006987 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03006988 n_channels = validate_scan_freqs(
Luciano Coelho256da022014-11-10 16:13:46 +02006989 attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006990 if (!n_channels)
Luciano Coelho256da022014-11-10 16:13:46 +02006991 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006992 } else {
Ilan Peerbdfbec22014-01-09 11:37:23 +02006993 n_channels = ieee80211_get_num_supported_channels(wiphy);
Luciano Coelho807f8a82011-05-11 17:09:35 +03006994 }
6995
Luciano Coelho256da022014-11-10 16:13:46 +02006996 if (attrs[NL80211_ATTR_SCAN_SSIDS])
6997 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03006998 tmp)
6999 n_ssids++;
7000
Luciano Coelho93b6aa62011-07-13 14:57:28 +03007001 if (n_ssids > wiphy->max_sched_scan_ssids)
Luciano Coelho256da022014-11-10 16:13:46 +02007002 return ERR_PTR(-EINVAL);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007003
Johannes Bergea73cbc2014-01-24 10:53:53 +01007004 /*
7005 * First, count the number of 'real' matchsets. Due to an issue with
7006 * the old implementation, matchsets containing only the RSSI attribute
7007 * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
7008 * RSSI for all matchsets, rather than their own matchset for reporting
7009 * all APs with a strong RSSI. This is needed to be compatible with
7010 * older userspace that treated a matchset with only the RSSI as the
7011 * global RSSI for all other matchsets - if there are other matchsets.
7012 */
Luciano Coelho256da022014-11-10 16:13:46 +02007013 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007014 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007015 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Johannes Bergea73cbc2014-01-24 10:53:53 +01007016 tmp) {
7017 struct nlattr *rssi;
7018
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02007019 err = nla_parse_nested(tb,
7020 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
7021 attr, nl80211_match_policy);
Johannes Bergea73cbc2014-01-24 10:53:53 +01007022 if (err)
Luciano Coelho256da022014-11-10 16:13:46 +02007023 return ERR_PTR(err);
Johannes Bergea73cbc2014-01-24 10:53:53 +01007024 /* add other standalone attributes here */
7025 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
7026 n_match_sets++;
7027 continue;
7028 }
7029 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
7030 if (rssi)
7031 default_match_rssi = nla_get_s32(rssi);
7032 }
7033 }
7034
7035 /* However, if there's no other matchset, add the RSSI one */
7036 if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
7037 n_match_sets = 1;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007038
Arend Van Sprielaad1e812017-01-27 12:27:44 +00007039 if (n_match_sets > max_match_sets)
Luciano Coelho256da022014-11-10 16:13:46 +02007040 return ERR_PTR(-EINVAL);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007041
Luciano Coelho256da022014-11-10 16:13:46 +02007042 if (attrs[NL80211_ATTR_IE])
7043 ie_len = nla_len(attrs[NL80211_ATTR_IE]);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007044 else
7045 ie_len = 0;
7046
Luciano Coelho5a865ba2011-07-13 14:57:29 +03007047 if (ie_len > wiphy->max_sched_scan_ie_len)
Luciano Coelho256da022014-11-10 16:13:46 +02007048 return ERR_PTR(-EINVAL);
Luciano Coelhoc10841c2011-06-30 08:32:41 +03007049
Avraham Stern3b06d272015-10-12 09:51:34 +03007050 if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
7051 /*
7052 * NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
7053 * each scan plan already specifies its own interval
7054 */
7055 if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
7056 return ERR_PTR(-EINVAL);
7057
7058 nla_for_each_nested(attr,
7059 attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
7060 n_plans++;
7061 } else {
7062 /*
7063 * The scan interval attribute is kept for backward
7064 * compatibility. If no scan plans are specified and sched scan
7065 * interval is specified, one scan plan will be set with this
7066 * scan interval and infinite number of iterations.
7067 */
7068 if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
7069 return ERR_PTR(-EINVAL);
7070
7071 n_plans = 1;
7072 }
7073
7074 if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
7075 return ERR_PTR(-EINVAL);
7076
vamsi krishnabf95ecd2017-01-13 01:12:20 +02007077 if (!wiphy_ext_feature_isset(
7078 wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
7079 (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
7080 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
7081 return ERR_PTR(-EINVAL);
7082
Luciano Coelho807f8a82011-05-11 17:09:35 +03007083 request = kzalloc(sizeof(*request)
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007084 + sizeof(*request->ssids) * n_ssids
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007085 + sizeof(*request->match_sets) * n_match_sets
Avraham Stern3b06d272015-10-12 09:51:34 +03007086 + sizeof(*request->scan_plans) * n_plans
Luciano Coelhoa2cd43c2011-05-18 11:42:03 +03007087 + sizeof(*request->channels) * n_channels
Luciano Coelho807f8a82011-05-11 17:09:35 +03007088 + ie_len, GFP_KERNEL);
Luciano Coelho256da022014-11-10 16:13:46 +02007089 if (!request)
7090 return ERR_PTR(-ENOMEM);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007091
7092 if (n_ssids)
7093 request->ssids = (void *)&request->channels[n_channels];
7094 request->n_ssids = n_ssids;
7095 if (ie_len) {
Johannes Berg13874e42015-01-23 11:25:20 +01007096 if (n_ssids)
Luciano Coelho807f8a82011-05-11 17:09:35 +03007097 request->ie = (void *)(request->ssids + n_ssids);
7098 else
7099 request->ie = (void *)(request->channels + n_channels);
7100 }
7101
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007102 if (n_match_sets) {
7103 if (request->ie)
7104 request->match_sets = (void *)(request->ie + ie_len);
Johannes Berg13874e42015-01-23 11:25:20 +01007105 else if (n_ssids)
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007106 request->match_sets =
7107 (void *)(request->ssids + n_ssids);
7108 else
7109 request->match_sets =
7110 (void *)(request->channels + n_channels);
7111 }
7112 request->n_match_sets = n_match_sets;
7113
Avraham Stern3b06d272015-10-12 09:51:34 +03007114 if (n_match_sets)
7115 request->scan_plans = (void *)(request->match_sets +
7116 n_match_sets);
7117 else if (request->ie)
7118 request->scan_plans = (void *)(request->ie + ie_len);
7119 else if (n_ssids)
7120 request->scan_plans = (void *)(request->ssids + n_ssids);
7121 else
7122 request->scan_plans = (void *)(request->channels + n_channels);
7123
7124 request->n_scan_plans = n_plans;
7125
Luciano Coelho807f8a82011-05-11 17:09:35 +03007126 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007127 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007128 /* user specified, bail out if channel not found */
7129 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007130 attrs[NL80211_ATTR_SCAN_FREQUENCIES],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007131 tmp) {
7132 struct ieee80211_channel *chan;
7133
7134 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
7135
7136 if (!chan) {
7137 err = -EINVAL;
7138 goto out_free;
7139 }
7140
7141 /* ignore disabled channels */
7142 if (chan->flags & IEEE80211_CHAN_DISABLED)
7143 continue;
7144
7145 request->channels[i] = chan;
7146 i++;
7147 }
7148 } else {
7149 /* all channels */
Johannes Berg57fbcce2016-04-12 15:56:15 +02007150 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007151 int j;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007152
Luciano Coelho807f8a82011-05-11 17:09:35 +03007153 if (!wiphy->bands[band])
7154 continue;
7155 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
7156 struct ieee80211_channel *chan;
7157
7158 chan = &wiphy->bands[band]->channels[j];
7159
7160 if (chan->flags & IEEE80211_CHAN_DISABLED)
7161 continue;
7162
7163 request->channels[i] = chan;
7164 i++;
7165 }
7166 }
7167 }
7168
7169 if (!i) {
7170 err = -EINVAL;
7171 goto out_free;
7172 }
7173
7174 request->n_channels = i;
7175
7176 i = 0;
Johannes Berg13874e42015-01-23 11:25:20 +01007177 if (n_ssids) {
Luciano Coelho256da022014-11-10 16:13:46 +02007178 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
Luciano Coelho807f8a82011-05-11 17:09:35 +03007179 tmp) {
Luciano Coelho57a27e12011-06-07 20:42:26 +03007180 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
Luciano Coelho807f8a82011-05-11 17:09:35 +03007181 err = -EINVAL;
7182 goto out_free;
7183 }
Luciano Coelho57a27e12011-06-07 20:42:26 +03007184 request->ssids[i].ssid_len = nla_len(attr);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007185 memcpy(request->ssids[i].ssid, nla_data(attr),
7186 nla_len(attr));
Luciano Coelho807f8a82011-05-11 17:09:35 +03007187 i++;
7188 }
7189 }
7190
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007191 i = 0;
Luciano Coelho256da022014-11-10 16:13:46 +02007192 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007193 nla_for_each_nested(attr,
Luciano Coelho256da022014-11-10 16:13:46 +02007194 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007195 tmp) {
Thomas Pedersen88e920b2012-06-21 11:09:54 -07007196 struct nlattr *ssid, *rssi;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007197
Johannes Bergbfe2c7b2016-10-26 14:42:21 +02007198 err = nla_parse_nested(tb,
7199 NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
7200 attr, nl80211_match_policy);
Johannes Bergae811e22014-01-24 10:17:47 +01007201 if (err)
7202 goto out_free;
Johannes Berg4a4ab0d2012-06-13 11:17:11 +02007203 ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007204 if (ssid) {
Johannes Bergea73cbc2014-01-24 10:53:53 +01007205 if (WARN_ON(i >= n_match_sets)) {
7206 /* this indicates a programming error,
7207 * the loop above should have verified
7208 * things properly
7209 */
7210 err = -EINVAL;
7211 goto out_free;
7212 }
7213
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007214 if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
7215 err = -EINVAL;
7216 goto out_free;
7217 }
7218 memcpy(request->match_sets[i].ssid.ssid,
7219 nla_data(ssid), nla_len(ssid));
7220 request->match_sets[i].ssid.ssid_len =
7221 nla_len(ssid);
Kirtika Ruchandani56ab3642016-05-29 19:54:10 -07007222 /* special attribute - old implementation w/a */
Johannes Bergea73cbc2014-01-24 10:53:53 +01007223 request->match_sets[i].rssi_thold =
7224 default_match_rssi;
7225 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
7226 if (rssi)
7227 request->match_sets[i].rssi_thold =
7228 nla_get_s32(rssi);
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007229 }
7230 i++;
7231 }
Johannes Bergea73cbc2014-01-24 10:53:53 +01007232
7233 /* there was no other matchset, so the RSSI one is alone */
Luciano Coelhof89f46c2014-12-01 11:32:09 +02007234 if (i == 0 && n_match_sets)
Johannes Bergea73cbc2014-01-24 10:53:53 +01007235 request->match_sets[0].rssi_thold = default_match_rssi;
7236
7237 request->min_rssi_thold = INT_MAX;
7238 for (i = 0; i < n_match_sets; i++)
7239 request->min_rssi_thold =
7240 min(request->match_sets[i].rssi_thold,
7241 request->min_rssi_thold);
7242 } else {
7243 request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
Luciano Coelhoa1f1c212011-08-31 16:01:48 +03007244 }
7245
Johannes Berg9900e482014-02-04 21:01:25 +01007246 if (ie_len) {
7247 request->ie_len = ie_len;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007248 memcpy((void *)request->ie,
Luciano Coelho256da022014-11-10 16:13:46 +02007249 nla_data(attrs[NL80211_ATTR_IE]),
Luciano Coelho807f8a82011-05-11 17:09:35 +03007250 request->ie_len);
7251 }
7252
Luciano Coelho256da022014-11-10 16:13:46 +02007253 if (attrs[NL80211_ATTR_SCAN_FLAGS]) {
Sam Lefflered4737712012-10-11 21:03:31 -07007254 request->flags = nla_get_u32(
Luciano Coelho256da022014-11-10 16:13:46 +02007255 attrs[NL80211_ATTR_SCAN_FLAGS]);
Johannes Berg00c3a6e2013-10-26 17:14:38 +02007256 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
7257 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
Sam Leffler46856bb2012-10-11 21:03:32 -07007258 err = -EOPNOTSUPP;
7259 goto out_free;
7260 }
Johannes Bergad2b26a2014-06-12 21:39:05 +02007261
7262 if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
7263 u32 flg = NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
7264
7265 if (!wdev) /* must be net-detect */
7266 flg = NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
7267
7268 if (!(wiphy->features & flg)) {
7269 err = -EOPNOTSUPP;
7270 goto out_free;
7271 }
7272
7273 if (wdev && wdev->current_bss) {
7274 err = -EOPNOTSUPP;
7275 goto out_free;
7276 }
7277
7278 err = nl80211_parse_random_mac(attrs, request->mac_addr,
7279 request->mac_addr_mask);
7280 if (err)
7281 goto out_free;
7282 }
Sam Leffler46856bb2012-10-11 21:03:32 -07007283 }
Sam Lefflered4737712012-10-11 21:03:31 -07007284
Luciano Coelho9c748932015-01-16 16:04:09 +02007285 if (attrs[NL80211_ATTR_SCHED_SCAN_DELAY])
7286 request->delay =
7287 nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
7288
vamsi krishnabf95ecd2017-01-13 01:12:20 +02007289 if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
7290 request->relative_rssi = nla_get_s8(
7291 attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
7292 request->relative_rssi_set = true;
7293 }
7294
7295 if (request->relative_rssi_set &&
7296 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
7297 struct nl80211_bss_select_rssi_adjust *rssi_adjust;
7298
7299 rssi_adjust = nla_data(
7300 attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
7301 request->rssi_adjust.band = rssi_adjust->band;
7302 request->rssi_adjust.delta = rssi_adjust->delta;
7303 if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
7304 err = -EINVAL;
7305 goto out_free;
7306 }
7307 }
7308
Avraham Stern3b06d272015-10-12 09:51:34 +03007309 err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
7310 if (err)
7311 goto out_free;
7312
Sam Leffler15d60302012-10-11 21:03:34 -07007313 request->scan_start = jiffies;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007314
Luciano Coelho256da022014-11-10 16:13:46 +02007315 return request;
Luciano Coelho807f8a82011-05-11 17:09:35 +03007316
7317out_free:
7318 kfree(request);
Luciano Coelho256da022014-11-10 16:13:46 +02007319 return ERR_PTR(err);
7320}
7321
7322static int nl80211_start_sched_scan(struct sk_buff *skb,
7323 struct genl_info *info)
7324{
7325 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7326 struct net_device *dev = info->user_ptr[1];
Johannes Bergad2b26a2014-06-12 21:39:05 +02007327 struct wireless_dev *wdev = dev->ieee80211_ptr;
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007328 struct cfg80211_sched_scan_request *sched_scan_req;
Luciano Coelho256da022014-11-10 16:13:46 +02007329 int err;
7330
7331 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
7332 !rdev->ops->sched_scan_start)
7333 return -EOPNOTSUPP;
7334
7335 if (rdev->sched_scan_req)
7336 return -EINPROGRESS;
7337
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007338 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
Arend Van Sprielaad1e812017-01-27 12:27:44 +00007339 info->attrs,
7340 rdev->wiphy.max_match_sets);
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007341
7342 err = PTR_ERR_OR_ZERO(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007343 if (err)
7344 goto out_err;
7345
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007346 err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007347 if (err)
7348 goto out_free;
7349
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007350 sched_scan_req->dev = dev;
7351 sched_scan_req->wiphy = &rdev->wiphy;
7352
Jukka Rissanen93a1e862014-12-15 13:25:39 +02007353 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
7354 sched_scan_req->owner_nlportid = info->snd_portid;
7355
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007356 rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007357
7358 nl80211_send_sched_scan(rdev, dev,
7359 NL80211_CMD_START_SCHED_SCAN);
7360 return 0;
7361
7362out_free:
Jukka Rissanen31a60ed2014-12-15 13:25:38 +02007363 kfree(sched_scan_req);
Luciano Coelho256da022014-11-10 16:13:46 +02007364out_err:
Luciano Coelho807f8a82011-05-11 17:09:35 +03007365 return err;
7366}
7367
7368static int nl80211_stop_sched_scan(struct sk_buff *skb,
7369 struct genl_info *info)
7370{
7371 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7372
7373 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
7374 !rdev->ops->sched_scan_stop)
7375 return -EOPNOTSUPP;
7376
Johannes Berg5fe231e2013-05-08 21:45:15 +02007377 return __cfg80211_stop_sched_scan(rdev, false);
Luciano Coelho807f8a82011-05-11 17:09:35 +03007378}
7379
Simon Wunderlich04f39042013-02-08 18:16:19 +01007380static int nl80211_start_radar_detection(struct sk_buff *skb,
7381 struct genl_info *info)
7382{
7383 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7384 struct net_device *dev = info->user_ptr[1];
7385 struct wireless_dev *wdev = dev->ieee80211_ptr;
7386 struct cfg80211_chan_def chandef;
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007387 enum nl80211_dfs_regions dfs_region;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007388 unsigned int cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007389 int err;
7390
Luis R. Rodriguez55f74352013-11-25 20:56:10 +01007391 dfs_region = reg_get_dfs_region(wdev->wiphy);
7392 if (dfs_region == NL80211_DFS_UNSET)
7393 return -EINVAL;
7394
Simon Wunderlich04f39042013-02-08 18:16:19 +01007395 err = nl80211_parse_chandef(rdev, info, &chandef);
7396 if (err)
7397 return err;
7398
Simon Wunderlichff311bc2013-09-03 19:43:18 +02007399 if (netif_carrier_ok(dev))
7400 return -EBUSY;
7401
Simon Wunderlich04f39042013-02-08 18:16:19 +01007402 if (wdev->cac_started)
7403 return -EBUSY;
7404
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007405 err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
Luciano Coelho00ec75f2014-05-15 13:05:39 +03007406 wdev->iftype);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007407 if (err < 0)
7408 return err;
7409
7410 if (err == 0)
7411 return -EINVAL;
7412
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +01007413 if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
Simon Wunderlich04f39042013-02-08 18:16:19 +01007414 return -EINVAL;
7415
7416 if (!rdev->ops->start_radar_detection)
7417 return -EOPNOTSUPP;
7418
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007419 cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
7420 if (WARN_ON(!cac_time_ms))
7421 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
7422
Ilan Peera1056b12015-10-22 22:27:46 +03007423 err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
Simon Wunderlich04f39042013-02-08 18:16:19 +01007424 if (!err) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01007425 wdev->chandef = chandef;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007426 wdev->cac_started = true;
7427 wdev->cac_start_time = jiffies;
Janusz Dziedzic31559f32014-02-21 19:46:13 +01007428 wdev->cac_time_ms = cac_time_ms;
Simon Wunderlich04f39042013-02-08 18:16:19 +01007429 }
Simon Wunderlich04f39042013-02-08 18:16:19 +01007430 return err;
7431}
7432
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007433static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
7434{
7435 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7436 struct net_device *dev = info->user_ptr[1];
7437 struct wireless_dev *wdev = dev->ieee80211_ptr;
7438 struct cfg80211_csa_settings params;
7439 /* csa_attrs is defined static to avoid waste of stack size - this
7440 * function is called under RTNL lock, so this should not be a problem.
7441 */
7442 static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007443 int err;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007444 bool need_new_beacon = false;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007445 int len, i;
Luciano Coelho252e07c2014-10-08 09:48:34 +03007446 u32 cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007447
7448 if (!rdev->ops->channel_switch ||
7449 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
7450 return -EOPNOTSUPP;
7451
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007452 switch (dev->ieee80211_ptr->iftype) {
7453 case NL80211_IFTYPE_AP:
7454 case NL80211_IFTYPE_P2P_GO:
7455 need_new_beacon = true;
7456
7457 /* useless if AP is not running */
7458 if (!wdev->beacon_interval)
Johannes Berg1ff79df2014-01-22 10:05:27 +01007459 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007460 break;
7461 case NL80211_IFTYPE_ADHOC:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007462 if (!wdev->ssid_len)
7463 return -ENOTCONN;
7464 break;
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07007465 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg1ff79df2014-01-22 10:05:27 +01007466 if (!wdev->mesh_id_len)
7467 return -ENOTCONN;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007468 break;
7469 default:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007470 return -EOPNOTSUPP;
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007471 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007472
7473 memset(&params, 0, sizeof(params));
7474
7475 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
7476 !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
7477 return -EINVAL;
7478
7479 /* only important for AP, IBSS and mesh create IEs internally */
Andrei Otcheretianskid0a361a2013-10-17 10:52:17 +02007480 if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007481 return -EINVAL;
7482
Luciano Coelho252e07c2014-10-08 09:48:34 +03007483 /* Even though the attribute is u32, the specification says
7484 * u8, so let's make sure we don't overflow.
7485 */
7486 cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
7487 if (cs_count > 255)
7488 return -EINVAL;
7489
7490 params.count = cs_count;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007491
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007492 if (!need_new_beacon)
7493 goto skip_beacons;
7494
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007495 err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
7496 if (err)
7497 return err;
7498
7499 err = nla_parse_nested(csa_attrs, NL80211_ATTR_MAX,
7500 info->attrs[NL80211_ATTR_CSA_IES],
7501 nl80211_policy);
7502 if (err)
7503 return err;
7504
7505 err = nl80211_parse_beacon(csa_attrs, &params.beacon_csa);
7506 if (err)
7507 return err;
7508
7509 if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
7510 return -EINVAL;
7511
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007512 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7513 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007514 return -EINVAL;
7515
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007516 params.n_counter_offsets_beacon = len / sizeof(u16);
7517 if (rdev->wiphy.max_num_csa_counters &&
7518 (params.n_counter_offsets_beacon >
7519 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007520 return -EINVAL;
7521
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007522 params.counter_offsets_beacon =
7523 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
7524
7525 /* sanity checks - counters should fit and be the same */
7526 for (i = 0; i < params.n_counter_offsets_beacon; i++) {
7527 u16 offset = params.counter_offsets_beacon[i];
7528
7529 if (offset >= params.beacon_csa.tail_len)
7530 return -EINVAL;
7531
7532 if (params.beacon_csa.tail[offset] != params.count)
7533 return -EINVAL;
7534 }
7535
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007536 if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007537 len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7538 if (!len || (len % sizeof(u16)))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007539 return -EINVAL;
7540
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007541 params.n_counter_offsets_presp = len / sizeof(u16);
7542 if (rdev->wiphy.max_num_csa_counters &&
Johannes Bergad5987b2016-09-13 15:53:55 +02007543 (params.n_counter_offsets_presp >
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007544 rdev->wiphy.max_num_csa_counters))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007545 return -EINVAL;
Andrei Otcheretianski9a774c72014-05-09 14:11:46 +03007546
7547 params.counter_offsets_presp =
7548 nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
7549
7550 /* sanity checks - counters should fit and be the same */
7551 for (i = 0; i < params.n_counter_offsets_presp; i++) {
7552 u16 offset = params.counter_offsets_presp[i];
7553
7554 if (offset >= params.beacon_csa.probe_resp_len)
7555 return -EINVAL;
7556
7557 if (params.beacon_csa.probe_resp[offset] !=
7558 params.count)
7559 return -EINVAL;
7560 }
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007561 }
7562
Simon Wunderlichee4bc9e2013-08-28 13:41:33 +02007563skip_beacons:
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007564 err = nl80211_parse_chandef(rdev, info, &params.chandef);
7565 if (err)
7566 return err;
7567
Arik Nemtsov923b3522015-07-08 15:41:44 +03007568 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
7569 wdev->iftype))
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007570 return -EINVAL;
7571
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007572 err = cfg80211_chandef_dfs_required(wdev->wiphy,
7573 &params.chandef,
7574 wdev->iftype);
7575 if (err < 0)
7576 return err;
7577
Fabian Frederickdcc6c2f2014-10-25 17:57:35 +02007578 if (err > 0)
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02007579 params.radar_required = true;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007580
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007581 if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
7582 params.block_tx = true;
7583
Simon Wunderlichc56589e2013-11-21 18:19:49 +01007584 wdev_lock(wdev);
7585 err = rdev_channel_switch(rdev, dev, &params);
7586 wdev_unlock(wdev);
7587
7588 return err;
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +02007589}
7590
Johannes Berg9720bb32011-06-21 09:45:33 +02007591static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
7592 u32 seq, int flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007593 struct cfg80211_registered_device *rdev,
Johannes Berg48ab9052009-07-10 18:42:31 +02007594 struct wireless_dev *wdev,
7595 struct cfg80211_internal_bss *intbss)
Johannes Berg2a519312009-02-10 21:25:55 +01007596{
Johannes Berg48ab9052009-07-10 18:42:31 +02007597 struct cfg80211_bss *res = &intbss->pub;
Johannes Berg9caf0362012-11-29 01:25:20 +01007598 const struct cfg80211_bss_ies *ies;
Johannes Berg2a519312009-02-10 21:25:55 +01007599 void *hdr;
7600 struct nlattr *bss;
Johannes Berg48ab9052009-07-10 18:42:31 +02007601
7602 ASSERT_WDEV_LOCK(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007603
Eric W. Biederman15e47302012-09-07 20:12:54 +00007604 hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
Johannes Berg2a519312009-02-10 21:25:55 +01007605 NL80211_CMD_NEW_SCAN_RESULTS);
7606 if (!hdr)
7607 return -1;
7608
Johannes Berg9720bb32011-06-21 09:45:33 +02007609 genl_dump_check_consistent(cb, hdr, &nl80211_fam);
7610
Johannes Berg97990a02013-04-19 01:02:55 +02007611 if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
7612 goto nla_put_failure;
7613 if (wdev->netdev &&
David S. Miller9360ffd2012-03-29 04:41:26 -04007614 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
7615 goto nla_put_failure;
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007616 if (nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
7617 NL80211_ATTR_PAD))
Johannes Berg97990a02013-04-19 01:02:55 +02007618 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007619
7620 bss = nla_nest_start(msg, NL80211_ATTR_BSS);
7621 if (!bss)
7622 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -04007623 if ((!is_zero_ether_addr(res->bssid) &&
Johannes Berg9caf0362012-11-29 01:25:20 +01007624 nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
David S. Miller9360ffd2012-03-29 04:41:26 -04007625 goto nla_put_failure;
Johannes Berg9caf0362012-11-29 01:25:20 +01007626
7627 rcu_read_lock();
Johannes Berg0e227082014-08-12 20:34:30 +02007628 /* indicate whether we have probe response data or not */
7629 if (rcu_access_pointer(res->proberesp_ies) &&
7630 nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
7631 goto fail_unlock_rcu;
7632
7633 /* this pointer prefers to be pointed to probe response data
7634 * but is always valid
7635 */
Johannes Berg9caf0362012-11-29 01:25:20 +01007636 ies = rcu_dereference(res->ies);
Johannes Berg8cef2c92013-02-05 16:54:31 +01007637 if (ies) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007638 if (nla_put_u64_64bit(msg, NL80211_BSS_TSF, ies->tsf,
7639 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007640 goto fail_unlock_rcu;
Johannes Berg8cef2c92013-02-05 16:54:31 +01007641 if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
7642 ies->len, ies->data))
7643 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007644 }
Johannes Berg0e227082014-08-12 20:34:30 +02007645
7646 /* and this pointer is always (unless driver didn't know) beacon data */
Johannes Berg9caf0362012-11-29 01:25:20 +01007647 ies = rcu_dereference(res->beacon_ies);
Johannes Berg0e227082014-08-12 20:34:30 +02007648 if (ies && ies->from_beacon) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007649 if (nla_put_u64_64bit(msg, NL80211_BSS_BEACON_TSF, ies->tsf,
7650 NL80211_BSS_PAD))
Johannes Berg8cef2c92013-02-05 16:54:31 +01007651 goto fail_unlock_rcu;
7652 if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
7653 ies->len, ies->data))
7654 goto fail_unlock_rcu;
Johannes Berg9caf0362012-11-29 01:25:20 +01007655 }
7656 rcu_read_unlock();
7657
David S. Miller9360ffd2012-03-29 04:41:26 -04007658 if (res->beacon_interval &&
7659 nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
7660 goto nla_put_failure;
7661 if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
7662 nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
Simon Wunderlichdcd6eac2013-07-08 16:55:49 +02007663 nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
David S. Miller9360ffd2012-03-29 04:41:26 -04007664 nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
7665 jiffies_to_msecs(jiffies - intbss->ts)))
7666 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007667
Avraham Stern1d762502016-07-05 17:10:13 +03007668 if (intbss->parent_tsf &&
7669 (nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
7670 intbss->parent_tsf, NL80211_BSS_PAD) ||
7671 nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
7672 intbss->parent_bssid)))
7673 goto nla_put_failure;
7674
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007675 if (intbss->ts_boottime &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007676 nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
7677 intbss->ts_boottime, NL80211_BSS_PAD))
Dmitry Shmidt6e19bc42015-10-07 11:32:53 +02007678 goto nla_put_failure;
7679
Johannes Berg77965c92009-02-18 18:45:06 +01007680 switch (rdev->wiphy.signal_type) {
Johannes Berg2a519312009-02-10 21:25:55 +01007681 case CFG80211_SIGNAL_TYPE_MBM:
David S. Miller9360ffd2012-03-29 04:41:26 -04007682 if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
7683 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007684 break;
7685 case CFG80211_SIGNAL_TYPE_UNSPEC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007686 if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
7687 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +01007688 break;
7689 default:
7690 break;
7691 }
7692
Johannes Berg48ab9052009-07-10 18:42:31 +02007693 switch (wdev->iftype) {
Johannes Berg074ac8d2010-09-16 14:58:22 +02007694 case NL80211_IFTYPE_P2P_CLIENT:
Johannes Berg48ab9052009-07-10 18:42:31 +02007695 case NL80211_IFTYPE_STATION:
David S. Miller9360ffd2012-03-29 04:41:26 -04007696 if (intbss == wdev->current_bss &&
7697 nla_put_u32(msg, NL80211_BSS_STATUS,
7698 NL80211_BSS_STATUS_ASSOCIATED))
7699 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007700 break;
7701 case NL80211_IFTYPE_ADHOC:
David S. Miller9360ffd2012-03-29 04:41:26 -04007702 if (intbss == wdev->current_bss &&
7703 nla_put_u32(msg, NL80211_BSS_STATUS,
7704 NL80211_BSS_STATUS_IBSS_JOINED))
7705 goto nla_put_failure;
Johannes Berg48ab9052009-07-10 18:42:31 +02007706 break;
7707 default:
7708 break;
7709 }
7710
Johannes Berg2a519312009-02-10 21:25:55 +01007711 nla_nest_end(msg, bss);
7712
Johannes Berg053c0952015-01-16 22:09:00 +01007713 genlmsg_end(msg, hdr);
7714 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007715
Johannes Berg8cef2c92013-02-05 16:54:31 +01007716 fail_unlock_rcu:
7717 rcu_read_unlock();
Johannes Berg2a519312009-02-10 21:25:55 +01007718 nla_put_failure:
7719 genlmsg_cancel(msg, hdr);
7720 return -EMSGSIZE;
7721}
7722
Johannes Berg97990a02013-04-19 01:02:55 +02007723static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
Johannes Berg2a519312009-02-10 21:25:55 +01007724{
Johannes Berg48ab9052009-07-10 18:42:31 +02007725 struct cfg80211_registered_device *rdev;
Johannes Berg2a519312009-02-10 21:25:55 +01007726 struct cfg80211_internal_bss *scan;
Johannes Berg48ab9052009-07-10 18:42:31 +02007727 struct wireless_dev *wdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007728 int start = cb->args[2], idx = 0;
Johannes Berg2a519312009-02-10 21:25:55 +01007729 int err;
7730
Johannes Berg97990a02013-04-19 01:02:55 +02007731 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02007732 if (err)
7733 return err;
Johannes Berg2a519312009-02-10 21:25:55 +01007734
Johannes Berg48ab9052009-07-10 18:42:31 +02007735 wdev_lock(wdev);
7736 spin_lock_bh(&rdev->bss_lock);
7737 cfg80211_bss_expire(rdev);
7738
Johannes Berg9720bb32011-06-21 09:45:33 +02007739 cb->seq = rdev->bss_generation;
7740
Johannes Berg48ab9052009-07-10 18:42:31 +02007741 list_for_each_entry(scan, &rdev->bss_list, list) {
Johannes Berg2a519312009-02-10 21:25:55 +01007742 if (++idx <= start)
7743 continue;
Johannes Berg9720bb32011-06-21 09:45:33 +02007744 if (nl80211_send_bss(skb, cb,
Johannes Berg2a519312009-02-10 21:25:55 +01007745 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg48ab9052009-07-10 18:42:31 +02007746 rdev, wdev, scan) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +01007747 idx--;
Johannes Berg67748892010-10-04 21:14:06 +02007748 break;
Johannes Berg2a519312009-02-10 21:25:55 +01007749 }
7750 }
7751
Johannes Berg48ab9052009-07-10 18:42:31 +02007752 spin_unlock_bh(&rdev->bss_lock);
7753 wdev_unlock(wdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007754
Johannes Berg97990a02013-04-19 01:02:55 +02007755 cb->args[2] = idx;
7756 nl80211_finish_wdev_dump(rdev);
Johannes Berg2a519312009-02-10 21:25:55 +01007757
Johannes Berg67748892010-10-04 21:14:06 +02007758 return skb->len;
Johannes Berg2a519312009-02-10 21:25:55 +01007759}
7760
Eric W. Biederman15e47302012-09-07 20:12:54 +00007761static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
Johannes Berg11f78ac2014-11-14 16:43:50 +01007762 int flags, struct net_device *dev,
7763 bool allow_radio_stats,
7764 struct survey_info *survey)
Holger Schurig61fa7132009-11-11 12:25:40 +01007765{
7766 void *hdr;
7767 struct nlattr *infoattr;
7768
Johannes Berg11f78ac2014-11-14 16:43:50 +01007769 /* skip radio stats if userspace didn't request them */
7770 if (!survey->channel && !allow_radio_stats)
7771 return 0;
7772
Eric W. Biederman15e47302012-09-07 20:12:54 +00007773 hdr = nl80211hdr_put(msg, portid, seq, flags,
Holger Schurig61fa7132009-11-11 12:25:40 +01007774 NL80211_CMD_NEW_SURVEY_RESULTS);
7775 if (!hdr)
7776 return -ENOMEM;
7777
David S. Miller9360ffd2012-03-29 04:41:26 -04007778 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
7779 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01007780
7781 infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
7782 if (!infoattr)
7783 goto nla_put_failure;
7784
Johannes Berg11f78ac2014-11-14 16:43:50 +01007785 if (survey->channel &&
7786 nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
David S. Miller9360ffd2012-03-29 04:41:26 -04007787 survey->channel->center_freq))
7788 goto nla_put_failure;
7789
7790 if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
7791 nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
7792 goto nla_put_failure;
7793 if ((survey->filled & SURVEY_INFO_IN_USE) &&
7794 nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
7795 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007796 if ((survey->filled & SURVEY_INFO_TIME) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007797 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME,
7798 survey->time, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007799 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007800 if ((survey->filled & SURVEY_INFO_TIME_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007801 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_BUSY,
7802 survey->time_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007803 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007804 if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007805 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
7806 survey->time_ext_busy, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007807 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007808 if ((survey->filled & SURVEY_INFO_TIME_RX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007809 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_RX,
7810 survey->time_rx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007811 goto nla_put_failure;
Johannes Berg4ed20be2014-11-14 16:35:34 +01007812 if ((survey->filled & SURVEY_INFO_TIME_TX) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007813 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_TX,
7814 survey->time_tx, NL80211_SURVEY_INFO_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04007815 goto nla_put_failure;
Johannes Berg052536a2014-11-14 16:44:11 +01007816 if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02007817 nla_put_u64_64bit(msg, NL80211_SURVEY_INFO_TIME_SCAN,
7818 survey->time_scan, NL80211_SURVEY_INFO_PAD))
Johannes Berg052536a2014-11-14 16:44:11 +01007819 goto nla_put_failure;
Holger Schurig61fa7132009-11-11 12:25:40 +01007820
7821 nla_nest_end(msg, infoattr);
7822
Johannes Berg053c0952015-01-16 22:09:00 +01007823 genlmsg_end(msg, hdr);
7824 return 0;
Holger Schurig61fa7132009-11-11 12:25:40 +01007825
7826 nla_put_failure:
7827 genlmsg_cancel(msg, hdr);
7828 return -EMSGSIZE;
7829}
7830
Johannes Berg11f78ac2014-11-14 16:43:50 +01007831static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
Holger Schurig61fa7132009-11-11 12:25:40 +01007832{
Johannes Bergc90c39d2016-10-24 14:40:01 +02007833 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
Holger Schurig61fa7132009-11-11 12:25:40 +01007834 struct survey_info survey;
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007835 struct cfg80211_registered_device *rdev;
Johannes Berg97990a02013-04-19 01:02:55 +02007836 struct wireless_dev *wdev;
7837 int survey_idx = cb->args[2];
Holger Schurig61fa7132009-11-11 12:25:40 +01007838 int res;
Johannes Berg11f78ac2014-11-14 16:43:50 +01007839 bool radio_stats;
Holger Schurig61fa7132009-11-11 12:25:40 +01007840
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007841 res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
Johannes Berg67748892010-10-04 21:14:06 +02007842 if (res)
7843 return res;
Holger Schurig61fa7132009-11-11 12:25:40 +01007844
Johannes Berg11f78ac2014-11-14 16:43:50 +01007845 /* prepare_wdev_dump parsed the attributes */
Johannes Bergc90c39d2016-10-24 14:40:01 +02007846 radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
Johannes Berg11f78ac2014-11-14 16:43:50 +01007847
Johannes Berg97990a02013-04-19 01:02:55 +02007848 if (!wdev->netdev) {
7849 res = -EINVAL;
7850 goto out_err;
7851 }
7852
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007853 if (!rdev->ops->dump_survey) {
Holger Schurig61fa7132009-11-11 12:25:40 +01007854 res = -EOPNOTSUPP;
7855 goto out_err;
7856 }
7857
7858 while (1) {
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007859 res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
Holger Schurig61fa7132009-11-11 12:25:40 +01007860 if (res == -ENOENT)
7861 break;
7862 if (res)
7863 goto out_err;
7864
Johannes Berg11f78ac2014-11-14 16:43:50 +01007865 /* don't send disabled channels, but do send non-channel data */
7866 if (survey.channel &&
7867 survey.channel->flags & IEEE80211_CHAN_DISABLED) {
Luis R. Rodriguez180cdc72011-05-27 07:24:02 -07007868 survey_idx++;
7869 continue;
7870 }
7871
Holger Schurig61fa7132009-11-11 12:25:40 +01007872 if (nl80211_send_survey(skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00007873 NETLINK_CB(cb->skb).portid,
Holger Schurig61fa7132009-11-11 12:25:40 +01007874 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Johannes Berg11f78ac2014-11-14 16:43:50 +01007875 wdev->netdev, radio_stats, &survey) < 0)
Holger Schurig61fa7132009-11-11 12:25:40 +01007876 goto out;
7877 survey_idx++;
7878 }
7879
7880 out:
Johannes Berg97990a02013-04-19 01:02:55 +02007881 cb->args[2] = survey_idx;
Holger Schurig61fa7132009-11-11 12:25:40 +01007882 res = skb->len;
7883 out_err:
Zhao, Gang1b8ec872014-04-21 12:53:02 +08007884 nl80211_finish_wdev_dump(rdev);
Holger Schurig61fa7132009-11-11 12:25:40 +01007885 return res;
7886}
7887
Samuel Ortizb23aa672009-07-01 21:26:54 +02007888static bool nl80211_valid_wpa_versions(u32 wpa_versions)
7889{
7890 return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
7891 NL80211_WPA_VERSION_2));
7892}
7893
Jouni Malinen636a5d32009-03-19 13:39:22 +02007894static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
7895{
Johannes Berg4c476992010-10-04 21:36:35 +02007896 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7897 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02007898 struct ieee80211_channel *chan;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007899 const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
7900 int err, ssid_len, ie_len = 0, auth_data_len = 0;
Johannes Berg19957bb2009-07-02 17:20:43 +02007901 enum nl80211_auth_type auth_type;
Johannes Bergfffd0932009-07-08 14:22:54 +02007902 struct key_parse key;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03007903 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007904
Johannes Bergf4a11bb2009-03-27 12:40:28 +01007905 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
7906 return -EINVAL;
7907
7908 if (!info->attrs[NL80211_ATTR_MAC])
7909 return -EINVAL;
7910
Jouni Malinen17780922009-03-27 20:52:47 +02007911 if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
7912 return -EINVAL;
7913
Johannes Berg19957bb2009-07-02 17:20:43 +02007914 if (!info->attrs[NL80211_ATTR_SSID])
7915 return -EINVAL;
7916
7917 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
7918 return -EINVAL;
7919
Johannes Bergfffd0932009-07-08 14:22:54 +02007920 err = nl80211_parse_key(info, &key);
7921 if (err)
7922 return err;
7923
7924 if (key.idx >= 0) {
Johannes Berge31b8212010-10-05 19:39:30 +02007925 if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
7926 return -EINVAL;
Johannes Bergfffd0932009-07-08 14:22:54 +02007927 if (!key.p.key || !key.p.key_len)
7928 return -EINVAL;
7929 if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
7930 key.p.key_len != WLAN_KEY_LEN_WEP40) &&
7931 (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
7932 key.p.key_len != WLAN_KEY_LEN_WEP104))
7933 return -EINVAL;
Johannes Bergb6b55552016-09-13 16:25:58 +02007934 if (key.idx > 3)
Johannes Bergfffd0932009-07-08 14:22:54 +02007935 return -EINVAL;
7936 } else {
7937 key.p.key_len = 0;
7938 key.p.key = NULL;
7939 }
7940
Johannes Bergafea0b72010-08-10 09:46:42 +02007941 if (key.idx >= 0) {
7942 int i;
7943 bool ok = false;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07007944
Johannes Bergafea0b72010-08-10 09:46:42 +02007945 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
7946 if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
7947 ok = true;
7948 break;
7949 }
7950 }
Johannes Berg4c476992010-10-04 21:36:35 +02007951 if (!ok)
7952 return -EINVAL;
Johannes Bergafea0b72010-08-10 09:46:42 +02007953 }
7954
Johannes Berg4c476992010-10-04 21:36:35 +02007955 if (!rdev->ops->auth)
7956 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007957
Johannes Berg074ac8d2010-09-16 14:58:22 +02007958 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02007959 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
7960 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02007961
Johannes Berg19957bb2009-07-02 17:20:43 +02007962 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen664834d2014-01-15 00:01:44 +02007963 chan = nl80211_get_valid_chan(&rdev->wiphy,
7964 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
7965 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02007966 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02007967
Johannes Berg19957bb2009-07-02 17:20:43 +02007968 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
7969 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
7970
7971 if (info->attrs[NL80211_ATTR_IE]) {
7972 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
7973 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
7974 }
7975
7976 auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03007977 if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
Johannes Berg4c476992010-10-04 21:36:35 +02007978 return -EINVAL;
Johannes Berg19957bb2009-07-02 17:20:43 +02007979
Jouni Malinen63181062016-10-27 00:42:02 +03007980 if ((auth_type == NL80211_AUTHTYPE_SAE ||
7981 auth_type == NL80211_AUTHTYPE_FILS_SK ||
7982 auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
7983 auth_type == NL80211_AUTHTYPE_FILS_PK) &&
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007984 !info->attrs[NL80211_ATTR_AUTH_DATA])
Jouni Malinene39e5b52012-09-30 19:29:39 +03007985 return -EINVAL;
7986
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007987 if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
Jouni Malinen63181062016-10-27 00:42:02 +03007988 if (auth_type != NL80211_AUTHTYPE_SAE &&
7989 auth_type != NL80211_AUTHTYPE_FILS_SK &&
7990 auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
7991 auth_type != NL80211_AUTHTYPE_FILS_PK)
Jouni Malinene39e5b52012-09-30 19:29:39 +03007992 return -EINVAL;
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007993 auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
7994 auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03007995 /* need to include at least Auth Transaction and Status Code */
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03007996 if (auth_data_len < 4)
Jouni Malinene39e5b52012-09-30 19:29:39 +03007997 return -EINVAL;
7998 }
7999
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008000 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8001
Johannes Berg95de8172012-01-20 13:55:25 +01008002 /*
8003 * Since we no longer track auth state, ignore
8004 * requests to only change local state.
8005 */
8006 if (local_state_change)
8007 return 0;
8008
Johannes Berg91bf9b22013-05-15 17:44:01 +02008009 wdev_lock(dev->ieee80211_ptr);
8010 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
8011 ssid, ssid_len, ie, ie_len,
8012 key.p.key, key.p.key_len, key.idx,
Jouni Malinen11b6b5a2016-10-27 00:41:58 +03008013 auth_data, auth_data_len);
Johannes Berg91bf9b22013-05-15 17:44:01 +02008014 wdev_unlock(dev->ieee80211_ptr);
8015 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008016}
8017
Johannes Bergc0692b82010-08-27 14:26:53 +03008018static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
8019 struct genl_info *info,
Johannes Berg3dc27d22009-07-02 21:36:37 +02008020 struct cfg80211_crypto_settings *settings,
8021 int cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02008022{
Johannes Bergc0b2bbd2009-07-25 16:54:36 +02008023 memset(settings, 0, sizeof(*settings));
8024
Samuel Ortizb23aa672009-07-01 21:26:54 +02008025 settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
8026
Johannes Bergc0692b82010-08-27 14:26:53 +03008027 if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
8028 u16 proto;
Kirtika Ruchandani7a087e72016-05-29 19:51:23 -07008029
Johannes Bergc0692b82010-08-27 14:26:53 +03008030 proto = nla_get_u16(
8031 info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
8032 settings->control_port_ethertype = cpu_to_be16(proto);
8033 if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
8034 proto != ETH_P_PAE)
8035 return -EINVAL;
8036 if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
8037 settings->control_port_no_encrypt = true;
8038 } else
8039 settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
8040
Samuel Ortizb23aa672009-07-01 21:26:54 +02008041 if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
8042 void *data;
8043 int len, i;
8044
8045 data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
8046 len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
8047 settings->n_ciphers_pairwise = len / sizeof(u32);
8048
8049 if (len % sizeof(u32))
8050 return -EINVAL;
8051
Johannes Berg3dc27d22009-07-02 21:36:37 +02008052 if (settings->n_ciphers_pairwise > cipher_limit)
Samuel Ortizb23aa672009-07-01 21:26:54 +02008053 return -EINVAL;
8054
8055 memcpy(settings->ciphers_pairwise, data, len);
8056
8057 for (i = 0; i < settings->n_ciphers_pairwise; i++)
Jouni Malinen38ba3c52011-09-21 18:14:56 +03008058 if (!cfg80211_supported_cipher_suite(
8059 &rdev->wiphy,
Samuel Ortizb23aa672009-07-01 21:26:54 +02008060 settings->ciphers_pairwise[i]))
8061 return -EINVAL;
8062 }
8063
8064 if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
8065 settings->cipher_group =
8066 nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
Jouni Malinen38ba3c52011-09-21 18:14:56 +03008067 if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
8068 settings->cipher_group))
Samuel Ortizb23aa672009-07-01 21:26:54 +02008069 return -EINVAL;
8070 }
8071
8072 if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
8073 settings->wpa_versions =
8074 nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
8075 if (!nl80211_valid_wpa_versions(settings->wpa_versions))
8076 return -EINVAL;
8077 }
8078
8079 if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
8080 void *data;
Jouni Malinen6d302402011-09-21 18:11:33 +03008081 int len;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008082
8083 data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
8084 len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
8085 settings->n_akm_suites = len / sizeof(u32);
8086
8087 if (len % sizeof(u32))
8088 return -EINVAL;
8089
Jouni Malinen1b9ca022011-09-21 16:13:07 +03008090 if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
8091 return -EINVAL;
8092
Samuel Ortizb23aa672009-07-01 21:26:54 +02008093 memcpy(settings->akm_suites, data, len);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008094 }
8095
8096 return 0;
8097}
8098
Jouni Malinen636a5d32009-03-19 13:39:22 +02008099static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
8100{
Johannes Berg4c476992010-10-04 21:36:35 +02008101 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8102 struct net_device *dev = info->user_ptr[1];
Johannes Bergf444de02010-05-05 15:25:02 +02008103 struct ieee80211_channel *chan;
Johannes Bergf62fab72013-02-21 20:09:09 +01008104 struct cfg80211_assoc_request req = {};
8105 const u8 *bssid, *ssid;
8106 int err, ssid_len = 0;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008107
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008108 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8109 return -EINVAL;
8110
8111 if (!info->attrs[NL80211_ATTR_MAC] ||
Johannes Berg19957bb2009-07-02 17:20:43 +02008112 !info->attrs[NL80211_ATTR_SSID] ||
8113 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008114 return -EINVAL;
8115
Johannes Berg4c476992010-10-04 21:36:35 +02008116 if (!rdev->ops->assoc)
8117 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008118
Johannes Berg074ac8d2010-09-16 14:58:22 +02008119 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008120 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8121 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008122
Johannes Berg19957bb2009-07-02 17:20:43 +02008123 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008124
Jouni Malinen664834d2014-01-15 00:01:44 +02008125 chan = nl80211_get_valid_chan(&rdev->wiphy,
8126 info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8127 if (!chan)
Johannes Berg4c476992010-10-04 21:36:35 +02008128 return -EINVAL;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008129
Johannes Berg19957bb2009-07-02 17:20:43 +02008130 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8131 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008132
8133 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008134 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8135 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008136 }
8137
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008138 if (info->attrs[NL80211_ATTR_USE_MFP]) {
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008139 enum nl80211_mfp mfp =
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008140 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
Johannes Berg4f5dadc2009-07-07 03:56:10 +02008141 if (mfp == NL80211_MFP_REQUIRED)
Johannes Bergf62fab72013-02-21 20:09:09 +01008142 req.use_mfp = true;
Johannes Berg4c476992010-10-04 21:36:35 +02008143 else if (mfp != NL80211_MFP_NO)
8144 return -EINVAL;
Jouni Malinendc6382ce2009-05-06 22:09:37 +03008145 }
8146
Johannes Berg3e5d7642009-07-07 14:37:26 +02008147 if (info->attrs[NL80211_ATTR_PREV_BSSID])
Johannes Bergf62fab72013-02-21 20:09:09 +01008148 req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
Johannes Berg3e5d7642009-07-07 14:37:26 +02008149
Ben Greear7e7c8922011-11-18 11:31:59 -08008150 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008151 req.flags |= ASSOC_REQ_DISABLE_HT;
Ben Greear7e7c8922011-11-18 11:31:59 -08008152
8153 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008154 memcpy(&req.ht_capa_mask,
8155 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8156 sizeof(req.ht_capa_mask));
Ben Greear7e7c8922011-11-18 11:31:59 -08008157
8158 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008159 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
Ben Greear7e7c8922011-11-18 11:31:59 -08008160 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008161 memcpy(&req.ht_capa,
8162 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8163 sizeof(req.ht_capa));
Ben Greear7e7c8922011-11-18 11:31:59 -08008164 }
8165
Johannes Bergee2aca32013-02-21 17:36:01 +01008166 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
Johannes Bergf62fab72013-02-21 20:09:09 +01008167 req.flags |= ASSOC_REQ_DISABLE_VHT;
Johannes Bergee2aca32013-02-21 17:36:01 +01008168
8169 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergf62fab72013-02-21 20:09:09 +01008170 memcpy(&req.vht_capa_mask,
8171 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
8172 sizeof(req.vht_capa_mask));
Johannes Bergee2aca32013-02-21 17:36:01 +01008173
8174 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
Johannes Bergf62fab72013-02-21 20:09:09 +01008175 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
Johannes Bergee2aca32013-02-21 17:36:01 +01008176 return -EINVAL;
Johannes Bergf62fab72013-02-21 20:09:09 +01008177 memcpy(&req.vht_capa,
8178 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
8179 sizeof(req.vht_capa));
Johannes Bergee2aca32013-02-21 17:36:01 +01008180 }
8181
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008182 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02008183 if (!((rdev->wiphy.features &
8184 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
8185 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
8186 !wiphy_ext_feature_isset(&rdev->wiphy,
8187 NL80211_EXT_FEATURE_RRM))
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008188 return -EINVAL;
8189 req.flags |= ASSOC_REQ_USE_RRM;
8190 }
8191
Jouni Malinen348bd452016-10-27 00:42:03 +03008192 if (info->attrs[NL80211_ATTR_FILS_KEK]) {
8193 req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
8194 req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
8195 if (!info->attrs[NL80211_ATTR_FILS_NONCES])
8196 return -EINVAL;
8197 req.fils_nonces =
8198 nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
8199 }
8200
Johannes Bergf62fab72013-02-21 20:09:09 +01008201 err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
Johannes Berg91bf9b22013-05-15 17:44:01 +02008202 if (!err) {
8203 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008204
Johannes Bergf62fab72013-02-21 20:09:09 +01008205 err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
8206 ssid, ssid_len, &req);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008207
8208 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8209 dev->ieee80211_ptr->conn_owner_nlportid =
8210 info->snd_portid;
8211 memcpy(dev->ieee80211_ptr->disconnect_bssid,
8212 bssid, ETH_ALEN);
8213 }
8214
Johannes Berg91bf9b22013-05-15 17:44:01 +02008215 wdev_unlock(dev->ieee80211_ptr);
8216 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008217
Jouni Malinen636a5d32009-03-19 13:39:22 +02008218 return err;
8219}
8220
8221static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
8222{
Johannes Berg4c476992010-10-04 21:36:35 +02008223 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8224 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008225 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008226 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008227 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008228 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008229
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008230 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8231 return -EINVAL;
8232
8233 if (!info->attrs[NL80211_ATTR_MAC])
8234 return -EINVAL;
8235
8236 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8237 return -EINVAL;
8238
Johannes Berg4c476992010-10-04 21:36:35 +02008239 if (!rdev->ops->deauth)
8240 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008241
Johannes Berg074ac8d2010-09-16 14:58:22 +02008242 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008243 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8244 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008245
Johannes Berg19957bb2009-07-02 17:20:43 +02008246 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008247
Johannes Berg19957bb2009-07-02 17:20:43 +02008248 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8249 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008250 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008251 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008252 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008253
8254 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008255 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8256 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008257 }
8258
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008259 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8260
Johannes Berg91bf9b22013-05-15 17:44:01 +02008261 wdev_lock(dev->ieee80211_ptr);
8262 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
8263 local_state_change);
8264 wdev_unlock(dev->ieee80211_ptr);
8265 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008266}
8267
8268static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
8269{
Johannes Berg4c476992010-10-04 21:36:35 +02008270 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8271 struct net_device *dev = info->user_ptr[1];
Johannes Berg19957bb2009-07-02 17:20:43 +02008272 const u8 *ie = NULL, *bssid;
Johannes Berg91bf9b22013-05-15 17:44:01 +02008273 int ie_len = 0, err;
Johannes Berg19957bb2009-07-02 17:20:43 +02008274 u16 reason_code;
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008275 bool local_state_change;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008276
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008277 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8278 return -EINVAL;
8279
8280 if (!info->attrs[NL80211_ATTR_MAC])
8281 return -EINVAL;
8282
8283 if (!info->attrs[NL80211_ATTR_REASON_CODE])
8284 return -EINVAL;
8285
Johannes Berg4c476992010-10-04 21:36:35 +02008286 if (!rdev->ops->disassoc)
8287 return -EOPNOTSUPP;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008288
Johannes Berg074ac8d2010-09-16 14:58:22 +02008289 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008290 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8291 return -EOPNOTSUPP;
Jouni Malineneec60b02009-03-20 21:21:19 +02008292
Johannes Berg19957bb2009-07-02 17:20:43 +02008293 bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008294
Johannes Berg19957bb2009-07-02 17:20:43 +02008295 reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
8296 if (reason_code == 0) {
Johannes Bergf4a11bb2009-03-27 12:40:28 +01008297 /* Reason Code 0 is reserved */
Johannes Berg4c476992010-10-04 21:36:35 +02008298 return -EINVAL;
Jouni Malinen255e7372009-03-20 21:21:17 +02008299 }
Jouni Malinen636a5d32009-03-19 13:39:22 +02008300
8301 if (info->attrs[NL80211_ATTR_IE]) {
Johannes Berg19957bb2009-07-02 17:20:43 +02008302 ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8303 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
Jouni Malinen636a5d32009-03-19 13:39:22 +02008304 }
8305
Jouni Malinend5cdfac2010-04-04 09:37:19 +03008306 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
8307
Johannes Berg91bf9b22013-05-15 17:44:01 +02008308 wdev_lock(dev->ieee80211_ptr);
8309 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
8310 local_state_change);
8311 wdev_unlock(dev->ieee80211_ptr);
8312 return err;
Jouni Malinen636a5d32009-03-19 13:39:22 +02008313}
8314
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008315static bool
8316nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
Johannes Berg57fbcce2016-04-12 15:56:15 +02008317 int mcast_rate[NUM_NL80211_BANDS],
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008318 int rateval)
8319{
8320 struct wiphy *wiphy = &rdev->wiphy;
8321 bool found = false;
8322 int band, i;
8323
Johannes Berg57fbcce2016-04-12 15:56:15 +02008324 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008325 struct ieee80211_supported_band *sband;
8326
8327 sband = wiphy->bands[band];
8328 if (!sband)
8329 continue;
8330
8331 for (i = 0; i < sband->n_bitrates; i++) {
8332 if (sband->bitrates[i].bitrate == rateval) {
8333 mcast_rate[band] = i + 1;
8334 found = true;
8335 break;
8336 }
8337 }
8338 }
8339
8340 return found;
8341}
8342
Johannes Berg04a773a2009-04-19 21:24:32 +02008343static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
8344{
Johannes Berg4c476992010-10-04 21:36:35 +02008345 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8346 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008347 struct cfg80211_ibss_params ibss;
8348 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008349 struct cfg80211_cached_keys *connkeys = NULL;
Johannes Berg04a773a2009-04-19 21:24:32 +02008350 int err;
8351
Johannes Berg8e30bc52009-04-22 17:45:38 +02008352 memset(&ibss, 0, sizeof(ibss));
8353
Johannes Berg04a773a2009-04-19 21:24:32 +02008354 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8355 return -EINVAL;
8356
Johannes Berg683b6d32012-11-08 21:25:48 +01008357 if (!info->attrs[NL80211_ATTR_SSID] ||
Johannes Berg04a773a2009-04-19 21:24:32 +02008358 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8359 return -EINVAL;
8360
Johannes Berg8e30bc52009-04-22 17:45:38 +02008361 ibss.beacon_interval = 100;
8362
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308363 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
Johannes Berg8e30bc52009-04-22 17:45:38 +02008364 ibss.beacon_interval =
8365 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308366
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05308367 err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
8368 ibss.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05308369 if (err)
8370 return err;
Johannes Berg8e30bc52009-04-22 17:45:38 +02008371
Johannes Berg4c476992010-10-04 21:36:35 +02008372 if (!rdev->ops->join_ibss)
8373 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008374
Johannes Berg4c476992010-10-04 21:36:35 +02008375 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8376 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008377
Johannes Berg79c97e92009-07-07 03:56:12 +02008378 wiphy = &rdev->wiphy;
Johannes Berg04a773a2009-04-19 21:24:32 +02008379
Johannes Berg39193492011-09-16 13:45:25 +02008380 if (info->attrs[NL80211_ATTR_MAC]) {
Johannes Berg04a773a2009-04-19 21:24:32 +02008381 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Johannes Berg39193492011-09-16 13:45:25 +02008382
8383 if (!is_valid_ether_addr(ibss.bssid))
8384 return -EINVAL;
8385 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008386 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8387 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8388
8389 if (info->attrs[NL80211_ATTR_IE]) {
8390 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8391 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8392 }
8393
Johannes Berg683b6d32012-11-08 21:25:48 +01008394 err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
8395 if (err)
8396 return err;
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008397
Ilan Peer174e0cd2014-02-23 09:13:01 +02008398 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
8399 NL80211_IFTYPE_ADHOC))
Alexander Simon54858ee5b2011-11-30 16:56:32 +01008400 return -EINVAL;
8401
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008402 switch (ibss.chandef.width) {
Simon Wunderlichbf372642013-07-08 16:55:58 +02008403 case NL80211_CHAN_WIDTH_5:
8404 case NL80211_CHAN_WIDTH_10:
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008405 case NL80211_CHAN_WIDTH_20_NOHT:
8406 break;
8407 case NL80211_CHAN_WIDTH_20:
8408 case NL80211_CHAN_WIDTH_40:
Janusz.Dziedzic@tieto.comffc11992015-02-21 16:52:39 +01008409 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8410 return -EINVAL;
8411 break;
8412 case NL80211_CHAN_WIDTH_80:
8413 case NL80211_CHAN_WIDTH_80P80:
8414 case NL80211_CHAN_WIDTH_160:
8415 if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
8416 return -EINVAL;
8417 if (!wiphy_ext_feature_isset(&rdev->wiphy,
8418 NL80211_EXT_FEATURE_VHT_IBSS))
8419 return -EINVAL;
8420 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008421 default:
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008422 return -EINVAL;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02008423 }
Johannes Bergdb9c64c2012-11-09 14:56:41 +01008424
Johannes Berg04a773a2009-04-19 21:24:32 +02008425 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
Johannes Bergfffd0932009-07-08 14:22:54 +02008426 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
Johannes Berg04a773a2009-04-19 21:24:32 +02008427
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008428 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
8429 u8 *rates =
8430 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8431 int n_rates =
8432 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
8433 struct ieee80211_supported_band *sband =
Johannes Berg683b6d32012-11-08 21:25:48 +01008434 wiphy->bands[ibss.chandef.chan->band];
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008435
Johannes Berg34850ab2011-07-18 18:08:35 +02008436 err = ieee80211_get_ratemask(sband, rates, n_rates,
8437 &ibss.basic_rates);
8438 if (err)
8439 return err;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008440 }
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008441
Simon Wunderlich803768f2013-06-28 10:39:58 +02008442 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8443 memcpy(&ibss.ht_capa_mask,
8444 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8445 sizeof(ibss.ht_capa_mask));
8446
8447 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
8448 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8449 return -EINVAL;
8450 memcpy(&ibss.ht_capa,
8451 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8452 sizeof(ibss.ht_capa));
8453 }
8454
Felix Fietkaudd5b4cc2010-11-22 20:58:24 +01008455 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
8456 !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
8457 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
8458 return -EINVAL;
Teemu Paasikivifbd2c8d2010-06-14 12:55:31 +03008459
Johannes Berg4c476992010-10-04 21:36:35 +02008460 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
Sujith Manoharande7044e2012-10-18 10:19:28 +05308461 bool no_ht = false;
8462
Johannes Berg4c476992010-10-04 21:36:35 +02008463 connkeys = nl80211_parse_connkeys(rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +05308464 info->attrs[NL80211_ATTR_KEYS],
8465 &no_ht);
Johannes Berg4c476992010-10-04 21:36:35 +02008466 if (IS_ERR(connkeys))
8467 return PTR_ERR(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308468
Johannes Berg3d9d1d62012-11-08 23:14:50 +01008469 if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
8470 no_ht) {
Ola Olsson5e950a72016-02-11 01:00:22 +01008471 kzfree(connkeys);
Sujith Manoharande7044e2012-10-18 10:19:28 +05308472 return -EINVAL;
8473 }
Johannes Berg4c476992010-10-04 21:36:35 +02008474 }
Johannes Berg04a773a2009-04-19 21:24:32 +02008475
Antonio Quartulli267335d2012-01-31 20:25:47 +01008476 ibss.control_port =
8477 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
8478
Simon Wunderlich5336fa82013-10-07 18:41:05 +02008479 ibss.userspace_handles_dfs =
8480 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
8481
Johannes Berg4c476992010-10-04 21:36:35 +02008482 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02008483 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03008484 kzfree(connkeys);
Johannes Berg04a773a2009-04-19 21:24:32 +02008485 return err;
8486}
8487
8488static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
8489{
Johannes Berg4c476992010-10-04 21:36:35 +02008490 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8491 struct net_device *dev = info->user_ptr[1];
Johannes Berg04a773a2009-04-19 21:24:32 +02008492
Johannes Berg4c476992010-10-04 21:36:35 +02008493 if (!rdev->ops->leave_ibss)
8494 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008495
Johannes Berg4c476992010-10-04 21:36:35 +02008496 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
8497 return -EOPNOTSUPP;
Johannes Berg04a773a2009-04-19 21:24:32 +02008498
Johannes Berg4c476992010-10-04 21:36:35 +02008499 return cfg80211_leave_ibss(rdev, dev, false);
Johannes Berg04a773a2009-04-19 21:24:32 +02008500}
8501
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008502static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
8503{
8504 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8505 struct net_device *dev = info->user_ptr[1];
Johannes Berg57fbcce2016-04-12 15:56:15 +02008506 int mcast_rate[NUM_NL80211_BANDS];
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008507 u32 nla_rate;
8508 int err;
8509
8510 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
Bertold Van den Bergh876dc932015-08-05 16:02:21 +02008511 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
8512 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008513 return -EOPNOTSUPP;
8514
8515 if (!rdev->ops->set_mcast_rate)
8516 return -EOPNOTSUPP;
8517
8518 memset(mcast_rate, 0, sizeof(mcast_rate));
8519
8520 if (!info->attrs[NL80211_ATTR_MCAST_RATE])
8521 return -EINVAL;
8522
8523 nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
8524 if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
8525 return -EINVAL;
8526
Ilan Peera1056b12015-10-22 22:27:46 +03008527 err = rdev_set_mcast_rate(rdev, dev, mcast_rate);
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008528
8529 return err;
8530}
8531
Johannes Bergad7e7182013-11-13 13:37:47 +01008532static struct sk_buff *
8533__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008534 struct wireless_dev *wdev, int approxlen,
8535 u32 portid, u32 seq, enum nl80211_commands cmd,
Johannes Berg567ffc32013-12-18 14:43:31 +01008536 enum nl80211_attrs attr,
8537 const struct nl80211_vendor_cmd_info *info,
8538 gfp_t gfp)
Johannes Bergad7e7182013-11-13 13:37:47 +01008539{
8540 struct sk_buff *skb;
8541 void *hdr;
8542 struct nlattr *data;
8543
8544 skb = nlmsg_new(approxlen + 100, gfp);
8545 if (!skb)
8546 return NULL;
8547
8548 hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
8549 if (!hdr) {
8550 kfree_skb(skb);
8551 return NULL;
8552 }
8553
8554 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
8555 goto nla_put_failure;
Johannes Berg567ffc32013-12-18 14:43:31 +01008556
8557 if (info) {
8558 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
8559 info->vendor_id))
8560 goto nla_put_failure;
8561 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
8562 info->subcmd))
8563 goto nla_put_failure;
8564 }
8565
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008566 if (wdev) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02008567 if (nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
8568 wdev_id(wdev), NL80211_ATTR_PAD))
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008569 goto nla_put_failure;
8570 if (wdev->netdev &&
8571 nla_put_u32(skb, NL80211_ATTR_IFINDEX,
8572 wdev->netdev->ifindex))
8573 goto nla_put_failure;
8574 }
8575
Johannes Bergad7e7182013-11-13 13:37:47 +01008576 data = nla_nest_start(skb, attr);
Johannes Berg76e1fb42016-09-14 09:55:57 +02008577 if (!data)
8578 goto nla_put_failure;
Johannes Bergad7e7182013-11-13 13:37:47 +01008579
8580 ((void **)skb->cb)[0] = rdev;
8581 ((void **)skb->cb)[1] = hdr;
8582 ((void **)skb->cb)[2] = data;
8583
8584 return skb;
8585
8586 nla_put_failure:
8587 kfree_skb(skb);
8588 return NULL;
8589}
Antonio Quartullif4e583c2012-11-02 13:27:48 +01008590
Johannes Berge03ad6e2014-01-01 17:22:30 +01008591struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008592 struct wireless_dev *wdev,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008593 enum nl80211_commands cmd,
8594 enum nl80211_attrs attr,
8595 int vendor_event_idx,
8596 int approxlen, gfp_t gfp)
8597{
Zhao, Gangf26cbf42014-04-21 12:53:03 +08008598 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berge03ad6e2014-01-01 17:22:30 +01008599 const struct nl80211_vendor_cmd_info *info;
8600
8601 switch (cmd) {
8602 case NL80211_CMD_TESTMODE:
8603 if (WARN_ON(vendor_event_idx != -1))
8604 return NULL;
8605 info = NULL;
8606 break;
8607 case NL80211_CMD_VENDOR:
8608 if (WARN_ON(vendor_event_idx < 0 ||
8609 vendor_event_idx >= wiphy->n_vendor_events))
8610 return NULL;
8611 info = &wiphy->vendor_events[vendor_event_idx];
8612 break;
8613 default:
8614 WARN_ON(1);
8615 return NULL;
8616 }
8617
Ahmad Kholaif6c09e792015-02-26 15:26:53 +02008618 return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
Johannes Berge03ad6e2014-01-01 17:22:30 +01008619 cmd, attr, info, gfp);
8620}
8621EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
8622
8623void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
8624{
8625 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
8626 void *hdr = ((void **)skb->cb)[1];
8627 struct nlattr *data = ((void **)skb->cb)[2];
8628 enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
8629
Johannes Bergbd8c78e2014-07-30 14:55:26 +02008630 /* clear CB data for netlink core to own from now on */
8631 memset(skb->cb, 0, sizeof(skb->cb));
8632
Johannes Berge03ad6e2014-01-01 17:22:30 +01008633 nla_nest_end(skb, data);
8634 genlmsg_end(skb, hdr);
8635
8636 if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
8637 mcgrp = NL80211_MCGRP_VENDOR;
8638
8639 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
8640 mcgrp, gfp);
8641}
8642EXPORT_SYMBOL(__cfg80211_send_event_skb);
8643
Johannes Bergaff89a92009-07-01 21:26:51 +02008644#ifdef CONFIG_NL80211_TESTMODE
Johannes Bergaff89a92009-07-01 21:26:51 +02008645static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
8646{
Johannes Berg4c476992010-10-04 21:36:35 +02008647 struct cfg80211_registered_device *rdev = info->user_ptr[0];
David Spinadelfc73f112013-07-31 18:04:15 +03008648 struct wireless_dev *wdev =
8649 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
Johannes Bergaff89a92009-07-01 21:26:51 +02008650 int err;
8651
David Spinadelfc73f112013-07-31 18:04:15 +03008652 if (!rdev->ops->testmode_cmd)
8653 return -EOPNOTSUPP;
8654
8655 if (IS_ERR(wdev)) {
8656 err = PTR_ERR(wdev);
8657 if (err != -EINVAL)
8658 return err;
8659 wdev = NULL;
8660 } else if (wdev->wiphy != &rdev->wiphy) {
8661 return -EINVAL;
8662 }
8663
Johannes Bergaff89a92009-07-01 21:26:51 +02008664 if (!info->attrs[NL80211_ATTR_TESTDATA])
8665 return -EINVAL;
8666
Johannes Bergad7e7182013-11-13 13:37:47 +01008667 rdev->cur_cmd_info = info;
David Spinadelfc73f112013-07-31 18:04:15 +03008668 err = rdev_testmode_cmd(rdev, wdev,
Johannes Bergaff89a92009-07-01 21:26:51 +02008669 nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
8670 nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
Johannes Bergad7e7182013-11-13 13:37:47 +01008671 rdev->cur_cmd_info = NULL;
Johannes Bergaff89a92009-07-01 21:26:51 +02008672
Johannes Bergaff89a92009-07-01 21:26:51 +02008673 return err;
8674}
8675
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008676static int nl80211_testmode_dump(struct sk_buff *skb,
8677 struct netlink_callback *cb)
8678{
Johannes Berg00918d32011-12-13 17:22:05 +01008679 struct cfg80211_registered_device *rdev;
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008680 int err;
8681 long phy_idx;
8682 void *data = NULL;
8683 int data_len = 0;
8684
Johannes Berg5fe231e2013-05-08 21:45:15 +02008685 rtnl_lock();
8686
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008687 if (cb->args[0]) {
8688 /*
8689 * 0 is a valid index, but not valid for args[0],
8690 * so we need to offset by 1.
8691 */
8692 phy_idx = cb->args[0] - 1;
Luca Coelhoa4956dc2017-02-07 22:13:56 +02008693
8694 rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
8695 if (!rdev) {
8696 err = -ENOENT;
8697 goto out_err;
8698 }
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008699 } else {
Johannes Bergc90c39d2016-10-24 14:40:01 +02008700 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
8701
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008702 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergc90c39d2016-10-24 14:40:01 +02008703 attrbuf, nl80211_fam.maxattr, nl80211_policy);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008704 if (err)
Johannes Berg5fe231e2013-05-08 21:45:15 +02008705 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01008706
Johannes Bergc90c39d2016-10-24 14:40:01 +02008707 rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg2bd7e352012-06-15 14:23:16 +02008708 if (IS_ERR(rdev)) {
Johannes Berg5fe231e2013-05-08 21:45:15 +02008709 err = PTR_ERR(rdev);
8710 goto out_err;
Johannes Berg00918d32011-12-13 17:22:05 +01008711 }
Johannes Berg2bd7e352012-06-15 14:23:16 +02008712 phy_idx = rdev->wiphy_idx;
Johannes Berg2bd7e352012-06-15 14:23:16 +02008713
Johannes Bergc90c39d2016-10-24 14:40:01 +02008714 if (attrbuf[NL80211_ATTR_TESTDATA])
8715 cb->args[1] = (long)attrbuf[NL80211_ATTR_TESTDATA];
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008716 }
8717
8718 if (cb->args[1]) {
8719 data = nla_data((void *)cb->args[1]);
8720 data_len = nla_len((void *)cb->args[1]);
8721 }
8722
Johannes Berg00918d32011-12-13 17:22:05 +01008723 if (!rdev->ops->testmode_dump) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008724 err = -EOPNOTSUPP;
8725 goto out_err;
8726 }
8727
8728 while (1) {
Eric W. Biederman15e47302012-09-07 20:12:54 +00008729 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008730 cb->nlh->nlmsg_seq, NLM_F_MULTI,
8731 NL80211_CMD_TESTMODE);
8732 struct nlattr *tmdata;
8733
Dan Carpentercb35fba2013-08-14 14:50:01 +03008734 if (!hdr)
8735 break;
8736
David S. Miller9360ffd2012-03-29 04:41:26 -04008737 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008738 genlmsg_cancel(skb, hdr);
8739 break;
8740 }
8741
8742 tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
8743 if (!tmdata) {
8744 genlmsg_cancel(skb, hdr);
8745 break;
8746 }
Hila Gonene35e4d22012-06-27 17:19:42 +03008747 err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008748 nla_nest_end(skb, tmdata);
8749
8750 if (err == -ENOBUFS || err == -ENOENT) {
8751 genlmsg_cancel(skb, hdr);
8752 break;
8753 } else if (err) {
8754 genlmsg_cancel(skb, hdr);
8755 goto out_err;
8756 }
8757
8758 genlmsg_end(skb, hdr);
8759 }
8760
8761 err = skb->len;
8762 /* see above */
8763 cb->args[0] = phy_idx + 1;
8764 out_err:
Johannes Berg5fe231e2013-05-08 21:45:15 +02008765 rtnl_unlock();
Wey-Yi Guy71063f02011-05-20 09:05:54 -07008766 return err;
8767}
Johannes Bergaff89a92009-07-01 21:26:51 +02008768#endif
8769
Samuel Ortizb23aa672009-07-01 21:26:54 +02008770static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
8771{
Johannes Berg4c476992010-10-04 21:36:35 +02008772 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8773 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02008774 struct cfg80211_connect_params connect;
8775 struct wiphy *wiphy;
Johannes Bergfffd0932009-07-08 14:22:54 +02008776 struct cfg80211_cached_keys *connkeys = NULL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008777 int err;
8778
8779 memset(&connect, 0, sizeof(connect));
8780
8781 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8782 return -EINVAL;
8783
8784 if (!info->attrs[NL80211_ATTR_SSID] ||
8785 !nla_len(info->attrs[NL80211_ATTR_SSID]))
8786 return -EINVAL;
8787
8788 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
8789 connect.auth_type =
8790 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
Jouni Malinene39e5b52012-09-30 19:29:39 +03008791 if (!nl80211_valid_auth_type(rdev, connect.auth_type,
8792 NL80211_CMD_CONNECT))
Samuel Ortizb23aa672009-07-01 21:26:54 +02008793 return -EINVAL;
8794 } else
8795 connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
8796
8797 connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
8798
Johannes Bergc0692b82010-08-27 14:26:53 +03008799 err = nl80211_crypto_settings(rdev, info, &connect.crypto,
Johannes Berg3dc27d22009-07-02 21:36:37 +02008800 NL80211_MAX_NR_CIPHER_SUITES);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008801 if (err)
8802 return err;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008803
Johannes Berg074ac8d2010-09-16 14:58:22 +02008804 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02008805 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
8806 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008807
Johannes Berg79c97e92009-07-07 03:56:12 +02008808 wiphy = &rdev->wiphy;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008809
Bala Shanmugam4486ea92012-03-07 17:27:12 +05308810 connect.bg_scan_period = -1;
8811 if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] &&
8812 (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) {
8813 connect.bg_scan_period =
8814 nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]);
8815 }
8816
Samuel Ortizb23aa672009-07-01 21:26:54 +02008817 if (info->attrs[NL80211_ATTR_MAC])
8818 connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
Jouni Malinen1df4a512014-01-15 00:00:47 +02008819 else if (info->attrs[NL80211_ATTR_MAC_HINT])
8820 connect.bssid_hint =
8821 nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
Samuel Ortizb23aa672009-07-01 21:26:54 +02008822 connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
8823 connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
8824
8825 if (info->attrs[NL80211_ATTR_IE]) {
8826 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8827 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
8828 }
8829
Jouni Malinencee00a92013-01-15 17:15:57 +02008830 if (info->attrs[NL80211_ATTR_USE_MFP]) {
8831 connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
8832 if (connect.mfp != NL80211_MFP_REQUIRED &&
8833 connect.mfp != NL80211_MFP_NO)
8834 return -EINVAL;
8835 } else {
8836 connect.mfp = NL80211_MFP_NO;
8837 }
8838
Jouni Malinenba6fbac2016-03-29 13:53:27 +03008839 if (info->attrs[NL80211_ATTR_PREV_BSSID])
8840 connect.prev_bssid =
8841 nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
8842
Samuel Ortizb23aa672009-07-01 21:26:54 +02008843 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02008844 connect.channel = nl80211_get_valid_chan(
8845 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
8846 if (!connect.channel)
Johannes Berg4c476992010-10-04 21:36:35 +02008847 return -EINVAL;
Jouni Malinen1df4a512014-01-15 00:00:47 +02008848 } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
Jouni Malinen664834d2014-01-15 00:01:44 +02008849 connect.channel_hint = nl80211_get_valid_chan(
8850 wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
8851 if (!connect.channel_hint)
Jouni Malinen1df4a512014-01-15 00:00:47 +02008852 return -EINVAL;
Samuel Ortizb23aa672009-07-01 21:26:54 +02008853 }
8854
Johannes Bergfffd0932009-07-08 14:22:54 +02008855 if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
8856 connkeys = nl80211_parse_connkeys(rdev,
Sujith Manoharande7044e2012-10-18 10:19:28 +05308857 info->attrs[NL80211_ATTR_KEYS], NULL);
Johannes Berg4c476992010-10-04 21:36:35 +02008858 if (IS_ERR(connkeys))
8859 return PTR_ERR(connkeys);
Johannes Bergfffd0932009-07-08 14:22:54 +02008860 }
8861
Ben Greear7e7c8922011-11-18 11:31:59 -08008862 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
8863 connect.flags |= ASSOC_REQ_DISABLE_HT;
8864
8865 if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
8866 memcpy(&connect.ht_capa_mask,
8867 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
8868 sizeof(connect.ht_capa_mask));
8869
8870 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
Wei Yongjunb4e4f472012-09-02 21:41:04 +08008871 if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03008872 kzfree(connkeys);
Ben Greear7e7c8922011-11-18 11:31:59 -08008873 return -EINVAL;
Wei Yongjunb4e4f472012-09-02 21:41:04 +08008874 }
Ben Greear7e7c8922011-11-18 11:31:59 -08008875 memcpy(&connect.ht_capa,
8876 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
8877 sizeof(connect.ht_capa));
8878 }
8879
Johannes Bergee2aca32013-02-21 17:36:01 +01008880 if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
8881 connect.flags |= ASSOC_REQ_DISABLE_VHT;
8882
8883 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
8884 memcpy(&connect.vht_capa_mask,
8885 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
8886 sizeof(connect.vht_capa_mask));
8887
8888 if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
8889 if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
Johannes Bergb47f6102014-09-10 13:39:54 +03008890 kzfree(connkeys);
Johannes Bergee2aca32013-02-21 17:36:01 +01008891 return -EINVAL;
8892 }
8893 memcpy(&connect.vht_capa,
8894 nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
8895 sizeof(connect.vht_capa));
8896 }
8897
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008898 if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
Beni Lev0c9ca112016-02-17 20:30:00 +02008899 if (!((rdev->wiphy.features &
8900 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
8901 (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
8902 !wiphy_ext_feature_isset(&rdev->wiphy,
8903 NL80211_EXT_FEATURE_RRM)) {
Ola Olsson707554b2015-12-11 21:04:52 +01008904 kzfree(connkeys);
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008905 return -EINVAL;
Ola Olsson707554b2015-12-11 21:04:52 +01008906 }
Assaf Kraussbab5ab72014-09-03 15:25:01 +03008907 connect.flags |= ASSOC_REQ_USE_RRM;
8908 }
8909
Lior David34d50512016-01-28 10:58:25 +02008910 connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
Johannes Berg57fbcce2016-04-12 15:56:15 +02008911 if (connect.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
Lior David34d50512016-01-28 10:58:25 +02008912 kzfree(connkeys);
8913 return -EOPNOTSUPP;
8914 }
8915
Arend van Spriel38de03d2016-03-02 20:37:18 +01008916 if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
8917 /* bss selection makes no sense if bssid is set */
8918 if (connect.bssid) {
8919 kzfree(connkeys);
8920 return -EINVAL;
8921 }
8922
8923 err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
8924 wiphy, &connect.bss_select);
8925 if (err) {
8926 kzfree(connkeys);
8927 return err;
8928 }
8929 }
8930
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03008931 if (wiphy_ext_feature_isset(&rdev->wiphy,
8932 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
8933 info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
8934 info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
8935 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
8936 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
8937 connect.fils_erp_username =
8938 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
8939 connect.fils_erp_username_len =
8940 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
8941 connect.fils_erp_realm =
8942 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
8943 connect.fils_erp_realm_len =
8944 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
8945 connect.fils_erp_next_seq_num =
8946 nla_get_u16(
8947 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
8948 connect.fils_erp_rrk =
8949 nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
8950 connect.fils_erp_rrk_len =
8951 nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
8952 } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
8953 info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
8954 info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
8955 info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
8956 kzfree(connkeys);
8957 return -EINVAL;
8958 }
8959
Johannes Berg83739b02013-05-15 17:44:01 +02008960 wdev_lock(dev->ieee80211_ptr);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008961
Jouni Malinen4ce2bd92016-03-29 13:53:28 +03008962 err = cfg80211_connect(rdev, dev, &connect, connkeys,
8963 connect.prev_bssid);
Johannes Bergfffd0932009-07-08 14:22:54 +02008964 if (err)
Johannes Bergb47f6102014-09-10 13:39:54 +03008965 kzfree(connkeys);
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -05008966
8967 if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
8968 dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
8969 if (connect.bssid)
8970 memcpy(dev->ieee80211_ptr->disconnect_bssid,
8971 connect.bssid, ETH_ALEN);
8972 else
8973 memset(dev->ieee80211_ptr->disconnect_bssid,
8974 0, ETH_ALEN);
8975 }
8976
8977 wdev_unlock(dev->ieee80211_ptr);
8978
Samuel Ortizb23aa672009-07-01 21:26:54 +02008979 return err;
8980}
8981
vamsi krishna088e8df2016-10-27 16:51:11 +03008982static int nl80211_update_connect_params(struct sk_buff *skb,
8983 struct genl_info *info)
8984{
8985 struct cfg80211_connect_params connect = {};
8986 struct cfg80211_registered_device *rdev = info->user_ptr[0];
8987 struct net_device *dev = info->user_ptr[1];
8988 struct wireless_dev *wdev = dev->ieee80211_ptr;
8989 u32 changed = 0;
8990 int ret;
8991
8992 if (!rdev->ops->update_connect_params)
8993 return -EOPNOTSUPP;
8994
8995 if (info->attrs[NL80211_ATTR_IE]) {
8996 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
8997 return -EINVAL;
8998 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
8999 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
9000 changed |= UPDATE_ASSOC_IES;
9001 }
9002
9003 wdev_lock(dev->ieee80211_ptr);
9004 if (!wdev->current_bss)
9005 ret = -ENOLINK;
9006 else
9007 ret = rdev_update_connect_params(rdev, dev, &connect, changed);
9008 wdev_unlock(dev->ieee80211_ptr);
9009
9010 return ret;
9011}
9012
Samuel Ortizb23aa672009-07-01 21:26:54 +02009013static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
9014{
Johannes Berg4c476992010-10-04 21:36:35 +02009015 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9016 struct net_device *dev = info->user_ptr[1];
Samuel Ortizb23aa672009-07-01 21:26:54 +02009017 u16 reason;
Johannes Berg83739b02013-05-15 17:44:01 +02009018 int ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009019
9020 if (!info->attrs[NL80211_ATTR_REASON_CODE])
9021 reason = WLAN_REASON_DEAUTH_LEAVING;
9022 else
9023 reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
9024
9025 if (reason == 0)
9026 return -EINVAL;
9027
Johannes Berg074ac8d2010-09-16 14:58:22 +02009028 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009029 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9030 return -EOPNOTSUPP;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009031
Johannes Berg83739b02013-05-15 17:44:01 +02009032 wdev_lock(dev->ieee80211_ptr);
9033 ret = cfg80211_disconnect(rdev, dev, reason, true);
9034 wdev_unlock(dev->ieee80211_ptr);
9035 return ret;
Samuel Ortizb23aa672009-07-01 21:26:54 +02009036}
9037
Johannes Berg463d0182009-07-14 00:33:35 +02009038static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
9039{
Johannes Berg4c476992010-10-04 21:36:35 +02009040 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg463d0182009-07-14 00:33:35 +02009041 struct net *net;
9042 int err;
Johannes Berg463d0182009-07-14 00:33:35 +02009043
Vadim Kochan4b681c82015-01-12 16:34:05 +02009044 if (info->attrs[NL80211_ATTR_PID]) {
9045 u32 pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
9046
9047 net = get_net_ns_by_pid(pid);
9048 } else if (info->attrs[NL80211_ATTR_NETNS_FD]) {
9049 u32 fd = nla_get_u32(info->attrs[NL80211_ATTR_NETNS_FD]);
9050
9051 net = get_net_ns_by_fd(fd);
9052 } else {
Johannes Berg463d0182009-07-14 00:33:35 +02009053 return -EINVAL;
Vadim Kochan4b681c82015-01-12 16:34:05 +02009054 }
Johannes Berg463d0182009-07-14 00:33:35 +02009055
Johannes Berg4c476992010-10-04 21:36:35 +02009056 if (IS_ERR(net))
9057 return PTR_ERR(net);
Johannes Berg463d0182009-07-14 00:33:35 +02009058
9059 err = 0;
9060
9061 /* check if anything to do */
Johannes Berg4c476992010-10-04 21:36:35 +02009062 if (!net_eq(wiphy_net(&rdev->wiphy), net))
9063 err = cfg80211_switch_netns(rdev, net);
Johannes Berg463d0182009-07-14 00:33:35 +02009064
Johannes Berg463d0182009-07-14 00:33:35 +02009065 put_net(net);
Johannes Berg463d0182009-07-14 00:33:35 +02009066 return err;
9067}
9068
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009069static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
9070{
Johannes Berg4c476992010-10-04 21:36:35 +02009071 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009072 int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
9073 struct cfg80211_pmksa *pmksa) = NULL;
Johannes Berg4c476992010-10-04 21:36:35 +02009074 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009075 struct cfg80211_pmksa pmksa;
9076
9077 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
9078
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009079 if (!info->attrs[NL80211_ATTR_PMKID])
9080 return -EINVAL;
9081
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009082 pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +03009083
9084 if (info->attrs[NL80211_ATTR_MAC]) {
9085 pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
9086 } else if (info->attrs[NL80211_ATTR_SSID] &&
9087 info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
9088 (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
9089 info->attrs[NL80211_ATTR_PMK])) {
9090 pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
9091 pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
9092 pmksa.cache_id =
9093 nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
9094 } else {
9095 return -EINVAL;
9096 }
9097 if (info->attrs[NL80211_ATTR_PMK]) {
9098 pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
9099 pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
9100 }
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009101
Johannes Berg074ac8d2010-09-16 14:58:22 +02009102 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009103 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9104 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009105
9106 switch (info->genlhdr->cmd) {
9107 case NL80211_CMD_SET_PMKSA:
9108 rdev_ops = rdev->ops->set_pmksa;
9109 break;
9110 case NL80211_CMD_DEL_PMKSA:
9111 rdev_ops = rdev->ops->del_pmksa;
9112 break;
9113 default:
9114 WARN_ON(1);
9115 break;
9116 }
9117
Johannes Berg4c476992010-10-04 21:36:35 +02009118 if (!rdev_ops)
9119 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009120
Johannes Berg4c476992010-10-04 21:36:35 +02009121 return rdev_ops(&rdev->wiphy, dev, &pmksa);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009122}
9123
9124static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
9125{
Johannes Berg4c476992010-10-04 21:36:35 +02009126 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9127 struct net_device *dev = info->user_ptr[1];
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009128
Johannes Berg074ac8d2010-09-16 14:58:22 +02009129 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009130 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
9131 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009132
Johannes Berg4c476992010-10-04 21:36:35 +02009133 if (!rdev->ops->flush_pmksa)
9134 return -EOPNOTSUPP;
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009135
Hila Gonene35e4d22012-06-27 17:19:42 +03009136 return rdev_flush_pmksa(rdev, dev);
Samuel Ortiz67fbb162009-11-24 23:59:15 +01009137}
9138
Arik Nemtsov109086c2011-09-28 14:12:50 +03009139static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
9140{
9141 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9142 struct net_device *dev = info->user_ptr[1];
9143 u8 action_code, dialog_token;
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309144 u32 peer_capability = 0;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009145 u16 status_code;
9146 u8 *peer;
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009147 bool initiator;
Arik Nemtsov109086c2011-09-28 14:12:50 +03009148
9149 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9150 !rdev->ops->tdls_mgmt)
9151 return -EOPNOTSUPP;
9152
9153 if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
9154 !info->attrs[NL80211_ATTR_STATUS_CODE] ||
9155 !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
9156 !info->attrs[NL80211_ATTR_IE] ||
9157 !info->attrs[NL80211_ATTR_MAC])
9158 return -EINVAL;
9159
9160 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9161 action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
9162 status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
9163 dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009164 initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]);
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309165 if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
9166 peer_capability =
9167 nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009168
Hila Gonene35e4d22012-06-27 17:19:42 +03009169 return rdev_tdls_mgmt(rdev, dev, peer, action_code,
Sunil Dutt Undekaridf942e72014-02-20 16:22:09 +05309170 dialog_token, status_code, peer_capability,
Arik Nemtsov31fa97c2014-06-11 17:18:21 +03009171 initiator,
Hila Gonene35e4d22012-06-27 17:19:42 +03009172 nla_data(info->attrs[NL80211_ATTR_IE]),
9173 nla_len(info->attrs[NL80211_ATTR_IE]));
Arik Nemtsov109086c2011-09-28 14:12:50 +03009174}
9175
9176static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
9177{
9178 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9179 struct net_device *dev = info->user_ptr[1];
9180 enum nl80211_tdls_operation operation;
9181 u8 *peer;
9182
9183 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
9184 !rdev->ops->tdls_oper)
9185 return -EOPNOTSUPP;
9186
9187 if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
9188 !info->attrs[NL80211_ATTR_MAC])
9189 return -EINVAL;
9190
9191 operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
9192 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
9193
Hila Gonene35e4d22012-06-27 17:19:42 +03009194 return rdev_tdls_oper(rdev, dev, peer, operation);
Arik Nemtsov109086c2011-09-28 14:12:50 +03009195}
9196
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009197static int nl80211_remain_on_channel(struct sk_buff *skb,
9198 struct genl_info *info)
9199{
Johannes Berg4c476992010-10-04 21:36:35 +02009200 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009201 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009202 struct cfg80211_chan_def chandef;
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05309203 const struct cfg80211_chan_def *compat_chandef;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009204 struct sk_buff *msg;
9205 void *hdr;
9206 u64 cookie;
Johannes Berg683b6d32012-11-08 21:25:48 +01009207 u32 duration;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009208 int err;
9209
9210 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
9211 !info->attrs[NL80211_ATTR_DURATION])
9212 return -EINVAL;
9213
9214 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
9215
Johannes Berg7c4ef712011-11-18 15:33:48 +01009216 if (!rdev->ops->remain_on_channel ||
9217 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
Johannes Berg4c476992010-10-04 21:36:35 +02009218 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009219
Johannes Bergebf348f2012-06-01 12:50:54 +02009220 /*
9221 * We should be on that channel for at least a minimum amount of
9222 * time (10ms) but no longer than the driver supports.
9223 */
9224 if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9225 duration > rdev->wiphy.max_remain_on_channel_duration)
9226 return -EINVAL;
9227
Johannes Berg683b6d32012-11-08 21:25:48 +01009228 err = nl80211_parse_chandef(rdev, info, &chandef);
9229 if (err)
9230 return err;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009231
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05309232 wdev_lock(wdev);
9233 if (!cfg80211_off_channel_oper_allowed(wdev) &&
9234 !cfg80211_chandef_identical(&wdev->chandef, &chandef)) {
9235 compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
9236 &chandef);
9237 if (compat_chandef != &chandef) {
9238 wdev_unlock(wdev);
9239 return -EBUSY;
9240 }
9241 }
9242 wdev_unlock(wdev);
9243
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009244 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009245 if (!msg)
9246 return -ENOMEM;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009247
Eric W. Biederman15e47302012-09-07 20:12:54 +00009248 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009249 NL80211_CMD_REMAIN_ON_CHANNEL);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009250 if (!hdr) {
9251 err = -ENOBUFS;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009252 goto free_msg;
9253 }
9254
Johannes Berg683b6d32012-11-08 21:25:48 +01009255 err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
9256 duration, &cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009257
9258 if (err)
9259 goto free_msg;
9260
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009261 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9262 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009263 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009264
9265 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009266
9267 return genlmsg_reply(msg, info);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009268
9269 nla_put_failure:
9270 err = -ENOBUFS;
9271 free_msg:
9272 nlmsg_free(msg);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009273 return err;
9274}
9275
9276static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
9277 struct genl_info *info)
9278{
Johannes Berg4c476992010-10-04 21:36:35 +02009279 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009280 struct wireless_dev *wdev = info->user_ptr[1];
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009281 u64 cookie;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009282
9283 if (!info->attrs[NL80211_ATTR_COOKIE])
9284 return -EINVAL;
9285
Johannes Berg4c476992010-10-04 21:36:35 +02009286 if (!rdev->ops->cancel_remain_on_channel)
9287 return -EOPNOTSUPP;
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009288
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009289 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9290
Hila Gonene35e4d22012-06-27 17:19:42 +03009291 return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
Jouni Malinen9588bbd2009-12-23 13:15:41 +01009292}
9293
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009294static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
9295 struct genl_info *info)
9296{
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009297 struct cfg80211_bitrate_mask mask;
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309298 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009299 struct net_device *dev = info->user_ptr[1];
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309300 int err;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009301
Johannes Berg4c476992010-10-04 21:36:35 +02009302 if (!rdev->ops->set_bitrate_mask)
9303 return -EOPNOTSUPP;
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009304
Purushottam Kushwahaa7c7fbf2016-09-14 17:38:44 +05309305 err = nl80211_parse_tx_bitrate_mask(info, &mask);
9306 if (err)
9307 return err;
Janusz Dziedzic78693032013-12-03 09:50:44 +01009308
Hila Gonene35e4d22012-06-27 17:19:42 +03009309 return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
Jouni Malinen13ae75b2009-12-29 12:59:45 +02009310}
9311
Johannes Berg2e161f72010-08-12 15:38:38 +02009312static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009313{
Johannes Berg4c476992010-10-04 21:36:35 +02009314 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009315 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg2e161f72010-08-12 15:38:38 +02009316 u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
Jouni Malinen026331c2010-02-15 12:53:10 +02009317
9318 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
9319 return -EINVAL;
9320
Johannes Berg2e161f72010-08-12 15:38:38 +02009321 if (info->attrs[NL80211_ATTR_FRAME_TYPE])
9322 frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
Jouni Malinen026331c2010-02-15 12:53:10 +02009323
Johannes Berg71bbc992012-06-15 15:30:18 +02009324 switch (wdev->iftype) {
9325 case NL80211_IFTYPE_STATION:
9326 case NL80211_IFTYPE_ADHOC:
9327 case NL80211_IFTYPE_P2P_CLIENT:
9328 case NL80211_IFTYPE_AP:
9329 case NL80211_IFTYPE_AP_VLAN:
9330 case NL80211_IFTYPE_MESH_POINT:
9331 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009332 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009333 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009334 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009335 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009336 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009337 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009338
9339 /* not much point in registering if we can't reply */
Johannes Berg4c476992010-10-04 21:36:35 +02009340 if (!rdev->ops->mgmt_tx)
9341 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009342
Eric W. Biederman15e47302012-09-07 20:12:54 +00009343 return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
Jouni Malinen026331c2010-02-15 12:53:10 +02009344 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
9345 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
Jouni Malinen026331c2010-02-15 12:53:10 +02009346}
9347
Johannes Berg2e161f72010-08-12 15:38:38 +02009348static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
Jouni Malinen026331c2010-02-15 12:53:10 +02009349{
Johannes Berg4c476992010-10-04 21:36:35 +02009350 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009351 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Berg683b6d32012-11-08 21:25:48 +01009352 struct cfg80211_chan_def chandef;
Jouni Malinen026331c2010-02-15 12:53:10 +02009353 int err;
Johannes Bergd64d3732011-11-10 09:44:46 +01009354 void *hdr = NULL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009355 u64 cookie;
Johannes Berge247bd902011-11-04 11:18:21 +01009356 struct sk_buff *msg = NULL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009357 struct cfg80211_mgmt_tx_params params = {
9358 .dont_wait_for_ack =
9359 info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
9360 };
Jouni Malinen026331c2010-02-15 12:53:10 +02009361
Johannes Berg683b6d32012-11-08 21:25:48 +01009362 if (!info->attrs[NL80211_ATTR_FRAME])
Jouni Malinen026331c2010-02-15 12:53:10 +02009363 return -EINVAL;
9364
Johannes Berg4c476992010-10-04 21:36:35 +02009365 if (!rdev->ops->mgmt_tx)
9366 return -EOPNOTSUPP;
Jouni Malinen026331c2010-02-15 12:53:10 +02009367
Johannes Berg71bbc992012-06-15 15:30:18 +02009368 switch (wdev->iftype) {
Antonio Quartulliea141b752013-06-11 14:20:03 +02009369 case NL80211_IFTYPE_P2P_DEVICE:
9370 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
9371 return -EINVAL;
Johannes Berg71bbc992012-06-15 15:30:18 +02009372 case NL80211_IFTYPE_STATION:
9373 case NL80211_IFTYPE_ADHOC:
9374 case NL80211_IFTYPE_P2P_CLIENT:
9375 case NL80211_IFTYPE_AP:
9376 case NL80211_IFTYPE_AP_VLAN:
9377 case NL80211_IFTYPE_MESH_POINT:
9378 case NL80211_IFTYPE_P2P_GO:
9379 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009380 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009381 default:
Johannes Berg4c476992010-10-04 21:36:35 +02009382 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009383 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009384
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009385 if (info->attrs[NL80211_ATTR_DURATION]) {
Johannes Berg7c4ef712011-11-18 15:33:48 +01009386 if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009387 return -EINVAL;
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009388 params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
Johannes Bergebf348f2012-06-01 12:50:54 +02009389
9390 /*
9391 * We should wait on the channel for at least a minimum amount
9392 * of time (10ms) but no longer than the driver supports.
9393 */
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009394 if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
9395 params.wait > rdev->wiphy.max_remain_on_channel_duration)
Johannes Bergebf348f2012-06-01 12:50:54 +02009396 return -EINVAL;
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009397 }
9398
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009399 params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009400
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009401 if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
Johannes Berg7c4ef712011-11-18 15:33:48 +01009402 return -EINVAL;
9403
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009404 params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
Rajkumar Manoharane9f935e2011-09-25 14:53:30 +05309405
Antonio Quartulliea141b752013-06-11 14:20:03 +02009406 /* get the channel if any has been specified, otherwise pass NULL to
9407 * the driver. The latter will use the current one
9408 */
9409 chandef.chan = NULL;
9410 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
9411 err = nl80211_parse_chandef(rdev, info, &chandef);
9412 if (err)
9413 return err;
9414 }
9415
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009416 if (!chandef.chan && params.offchan)
Antonio Quartulliea141b752013-06-11 14:20:03 +02009417 return -EINVAL;
Jouni Malinen026331c2010-02-15 12:53:10 +02009418
Vasanthakumar Thiagarajan34373d12017-02-27 17:04:34 +05309419 wdev_lock(wdev);
9420 if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) {
9421 wdev_unlock(wdev);
9422 return -EBUSY;
9423 }
9424 wdev_unlock(wdev);
9425
Andrei Otcheretianski34d22ce2014-05-09 14:11:44 +03009426 params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
9427 params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
9428
9429 if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
9430 int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9431 int i;
9432
9433 if (len % sizeof(u16))
9434 return -EINVAL;
9435
9436 params.n_csa_offsets = len / sizeof(u16);
9437 params.csa_offsets =
9438 nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
9439
9440 /* check that all the offsets fit the frame */
9441 for (i = 0; i < params.n_csa_offsets; i++) {
9442 if (params.csa_offsets[i] >= params.len)
9443 return -EINVAL;
9444 }
9445 }
9446
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009447 if (!params.dont_wait_for_ack) {
Johannes Berge247bd902011-11-04 11:18:21 +01009448 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9449 if (!msg)
9450 return -ENOMEM;
Jouni Malinen026331c2010-02-15 12:53:10 +02009451
Eric W. Biederman15e47302012-09-07 20:12:54 +00009452 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berge247bd902011-11-04 11:18:21 +01009453 NL80211_CMD_FRAME);
Dan Carpentercb35fba2013-08-14 14:50:01 +03009454 if (!hdr) {
9455 err = -ENOBUFS;
Johannes Berge247bd902011-11-04 11:18:21 +01009456 goto free_msg;
9457 }
Jouni Malinen026331c2010-02-15 12:53:10 +02009458 }
Johannes Berge247bd902011-11-04 11:18:21 +01009459
Andrei Otcheretianskib176e622013-11-18 19:06:49 +02009460 params.chan = chandef.chan;
9461 err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
Jouni Malinen026331c2010-02-15 12:53:10 +02009462 if (err)
9463 goto free_msg;
9464
Johannes Berge247bd902011-11-04 11:18:21 +01009465 if (msg) {
Nicolas Dichtel2dad6242016-04-25 10:25:22 +02009466 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
9467 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -04009468 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +02009469
Johannes Berge247bd902011-11-04 11:18:21 +01009470 genlmsg_end(msg, hdr);
9471 return genlmsg_reply(msg, info);
9472 }
9473
9474 return 0;
Jouni Malinen026331c2010-02-15 12:53:10 +02009475
9476 nla_put_failure:
9477 err = -ENOBUFS;
9478 free_msg:
9479 nlmsg_free(msg);
Jouni Malinen026331c2010-02-15 12:53:10 +02009480 return err;
9481}
9482
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009483static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
9484{
9485 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg71bbc992012-06-15 15:30:18 +02009486 struct wireless_dev *wdev = info->user_ptr[1];
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009487 u64 cookie;
9488
9489 if (!info->attrs[NL80211_ATTR_COOKIE])
9490 return -EINVAL;
9491
9492 if (!rdev->ops->mgmt_tx_cancel_wait)
9493 return -EOPNOTSUPP;
9494
Johannes Berg71bbc992012-06-15 15:30:18 +02009495 switch (wdev->iftype) {
9496 case NL80211_IFTYPE_STATION:
9497 case NL80211_IFTYPE_ADHOC:
9498 case NL80211_IFTYPE_P2P_CLIENT:
9499 case NL80211_IFTYPE_AP:
9500 case NL80211_IFTYPE_AP_VLAN:
9501 case NL80211_IFTYPE_P2P_GO:
Johannes Berg98104fde2012-06-16 00:19:54 +02009502 case NL80211_IFTYPE_P2P_DEVICE:
Johannes Berg71bbc992012-06-15 15:30:18 +02009503 break;
Ayala Bekercb3b7d82016-09-20 17:31:13 +03009504 case NL80211_IFTYPE_NAN:
Johannes Berg71bbc992012-06-15 15:30:18 +02009505 default:
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009506 return -EOPNOTSUPP;
Johannes Berg71bbc992012-06-15 15:30:18 +02009507 }
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009508
9509 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
9510
Hila Gonene35e4d22012-06-27 17:19:42 +03009511 return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
Johannes Bergf7ca38d2010-11-25 10:02:29 +01009512}
9513
Kalle Valoffb9eb32010-02-17 17:58:10 +02009514static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
9515{
Johannes Berg4c476992010-10-04 21:36:35 +02009516 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009517 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009518 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009519 u8 ps_state;
9520 bool state;
9521 int err;
9522
Johannes Berg4c476992010-10-04 21:36:35 +02009523 if (!info->attrs[NL80211_ATTR_PS_STATE])
9524 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009525
9526 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
9527
Johannes Berg4c476992010-10-04 21:36:35 +02009528 if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
9529 return -EINVAL;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009530
9531 wdev = dev->ieee80211_ptr;
9532
Johannes Berg4c476992010-10-04 21:36:35 +02009533 if (!rdev->ops->set_power_mgmt)
9534 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009535
9536 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
9537
9538 if (state == wdev->ps)
Johannes Berg4c476992010-10-04 21:36:35 +02009539 return 0;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009540
Hila Gonene35e4d22012-06-27 17:19:42 +03009541 err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
Johannes Berg4c476992010-10-04 21:36:35 +02009542 if (!err)
9543 wdev->ps = state;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009544 return err;
9545}
9546
9547static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
9548{
Johannes Berg4c476992010-10-04 21:36:35 +02009549 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009550 enum nl80211_ps_state ps_state;
9551 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +02009552 struct net_device *dev = info->user_ptr[1];
Kalle Valoffb9eb32010-02-17 17:58:10 +02009553 struct sk_buff *msg;
9554 void *hdr;
9555 int err;
9556
Kalle Valoffb9eb32010-02-17 17:58:10 +02009557 wdev = dev->ieee80211_ptr;
9558
Johannes Berg4c476992010-10-04 21:36:35 +02009559 if (!rdev->ops->set_power_mgmt)
9560 return -EOPNOTSUPP;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009561
9562 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg4c476992010-10-04 21:36:35 +02009563 if (!msg)
9564 return -ENOMEM;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009565
Eric W. Biederman15e47302012-09-07 20:12:54 +00009566 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Kalle Valoffb9eb32010-02-17 17:58:10 +02009567 NL80211_CMD_GET_POWER_SAVE);
9568 if (!hdr) {
Johannes Berg4c476992010-10-04 21:36:35 +02009569 err = -ENOBUFS;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009570 goto free_msg;
9571 }
9572
9573 if (wdev->ps)
9574 ps_state = NL80211_PS_ENABLED;
9575 else
9576 ps_state = NL80211_PS_DISABLED;
9577
David S. Miller9360ffd2012-03-29 04:41:26 -04009578 if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
9579 goto nla_put_failure;
Kalle Valoffb9eb32010-02-17 17:58:10 +02009580
9581 genlmsg_end(msg, hdr);
Johannes Berg4c476992010-10-04 21:36:35 +02009582 return genlmsg_reply(msg, info);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009583
Johannes Berg4c476992010-10-04 21:36:35 +02009584 nla_put_failure:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009585 err = -ENOBUFS;
Johannes Berg4c476992010-10-04 21:36:35 +02009586 free_msg:
Kalle Valoffb9eb32010-02-17 17:58:10 +02009587 nlmsg_free(msg);
Kalle Valoffb9eb32010-02-17 17:58:10 +02009588 return err;
9589}
9590
Johannes Berg94e860f2014-01-20 23:58:15 +01009591static const struct nla_policy
9592nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009593 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009594 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
9595 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
Thomas Pedersen84f10702012-07-12 16:17:33 -07009596 [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
9597 [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
9598 [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +01009599 [NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009600};
9601
Thomas Pedersen84f10702012-07-12 16:17:33 -07009602static int nl80211_set_cqm_txe(struct genl_info *info,
Johannes Bergd9d8b012012-11-26 12:51:52 +01009603 u32 rate, u32 pkts, u32 intvl)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009604{
9605 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Thomas Pedersen84f10702012-07-12 16:17:33 -07009606 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009607 struct wireless_dev *wdev = dev->ieee80211_ptr;
Thomas Pedersen84f10702012-07-12 16:17:33 -07009608
Johannes Bergd9d8b012012-11-26 12:51:52 +01009609 if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
Thomas Pedersen84f10702012-07-12 16:17:33 -07009610 return -EINVAL;
9611
Thomas Pedersen84f10702012-07-12 16:17:33 -07009612 if (!rdev->ops->set_cqm_txe_config)
9613 return -EOPNOTSUPP;
9614
9615 if (wdev->iftype != NL80211_IFTYPE_STATION &&
9616 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9617 return -EOPNOTSUPP;
9618
Hila Gonene35e4d22012-06-27 17:19:42 +03009619 return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
Thomas Pedersen84f10702012-07-12 16:17:33 -07009620}
9621
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009622static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
9623 struct net_device *dev)
9624{
9625 struct wireless_dev *wdev = dev->ieee80211_ptr;
9626 s32 last, low, high;
9627 u32 hyst;
9628 int i, n;
9629 int err;
9630
9631 /* RSSI reporting disabled? */
9632 if (!wdev->cqm_config)
9633 return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
9634
9635 /*
9636 * Obtain current RSSI value if possible, if not and no RSSI threshold
9637 * event has been received yet, we should receive an event after a
9638 * connection is established and enough beacons received to calculate
9639 * the average.
9640 */
9641 if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
9642 rdev->ops->get_station) {
9643 struct station_info sinfo;
9644 u8 *mac_addr;
9645
9646 mac_addr = wdev->current_bss->pub.bssid;
9647
9648 err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
9649 if (err)
9650 return err;
9651
9652 if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
9653 wdev->cqm_config->last_rssi_event_value =
9654 (s8) sinfo.rx_beacon_signal_avg;
9655 }
9656
9657 last = wdev->cqm_config->last_rssi_event_value;
9658 hyst = wdev->cqm_config->rssi_hyst;
9659 n = wdev->cqm_config->n_rssi_thresholds;
9660
9661 for (i = 0; i < n; i++)
9662 if (last < wdev->cqm_config->rssi_thresholds[i])
9663 break;
9664
9665 low = i > 0 ?
9666 (wdev->cqm_config->rssi_thresholds[i - 1] - hyst) : S32_MIN;
9667 high = i < n ?
9668 (wdev->cqm_config->rssi_thresholds[i] + hyst - 1) : S32_MAX;
9669
9670 return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
9671}
9672
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009673static int nl80211_set_cqm_rssi(struct genl_info *info,
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009674 const s32 *thresholds, int n_thresholds,
9675 u32 hysteresis)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009676{
Johannes Berg4c476992010-10-04 21:36:35 +02009677 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Johannes Berg4c476992010-10-04 21:36:35 +02009678 struct net_device *dev = info->user_ptr[1];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009679 struct wireless_dev *wdev = dev->ieee80211_ptr;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009680 int i, err;
9681 s32 prev = S32_MIN;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009682
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009683 /* Check all values negative and sorted */
9684 for (i = 0; i < n_thresholds; i++) {
9685 if (thresholds[i] > 0 || thresholds[i] <= prev)
9686 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009687
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009688 prev = thresholds[i];
9689 }
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009690
Johannes Berg074ac8d2010-09-16 14:58:22 +02009691 if (wdev->iftype != NL80211_IFTYPE_STATION &&
Johannes Berg4c476992010-10-04 21:36:35 +02009692 wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
9693 return -EOPNOTSUPP;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009694
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009695 wdev_lock(wdev);
9696 cfg80211_cqm_config_free(wdev);
9697 wdev_unlock(wdev);
9698
9699 if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
9700 if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
9701 return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
9702
9703 return rdev_set_cqm_rssi_config(rdev, dev,
9704 thresholds[0], hysteresis);
9705 }
9706
9707 if (!wiphy_ext_feature_isset(&rdev->wiphy,
9708 NL80211_EXT_FEATURE_CQM_RSSI_LIST))
9709 return -EOPNOTSUPP;
9710
9711 if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */
9712 n_thresholds = 0;
9713
9714 wdev_lock(wdev);
9715 if (n_thresholds) {
9716 struct cfg80211_cqm_config *cqm_config;
9717
9718 cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
9719 n_thresholds * sizeof(s32), GFP_KERNEL);
9720 if (!cqm_config) {
9721 err = -ENOMEM;
9722 goto unlock;
9723 }
9724
9725 cqm_config->rssi_hyst = hysteresis;
9726 cqm_config->n_rssi_thresholds = n_thresholds;
9727 memcpy(cqm_config->rssi_thresholds, thresholds,
9728 n_thresholds * sizeof(s32));
9729
9730 wdev->cqm_config = cqm_config;
9731 }
9732
9733 err = cfg80211_cqm_rssi_update(rdev, dev);
9734
9735unlock:
9736 wdev_unlock(wdev);
9737
9738 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009739}
9740
9741static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
9742{
9743 struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
9744 struct nlattr *cqm;
9745 int err;
9746
9747 cqm = info->attrs[NL80211_ATTR_CQM];
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009748 if (!cqm)
9749 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009750
9751 err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
9752 nl80211_attr_cqm_policy);
9753 if (err)
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009754 return err;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009755
9756 if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
9757 attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009758 const s32 *thresholds =
9759 nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
9760 int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009761 u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009762
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +01009763 if (len % 4)
9764 return -EINVAL;
9765
9766 return nl80211_set_cqm_rssi(info, thresholds, len / 4,
9767 hysteresis);
Johannes Berg1da5fcc2013-08-06 14:10:48 +02009768 }
9769
9770 if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
9771 attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
9772 attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
9773 u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
9774 u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
9775 u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
9776
9777 return nl80211_set_cqm_txe(info, rate, pkts, intvl);
9778 }
9779
9780 return -EINVAL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +02009781}
9782
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01009783static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
9784{
9785 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9786 struct net_device *dev = info->user_ptr[1];
9787 struct ocb_setup setup = {};
9788 int err;
9789
9790 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
9791 if (err)
9792 return err;
9793
9794 return cfg80211_join_ocb(rdev, dev, &setup);
9795}
9796
9797static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
9798{
9799 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9800 struct net_device *dev = info->user_ptr[1];
9801
9802 return cfg80211_leave_ocb(rdev, dev);
9803}
9804
Johannes Berg29cbe682010-12-03 09:20:44 +01009805static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
9806{
9807 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9808 struct net_device *dev = info->user_ptr[1];
9809 struct mesh_config cfg;
Javier Cardonac80d5452010-12-16 17:37:49 -08009810 struct mesh_setup setup;
Johannes Berg29cbe682010-12-03 09:20:44 +01009811 int err;
9812
9813 /* start with default */
9814 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
Javier Cardonac80d5452010-12-16 17:37:49 -08009815 memcpy(&setup, &default_mesh_setup, sizeof(setup));
Johannes Berg29cbe682010-12-03 09:20:44 +01009816
Javier Cardona24bdd9f2010-12-16 17:37:48 -08009817 if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
Johannes Berg29cbe682010-12-03 09:20:44 +01009818 /* and parse parameters if given */
Javier Cardona24bdd9f2010-12-16 17:37:48 -08009819 err = nl80211_parse_mesh_config(info, &cfg, NULL);
Johannes Berg29cbe682010-12-03 09:20:44 +01009820 if (err)
9821 return err;
9822 }
9823
9824 if (!info->attrs[NL80211_ATTR_MESH_ID] ||
9825 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
9826 return -EINVAL;
9827
Javier Cardonac80d5452010-12-16 17:37:49 -08009828 setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
9829 setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
9830
Chun-Yeow Yeoh4bb62342011-11-24 17:15:20 -08009831 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
9832 !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
9833 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
9834 return -EINVAL;
9835
Marco Porsch9bdbf042013-01-07 16:04:51 +01009836 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
9837 setup.beacon_interval =
9838 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309839
Purushottam Kushwaha0c317a02016-10-12 18:26:51 +05309840 err = cfg80211_validate_beacon_int(rdev,
9841 NL80211_IFTYPE_MESH_POINT,
9842 setup.beacon_interval);
Purushottam Kushwaha12d20fc92016-08-11 15:14:02 +05309843 if (err)
9844 return err;
Marco Porsch9bdbf042013-01-07 16:04:51 +01009845 }
9846
9847 if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
9848 setup.dtim_period =
9849 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
9850 if (setup.dtim_period < 1 || setup.dtim_period > 100)
9851 return -EINVAL;
9852 }
9853
Javier Cardonac80d5452010-12-16 17:37:49 -08009854 if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
9855 /* parse additional setup parameters if given */
9856 err = nl80211_parse_mesh_setup(info, &setup);
9857 if (err)
9858 return err;
9859 }
9860
Thomas Pedersend37bb182013-03-04 13:06:13 -08009861 if (setup.user_mpm)
9862 cfg.auto_open_plinks = false;
9863
Johannes Bergcc1d2802012-05-16 23:50:20 +02009864 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
Johannes Berg683b6d32012-11-08 21:25:48 +01009865 err = nl80211_parse_chandef(rdev, info, &setup.chandef);
9866 if (err)
9867 return err;
Johannes Bergcc1d2802012-05-16 23:50:20 +02009868 } else {
9869 /* cfg80211_join_mesh() will sort it out */
Johannes Berg683b6d32012-11-08 21:25:48 +01009870 setup.chandef.chan = NULL;
Johannes Bergcc1d2802012-05-16 23:50:20 +02009871 }
9872
Ashok Nagarajanffb3cf32013-06-03 10:33:36 -07009873 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
9874 u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9875 int n_rates =
9876 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
9877 struct ieee80211_supported_band *sband;
9878
9879 if (!setup.chandef.chan)
9880 return -EINVAL;
9881
9882 sband = rdev->wiphy.bands[setup.chandef.chan->band];
9883
9884 err = ieee80211_get_ratemask(sband, rates, n_rates,
9885 &setup.basic_rates);
9886 if (err)
9887 return err;
9888 }
9889
Johannes Berg8564e382016-09-19 09:44:44 +02009890 if (info->attrs[NL80211_ATTR_TX_RATES]) {
9891 err = nl80211_parse_tx_bitrate_mask(info, &setup.beacon_rate);
9892 if (err)
9893 return err;
9894
9895 err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band,
9896 &setup.beacon_rate);
9897 if (err)
9898 return err;
9899 }
9900
Javier Cardonac80d5452010-12-16 17:37:49 -08009901 return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
Johannes Berg29cbe682010-12-03 09:20:44 +01009902}
9903
9904static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
9905{
9906 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9907 struct net_device *dev = info->user_ptr[1];
9908
9909 return cfg80211_leave_mesh(rdev, dev);
9910}
9911
Johannes Bergdfb89c52012-06-27 09:23:48 +02009912#ifdef CONFIG_PM
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009913static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
9914 struct cfg80211_registered_device *rdev)
9915{
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009916 struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009917 struct nlattr *nl_pats, *nl_pat;
9918 int i, pat_len;
9919
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009920 if (!wowlan->n_patterns)
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009921 return 0;
9922
9923 nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
9924 if (!nl_pats)
9925 return -ENOBUFS;
9926
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009927 for (i = 0; i < wowlan->n_patterns; i++) {
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009928 nl_pat = nla_nest_start(msg, i + 1);
9929 if (!nl_pat)
9930 return -ENOBUFS;
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009931 pat_len = wowlan->patterns[i].pattern_len;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07009932 if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009933 wowlan->patterns[i].mask) ||
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07009934 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
9935 wowlan->patterns[i].pattern) ||
9936 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
Johannes Berg6abb9cb2013-05-15 09:30:07 +02009937 wowlan->patterns[i].pkt_offset))
Amitkumar Karwarbb92d192013-02-12 12:16:26 -08009938 return -ENOBUFS;
9939 nla_nest_end(msg, nl_pat);
9940 }
9941 nla_nest_end(msg, nl_pats);
9942
9943 return 0;
9944}
9945
Johannes Berg2a0e0472013-01-23 22:57:40 +01009946static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
9947 struct cfg80211_wowlan_tcp *tcp)
9948{
9949 struct nlattr *nl_tcp;
9950
9951 if (!tcp)
9952 return 0;
9953
9954 nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
9955 if (!nl_tcp)
9956 return -ENOBUFS;
9957
Jiri Benc930345e2015-03-29 16:59:25 +02009958 if (nla_put_in_addr(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
9959 nla_put_in_addr(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
Johannes Berg2a0e0472013-01-23 22:57:40 +01009960 nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
9961 nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
9962 nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
9963 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
9964 tcp->payload_len, tcp->payload) ||
9965 nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
9966 tcp->data_interval) ||
9967 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
9968 tcp->wake_len, tcp->wake_data) ||
9969 nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK,
9970 DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask))
9971 return -ENOBUFS;
9972
9973 if (tcp->payload_seq.len &&
9974 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
9975 sizeof(tcp->payload_seq), &tcp->payload_seq))
9976 return -ENOBUFS;
9977
9978 if (tcp->payload_tok.len &&
9979 nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
9980 sizeof(tcp->payload_tok) + tcp->tokens_size,
9981 &tcp->payload_tok))
9982 return -ENOBUFS;
9983
Johannes Berge248ad32013-05-16 10:24:28 +02009984 nla_nest_end(msg, nl_tcp);
9985
Johannes Berg2a0e0472013-01-23 22:57:40 +01009986 return 0;
9987}
9988
Luciano Coelho75453cc2015-01-09 14:06:37 +02009989static int nl80211_send_wowlan_nd(struct sk_buff *msg,
9990 struct cfg80211_sched_scan_request *req)
9991{
Avraham Stern3b06d272015-10-12 09:51:34 +03009992 struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
Luciano Coelho75453cc2015-01-09 14:06:37 +02009993 int i;
9994
9995 if (!req)
9996 return 0;
9997
9998 nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
9999 if (!nd)
10000 return -ENOBUFS;
10001
Avraham Stern3b06d272015-10-12 09:51:34 +030010002 if (req->n_scan_plans == 1 &&
10003 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
10004 req->scan_plans[0].interval * 1000))
Luciano Coelho75453cc2015-01-09 14:06:37 +020010005 return -ENOBUFS;
10006
Luciano Coelho21fea562015-03-17 16:36:01 +020010007 if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
10008 return -ENOBUFS;
10009
vamsi krishnabf95ecd2017-01-13 01:12:20 +020010010 if (req->relative_rssi_set) {
10011 struct nl80211_bss_select_rssi_adjust rssi_adjust;
10012
10013 if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
10014 req->relative_rssi))
10015 return -ENOBUFS;
10016
10017 rssi_adjust.band = req->rssi_adjust.band;
10018 rssi_adjust.delta = req->rssi_adjust.delta;
10019 if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
10020 sizeof(rssi_adjust), &rssi_adjust))
10021 return -ENOBUFS;
10022 }
10023
Luciano Coelho75453cc2015-01-09 14:06:37 +020010024 freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
10025 if (!freqs)
10026 return -ENOBUFS;
10027
Johannes Berg53b18982016-09-14 09:59:21 +020010028 for (i = 0; i < req->n_channels; i++) {
10029 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
10030 return -ENOBUFS;
10031 }
Luciano Coelho75453cc2015-01-09 14:06:37 +020010032
10033 nla_nest_end(msg, freqs);
10034
10035 if (req->n_match_sets) {
10036 matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
Johannes Berg76e1fb42016-09-14 09:55:57 +020010037 if (!matches)
10038 return -ENOBUFS;
10039
Luciano Coelho75453cc2015-01-09 14:06:37 +020010040 for (i = 0; i < req->n_match_sets; i++) {
10041 match = nla_nest_start(msg, i);
Johannes Berg76e1fb42016-09-14 09:55:57 +020010042 if (!match)
10043 return -ENOBUFS;
10044
Johannes Berg53b18982016-09-14 09:59:21 +020010045 if (nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
10046 req->match_sets[i].ssid.ssid_len,
10047 req->match_sets[i].ssid.ssid))
10048 return -ENOBUFS;
Luciano Coelho75453cc2015-01-09 14:06:37 +020010049 nla_nest_end(msg, match);
10050 }
10051 nla_nest_end(msg, matches);
10052 }
10053
Avraham Stern3b06d272015-10-12 09:51:34 +030010054 scan_plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
10055 if (!scan_plans)
10056 return -ENOBUFS;
10057
10058 for (i = 0; i < req->n_scan_plans; i++) {
10059 scan_plan = nla_nest_start(msg, i + 1);
Johannes Berg76e1fb42016-09-14 09:55:57 +020010060 if (!scan_plan)
10061 return -ENOBUFS;
10062
Avraham Stern3b06d272015-10-12 09:51:34 +030010063 if (!scan_plan ||
10064 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
10065 req->scan_plans[i].interval) ||
10066 (req->scan_plans[i].iterations &&
10067 nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
10068 req->scan_plans[i].iterations)))
10069 return -ENOBUFS;
10070 nla_nest_end(msg, scan_plan);
10071 }
10072 nla_nest_end(msg, scan_plans);
10073
Luciano Coelho75453cc2015-01-09 14:06:37 +020010074 nla_nest_end(msg, nd);
10075
10076 return 0;
10077}
10078
Johannes Bergff1b6e62011-05-04 15:37:28 +020010079static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
10080{
10081 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10082 struct sk_buff *msg;
10083 void *hdr;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010084 u32 size = NLMSG_DEFAULT_SIZE;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010085
Johannes Berg964dc9e2013-06-03 17:25:34 +020010086 if (!rdev->wiphy.wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010087 return -EOPNOTSUPP;
10088
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010089 if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
Johannes Berg2a0e0472013-01-23 22:57:40 +010010090 /* adjust size to have room for all the data */
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010091 size += rdev->wiphy.wowlan_config->tcp->tokens_size +
10092 rdev->wiphy.wowlan_config->tcp->payload_len +
10093 rdev->wiphy.wowlan_config->tcp->wake_len +
10094 rdev->wiphy.wowlan_config->tcp->wake_len / 8;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010095 }
10096
10097 msg = nlmsg_new(size, GFP_KERNEL);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010098 if (!msg)
10099 return -ENOMEM;
10100
Eric W. Biederman15e47302012-09-07 20:12:54 +000010101 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Bergff1b6e62011-05-04 15:37:28 +020010102 NL80211_CMD_GET_WOWLAN);
10103 if (!hdr)
10104 goto nla_put_failure;
10105
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010106 if (rdev->wiphy.wowlan_config) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020010107 struct nlattr *nl_wowlan;
10108
10109 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
10110 if (!nl_wowlan)
10111 goto nla_put_failure;
10112
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010113 if ((rdev->wiphy.wowlan_config->any &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010114 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010115 (rdev->wiphy.wowlan_config->disconnect &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010116 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010117 (rdev->wiphy.wowlan_config->magic_pkt &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010118 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010119 (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010120 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010121 (rdev->wiphy.wowlan_config->eap_identity_req &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010122 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010123 (rdev->wiphy.wowlan_config->four_way_handshake &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010124 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010125 (rdev->wiphy.wowlan_config->rfkill_release &&
David S. Miller9360ffd2012-03-29 04:41:26 -040010126 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
10127 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010128
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010129 if (nl80211_send_wowlan_patterns(msg, rdev))
10130 goto nla_put_failure;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010131
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010132 if (nl80211_send_wowlan_tcp(msg,
10133 rdev->wiphy.wowlan_config->tcp))
Johannes Berg2a0e0472013-01-23 22:57:40 +010010134 goto nla_put_failure;
10135
Luciano Coelho75453cc2015-01-09 14:06:37 +020010136 if (nl80211_send_wowlan_nd(
10137 msg,
10138 rdev->wiphy.wowlan_config->nd_config))
10139 goto nla_put_failure;
10140
Johannes Bergff1b6e62011-05-04 15:37:28 +020010141 nla_nest_end(msg, nl_wowlan);
10142 }
10143
10144 genlmsg_end(msg, hdr);
10145 return genlmsg_reply(msg, info);
10146
10147nla_put_failure:
10148 nlmsg_free(msg);
10149 return -ENOBUFS;
10150}
10151
Johannes Berg2a0e0472013-01-23 22:57:40 +010010152static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
10153 struct nlattr *attr,
10154 struct cfg80211_wowlan *trig)
10155{
10156 struct nlattr *tb[NUM_NL80211_WOWLAN_TCP];
10157 struct cfg80211_wowlan_tcp *cfg;
10158 struct nl80211_wowlan_tcp_data_token *tok = NULL;
10159 struct nl80211_wowlan_tcp_data_seq *seq = NULL;
10160 u32 size;
10161 u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
10162 int err, port;
10163
Johannes Berg964dc9e2013-06-03 17:25:34 +020010164 if (!rdev->wiphy.wowlan->tcp)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010165 return -EINVAL;
10166
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010167 err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TCP, attr,
10168 nl80211_wowlan_tcp_policy);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010169 if (err)
10170 return err;
10171
10172 if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] ||
10173 !tb[NL80211_WOWLAN_TCP_DST_IPV4] ||
10174 !tb[NL80211_WOWLAN_TCP_DST_MAC] ||
10175 !tb[NL80211_WOWLAN_TCP_DST_PORT] ||
10176 !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] ||
10177 !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] ||
10178 !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] ||
10179 !tb[NL80211_WOWLAN_TCP_WAKE_MASK])
10180 return -EINVAL;
10181
10182 data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010183 if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010184 return -EINVAL;
10185
10186 if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
Johannes Berg964dc9e2013-06-03 17:25:34 +020010187 rdev->wiphy.wowlan->tcp->data_interval_max ||
Johannes Berg723d5682013-02-26 13:56:40 +010010188 nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010189 return -EINVAL;
10190
10191 wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010192 if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010193 return -EINVAL;
10194
10195 wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
10196 if (wake_mask_size != DIV_ROUND_UP(wake_size, 8))
10197 return -EINVAL;
10198
10199 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) {
10200 u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
10201
10202 tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]);
10203 tokens_size = tokln - sizeof(*tok);
10204
10205 if (!tok->len || tokens_size % tok->len)
10206 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010207 if (!rdev->wiphy.wowlan->tcp->tok)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010208 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010209 if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010210 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010211 if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010212 return -EINVAL;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010213 if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010214 return -EINVAL;
10215 if (tok->offset + tok->len > data_size)
10216 return -EINVAL;
10217 }
10218
10219 if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
10220 seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
Johannes Berg964dc9e2013-06-03 17:25:34 +020010221 if (!rdev->wiphy.wowlan->tcp->seq)
Johannes Berg2a0e0472013-01-23 22:57:40 +010010222 return -EINVAL;
10223 if (seq->len == 0 || seq->len > 4)
10224 return -EINVAL;
10225 if (seq->len + seq->offset > data_size)
10226 return -EINVAL;
10227 }
10228
10229 size = sizeof(*cfg);
10230 size += data_size;
10231 size += wake_size + wake_mask_size;
10232 size += tokens_size;
10233
10234 cfg = kzalloc(size, GFP_KERNEL);
10235 if (!cfg)
10236 return -ENOMEM;
Jiri Benc67b61f62015-03-29 16:59:26 +020010237 cfg->src = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
10238 cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010239 memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
10240 ETH_ALEN);
10241 if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
10242 port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
10243 else
10244 port = 0;
10245#ifdef CONFIG_INET
10246 /* allocate a socket and port for it and use it */
10247 err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
10248 IPPROTO_TCP, &cfg->sock, 1);
10249 if (err) {
10250 kfree(cfg);
10251 return err;
10252 }
10253 if (inet_csk_get_port(cfg->sock->sk, port)) {
10254 sock_release(cfg->sock);
10255 kfree(cfg);
10256 return -EADDRINUSE;
10257 }
10258 cfg->src_port = inet_sk(cfg->sock->sk)->inet_num;
10259#else
10260 if (!port) {
10261 kfree(cfg);
10262 return -EINVAL;
10263 }
10264 cfg->src_port = port;
10265#endif
10266
10267 cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]);
10268 cfg->payload_len = data_size;
10269 cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size;
10270 memcpy((void *)cfg->payload,
10271 nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]),
10272 data_size);
10273 if (seq)
10274 cfg->payload_seq = *seq;
10275 cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]);
10276 cfg->wake_len = wake_size;
10277 cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size;
10278 memcpy((void *)cfg->wake_data,
10279 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]),
10280 wake_size);
10281 cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size +
10282 data_size + wake_size;
10283 memcpy((void *)cfg->wake_mask,
10284 nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]),
10285 wake_mask_size);
10286 if (tok) {
10287 cfg->tokens_size = tokens_size;
10288 memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size);
10289 }
10290
10291 trig->tcp = cfg;
10292
10293 return 0;
10294}
10295
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010296static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
10297 const struct wiphy_wowlan_support *wowlan,
10298 struct nlattr *attr,
10299 struct cfg80211_wowlan *trig)
10300{
10301 struct nlattr **tb;
10302 int err;
10303
10304 tb = kzalloc(NUM_NL80211_ATTR * sizeof(*tb), GFP_KERNEL);
10305 if (!tb)
10306 return -ENOMEM;
10307
10308 if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) {
10309 err = -EOPNOTSUPP;
10310 goto out;
10311 }
10312
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010313 err = nla_parse_nested(tb, NL80211_ATTR_MAX, attr, nl80211_policy);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010314 if (err)
10315 goto out;
10316
Arend Van Sprielaad1e812017-01-27 12:27:44 +000010317 trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb,
10318 wowlan->max_nd_match_sets);
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010319 err = PTR_ERR_OR_ZERO(trig->nd_config);
10320 if (err)
10321 trig->nd_config = NULL;
10322
10323out:
10324 kfree(tb);
10325 return err;
10326}
10327
Johannes Bergff1b6e62011-05-04 15:37:28 +020010328static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
10329{
10330 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10331 struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010332 struct cfg80211_wowlan new_triggers = {};
Johannes Bergae33bd82012-07-12 16:25:02 +020010333 struct cfg80211_wowlan *ntrig;
Johannes Berg964dc9e2013-06-03 17:25:34 +020010334 const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010335 int err, i;
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010336 bool prev_enabled = rdev->wiphy.wowlan_config;
Johannes Berg98fc4382015-03-01 09:10:13 +020010337 bool regular = false;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010338
Johannes Berg964dc9e2013-06-03 17:25:34 +020010339 if (!wowlan)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010340 return -EOPNOTSUPP;
10341
Johannes Bergae33bd82012-07-12 16:25:02 +020010342 if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
10343 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010344 rdev->wiphy.wowlan_config = NULL;
Johannes Bergae33bd82012-07-12 16:25:02 +020010345 goto set_wakeup;
10346 }
Johannes Bergff1b6e62011-05-04 15:37:28 +020010347
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010348 err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TRIG,
10349 info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS],
10350 nl80211_wowlan_policy);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010351 if (err)
10352 return err;
10353
10354 if (tb[NL80211_WOWLAN_TRIG_ANY]) {
10355 if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
10356 return -EINVAL;
10357 new_triggers.any = true;
10358 }
10359
10360 if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
10361 if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
10362 return -EINVAL;
10363 new_triggers.disconnect = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010364 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010365 }
10366
10367 if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
10368 if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
10369 return -EINVAL;
10370 new_triggers.magic_pkt = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010371 regular = true;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010372 }
10373
Johannes Berg77dbbb12011-07-13 10:48:55 +020010374 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
10375 return -EINVAL;
10376
10377 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) {
10378 if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
10379 return -EINVAL;
10380 new_triggers.gtk_rekey_failure = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010381 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010382 }
10383
10384 if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
10385 if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
10386 return -EINVAL;
10387 new_triggers.eap_identity_req = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010388 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010389 }
10390
10391 if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
10392 if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
10393 return -EINVAL;
10394 new_triggers.four_way_handshake = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010395 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010396 }
10397
10398 if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
10399 if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
10400 return -EINVAL;
10401 new_triggers.rfkill_release = true;
Johannes Berg98fc4382015-03-01 09:10:13 +020010402 regular = true;
Johannes Berg77dbbb12011-07-13 10:48:55 +020010403 }
10404
Johannes Bergff1b6e62011-05-04 15:37:28 +020010405 if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
10406 struct nlattr *pat;
10407 int n_patterns = 0;
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010408 int rem, pat_len, mask_len, pkt_offset;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010409 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
Johannes Bergff1b6e62011-05-04 15:37:28 +020010410
Johannes Berg98fc4382015-03-01 09:10:13 +020010411 regular = true;
10412
Johannes Bergff1b6e62011-05-04 15:37:28 +020010413 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10414 rem)
10415 n_patterns++;
10416 if (n_patterns > wowlan->n_patterns)
10417 return -EINVAL;
10418
10419 new_triggers.patterns = kcalloc(n_patterns,
10420 sizeof(new_triggers.patterns[0]),
10421 GFP_KERNEL);
10422 if (!new_triggers.patterns)
10423 return -ENOMEM;
10424
10425 new_triggers.n_patterns = n_patterns;
10426 i = 0;
10427
10428 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
10429 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010430 u8 *mask_pat;
10431
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010432 nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat,
10433 NULL);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010434 err = -EINVAL;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010435 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10436 !pat_tb[NL80211_PKTPAT_PATTERN])
Johannes Bergff1b6e62011-05-04 15:37:28 +020010437 goto error;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010438 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010439 mask_len = DIV_ROUND_UP(pat_len, 8);
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010440 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
Johannes Bergff1b6e62011-05-04 15:37:28 +020010441 goto error;
10442 if (pat_len > wowlan->pattern_max_len ||
10443 pat_len < wowlan->pattern_min_len)
10444 goto error;
10445
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010446 if (!pat_tb[NL80211_PKTPAT_OFFSET])
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010447 pkt_offset = 0;
10448 else
10449 pkt_offset = nla_get_u32(
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010450 pat_tb[NL80211_PKTPAT_OFFSET]);
Amitkumar Karwarbb92d192013-02-12 12:16:26 -080010451 if (pkt_offset > wowlan->max_pkt_offset)
10452 goto error;
10453 new_triggers.patterns[i].pkt_offset = pkt_offset;
10454
Johannes Berg922bd802014-05-19 17:59:50 +020010455 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10456 if (!mask_pat) {
Johannes Bergff1b6e62011-05-04 15:37:28 +020010457 err = -ENOMEM;
10458 goto error;
10459 }
Johannes Berg922bd802014-05-19 17:59:50 +020010460 new_triggers.patterns[i].mask = mask_pat;
10461 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010462 mask_len);
Johannes Berg922bd802014-05-19 17:59:50 +020010463 mask_pat += mask_len;
10464 new_triggers.patterns[i].pattern = mask_pat;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010465 new_triggers.patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010466 memcpy(mask_pat,
Amitkumar Karwar50ac6602013-06-25 19:03:56 -070010467 nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
Johannes Bergff1b6e62011-05-04 15:37:28 +020010468 pat_len);
10469 i++;
10470 }
10471 }
10472
Johannes Berg2a0e0472013-01-23 22:57:40 +010010473 if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010474 regular = true;
Johannes Berg2a0e0472013-01-23 22:57:40 +010010475 err = nl80211_parse_wowlan_tcp(
10476 rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
10477 &new_triggers);
10478 if (err)
10479 goto error;
10480 }
10481
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010482 if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
Johannes Berg98fc4382015-03-01 09:10:13 +020010483 regular = true;
Luciano Coelho8cd4d452014-09-17 11:55:28 +030010484 err = nl80211_parse_wowlan_nd(
10485 rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
10486 &new_triggers);
10487 if (err)
10488 goto error;
10489 }
10490
Johannes Berg98fc4382015-03-01 09:10:13 +020010491 /* The 'any' trigger means the device continues operating more or less
10492 * as in its normal operation mode and wakes up the host on most of the
10493 * normal interrupts (like packet RX, ...)
10494 * It therefore makes little sense to combine with the more constrained
10495 * wakeup trigger modes.
10496 */
10497 if (new_triggers.any && regular) {
10498 err = -EINVAL;
10499 goto error;
10500 }
10501
Johannes Bergae33bd82012-07-12 16:25:02 +020010502 ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
10503 if (!ntrig) {
10504 err = -ENOMEM;
10505 goto error;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010506 }
Johannes Bergae33bd82012-07-12 16:25:02 +020010507 cfg80211_rdev_free_wowlan(rdev);
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010508 rdev->wiphy.wowlan_config = ntrig;
Johannes Bergff1b6e62011-05-04 15:37:28 +020010509
Johannes Bergae33bd82012-07-12 16:25:02 +020010510 set_wakeup:
Johannes Berg6abb9cb2013-05-15 09:30:07 +020010511 if (rdev->ops->set_wakeup &&
10512 prev_enabled != !!rdev->wiphy.wowlan_config)
10513 rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
Johannes Berg6d525632012-04-04 15:05:25 +020010514
Johannes Bergff1b6e62011-05-04 15:37:28 +020010515 return 0;
10516 error:
10517 for (i = 0; i < new_triggers.n_patterns; i++)
10518 kfree(new_triggers.patterns[i].mask);
10519 kfree(new_triggers.patterns);
Johannes Berg2a0e0472013-01-23 22:57:40 +010010520 if (new_triggers.tcp && new_triggers.tcp->sock)
10521 sock_release(new_triggers.tcp->sock);
10522 kfree(new_triggers.tcp);
Ola Olssone5dbe072015-12-12 23:17:17 +010010523 kfree(new_triggers.nd_config);
Johannes Bergff1b6e62011-05-04 15:37:28 +020010524 return err;
10525}
Johannes Bergdfb89c52012-06-27 09:23:48 +020010526#endif
Johannes Bergff1b6e62011-05-04 15:37:28 +020010527
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010528static int nl80211_send_coalesce_rules(struct sk_buff *msg,
10529 struct cfg80211_registered_device *rdev)
10530{
10531 struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
10532 int i, j, pat_len;
10533 struct cfg80211_coalesce_rules *rule;
10534
10535 if (!rdev->coalesce->n_rules)
10536 return 0;
10537
10538 nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
10539 if (!nl_rules)
10540 return -ENOBUFS;
10541
10542 for (i = 0; i < rdev->coalesce->n_rules; i++) {
10543 nl_rule = nla_nest_start(msg, i + 1);
10544 if (!nl_rule)
10545 return -ENOBUFS;
10546
10547 rule = &rdev->coalesce->rules[i];
10548 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
10549 rule->delay))
10550 return -ENOBUFS;
10551
10552 if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
10553 rule->condition))
10554 return -ENOBUFS;
10555
10556 nl_pats = nla_nest_start(msg,
10557 NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
10558 if (!nl_pats)
10559 return -ENOBUFS;
10560
10561 for (j = 0; j < rule->n_patterns; j++) {
10562 nl_pat = nla_nest_start(msg, j + 1);
10563 if (!nl_pat)
10564 return -ENOBUFS;
10565 pat_len = rule->patterns[j].pattern_len;
10566 if (nla_put(msg, NL80211_PKTPAT_MASK,
10567 DIV_ROUND_UP(pat_len, 8),
10568 rule->patterns[j].mask) ||
10569 nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
10570 rule->patterns[j].pattern) ||
10571 nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
10572 rule->patterns[j].pkt_offset))
10573 return -ENOBUFS;
10574 nla_nest_end(msg, nl_pat);
10575 }
10576 nla_nest_end(msg, nl_pats);
10577 nla_nest_end(msg, nl_rule);
10578 }
10579 nla_nest_end(msg, nl_rules);
10580
10581 return 0;
10582}
10583
10584static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
10585{
10586 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10587 struct sk_buff *msg;
10588 void *hdr;
10589
10590 if (!rdev->wiphy.coalesce)
10591 return -EOPNOTSUPP;
10592
10593 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10594 if (!msg)
10595 return -ENOMEM;
10596
10597 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
10598 NL80211_CMD_GET_COALESCE);
10599 if (!hdr)
10600 goto nla_put_failure;
10601
10602 if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
10603 goto nla_put_failure;
10604
10605 genlmsg_end(msg, hdr);
10606 return genlmsg_reply(msg, info);
10607
10608nla_put_failure:
10609 nlmsg_free(msg);
10610 return -ENOBUFS;
10611}
10612
10613void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
10614{
10615 struct cfg80211_coalesce *coalesce = rdev->coalesce;
10616 int i, j;
10617 struct cfg80211_coalesce_rules *rule;
10618
10619 if (!coalesce)
10620 return;
10621
10622 for (i = 0; i < coalesce->n_rules; i++) {
10623 rule = &coalesce->rules[i];
10624 for (j = 0; j < rule->n_patterns; j++)
10625 kfree(rule->patterns[j].mask);
10626 kfree(rule->patterns);
10627 }
10628 kfree(coalesce->rules);
10629 kfree(coalesce);
10630 rdev->coalesce = NULL;
10631}
10632
10633static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
10634 struct nlattr *rule,
10635 struct cfg80211_coalesce_rules *new_rule)
10636{
10637 int err, i;
10638 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10639 struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
10640 int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
10641 struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
10642
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010643 err = nla_parse_nested(tb, NL80211_ATTR_COALESCE_RULE_MAX, rule,
10644 nl80211_coalesce_policy);
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010645 if (err)
10646 return err;
10647
10648 if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
10649 new_rule->delay =
10650 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
10651 if (new_rule->delay > coalesce->max_delay)
10652 return -EINVAL;
10653
10654 if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
10655 new_rule->condition =
10656 nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
10657 if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH &&
10658 new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH)
10659 return -EINVAL;
10660
10661 if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
10662 return -EINVAL;
10663
10664 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
10665 rem)
10666 n_patterns++;
10667 if (n_patterns > coalesce->n_patterns)
10668 return -EINVAL;
10669
10670 new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
10671 GFP_KERNEL);
10672 if (!new_rule->patterns)
10673 return -ENOMEM;
10674
10675 new_rule->n_patterns = n_patterns;
10676 i = 0;
10677
10678 nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
10679 rem) {
Johannes Berg922bd802014-05-19 17:59:50 +020010680 u8 *mask_pat;
10681
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010682 nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat, NULL);
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010683 if (!pat_tb[NL80211_PKTPAT_MASK] ||
10684 !pat_tb[NL80211_PKTPAT_PATTERN])
10685 return -EINVAL;
10686 pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
10687 mask_len = DIV_ROUND_UP(pat_len, 8);
10688 if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
10689 return -EINVAL;
10690 if (pat_len > coalesce->pattern_max_len ||
10691 pat_len < coalesce->pattern_min_len)
10692 return -EINVAL;
10693
10694 if (!pat_tb[NL80211_PKTPAT_OFFSET])
10695 pkt_offset = 0;
10696 else
10697 pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
10698 if (pkt_offset > coalesce->max_pkt_offset)
10699 return -EINVAL;
10700 new_rule->patterns[i].pkt_offset = pkt_offset;
10701
Johannes Berg922bd802014-05-19 17:59:50 +020010702 mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
10703 if (!mask_pat)
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010704 return -ENOMEM;
Johannes Berg922bd802014-05-19 17:59:50 +020010705
10706 new_rule->patterns[i].mask = mask_pat;
10707 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
10708 mask_len);
10709
10710 mask_pat += mask_len;
10711 new_rule->patterns[i].pattern = mask_pat;
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010712 new_rule->patterns[i].pattern_len = pat_len;
Johannes Berg922bd802014-05-19 17:59:50 +020010713 memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
10714 pat_len);
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010715 i++;
10716 }
10717
10718 return 0;
10719}
10720
10721static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
10722{
10723 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10724 const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
10725 struct cfg80211_coalesce new_coalesce = {};
10726 struct cfg80211_coalesce *n_coalesce;
10727 int err, rem_rule, n_rules = 0, i, j;
10728 struct nlattr *rule;
10729 struct cfg80211_coalesce_rules *tmp_rule;
10730
10731 if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
10732 return -EOPNOTSUPP;
10733
10734 if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
10735 cfg80211_rdev_free_coalesce(rdev);
Ilan Peera1056b12015-10-22 22:27:46 +030010736 rdev_set_coalesce(rdev, NULL);
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010737 return 0;
10738 }
10739
10740 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
10741 rem_rule)
10742 n_rules++;
10743 if (n_rules > coalesce->n_rules)
10744 return -EINVAL;
10745
10746 new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
10747 GFP_KERNEL);
10748 if (!new_coalesce.rules)
10749 return -ENOMEM;
10750
10751 new_coalesce.n_rules = n_rules;
10752 i = 0;
10753
10754 nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
10755 rem_rule) {
10756 err = nl80211_parse_coalesce_rule(rdev, rule,
10757 &new_coalesce.rules[i]);
10758 if (err)
10759 goto error;
10760
10761 i++;
10762 }
10763
Ilan Peera1056b12015-10-22 22:27:46 +030010764 err = rdev_set_coalesce(rdev, &new_coalesce);
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070010765 if (err)
10766 goto error;
10767
10768 n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
10769 if (!n_coalesce) {
10770 err = -ENOMEM;
10771 goto error;
10772 }
10773 cfg80211_rdev_free_coalesce(rdev);
10774 rdev->coalesce = n_coalesce;
10775
10776 return 0;
10777error:
10778 for (i = 0; i < new_coalesce.n_rules; i++) {
10779 tmp_rule = &new_coalesce.rules[i];
10780 for (j = 0; j < tmp_rule->n_patterns; j++)
10781 kfree(tmp_rule->patterns[j].mask);
10782 kfree(tmp_rule->patterns);
10783 }
10784 kfree(new_coalesce.rules);
10785
10786 return err;
10787}
10788
Johannes Berge5497d72011-07-05 16:35:40 +020010789static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
10790{
10791 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10792 struct net_device *dev = info->user_ptr[1];
10793 struct wireless_dev *wdev = dev->ieee80211_ptr;
10794 struct nlattr *tb[NUM_NL80211_REKEY_DATA];
10795 struct cfg80211_gtk_rekey_data rekey_data;
10796 int err;
10797
10798 if (!info->attrs[NL80211_ATTR_REKEY_DATA])
10799 return -EINVAL;
10800
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020010801 err = nla_parse_nested(tb, MAX_NL80211_REKEY_DATA,
10802 info->attrs[NL80211_ATTR_REKEY_DATA],
10803 nl80211_rekey_policy);
Johannes Berge5497d72011-07-05 16:35:40 +020010804 if (err)
10805 return err;
10806
10807 if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
10808 return -ERANGE;
10809 if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
10810 return -ERANGE;
10811 if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
10812 return -ERANGE;
10813
Johannes Berg78f686c2014-09-10 22:28:06 +030010814 rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
10815 rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
10816 rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
Johannes Berge5497d72011-07-05 16:35:40 +020010817
10818 wdev_lock(wdev);
10819 if (!wdev->current_bss) {
10820 err = -ENOTCONN;
10821 goto out;
10822 }
10823
10824 if (!rdev->ops->set_rekey_data) {
10825 err = -EOPNOTSUPP;
10826 goto out;
10827 }
10828
Hila Gonene35e4d22012-06-27 17:19:42 +030010829 err = rdev_set_rekey_data(rdev, dev, &rekey_data);
Johannes Berge5497d72011-07-05 16:35:40 +020010830 out:
10831 wdev_unlock(wdev);
10832 return err;
10833}
10834
Johannes Berg28946da2011-11-04 11:18:12 +010010835static int nl80211_register_unexpected_frame(struct sk_buff *skb,
10836 struct genl_info *info)
10837{
10838 struct net_device *dev = info->user_ptr[1];
10839 struct wireless_dev *wdev = dev->ieee80211_ptr;
10840
10841 if (wdev->iftype != NL80211_IFTYPE_AP &&
10842 wdev->iftype != NL80211_IFTYPE_P2P_GO)
10843 return -EINVAL;
10844
Eric W. Biederman15e47302012-09-07 20:12:54 +000010845 if (wdev->ap_unexpected_nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010010846 return -EBUSY;
10847
Eric W. Biederman15e47302012-09-07 20:12:54 +000010848 wdev->ap_unexpected_nlportid = info->snd_portid;
Johannes Berg28946da2011-11-04 11:18:12 +010010849 return 0;
10850}
10851
Johannes Berg7f6cf312011-11-04 11:18:15 +010010852static int nl80211_probe_client(struct sk_buff *skb,
10853 struct genl_info *info)
10854{
10855 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10856 struct net_device *dev = info->user_ptr[1];
10857 struct wireless_dev *wdev = dev->ieee80211_ptr;
10858 struct sk_buff *msg;
10859 void *hdr;
10860 const u8 *addr;
10861 u64 cookie;
10862 int err;
10863
10864 if (wdev->iftype != NL80211_IFTYPE_AP &&
10865 wdev->iftype != NL80211_IFTYPE_P2P_GO)
10866 return -EOPNOTSUPP;
10867
10868 if (!info->attrs[NL80211_ATTR_MAC])
10869 return -EINVAL;
10870
10871 if (!rdev->ops->probe_client)
10872 return -EOPNOTSUPP;
10873
10874 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10875 if (!msg)
10876 return -ENOMEM;
10877
Eric W. Biederman15e47302012-09-07 20:12:54 +000010878 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
Johannes Berg7f6cf312011-11-04 11:18:15 +010010879 NL80211_CMD_PROBE_CLIENT);
Dan Carpentercb35fba2013-08-14 14:50:01 +030010880 if (!hdr) {
10881 err = -ENOBUFS;
Johannes Berg7f6cf312011-11-04 11:18:15 +010010882 goto free_msg;
10883 }
10884
10885 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
10886
Hila Gonene35e4d22012-06-27 17:19:42 +030010887 err = rdev_probe_client(rdev, dev, addr, &cookie);
Johannes Berg7f6cf312011-11-04 11:18:15 +010010888 if (err)
10889 goto free_msg;
10890
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020010891 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
10892 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040010893 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010010894
10895 genlmsg_end(msg, hdr);
10896
10897 return genlmsg_reply(msg, info);
10898
10899 nla_put_failure:
10900 err = -ENOBUFS;
10901 free_msg:
10902 nlmsg_free(msg);
10903 return err;
10904}
10905
Johannes Berg5e760232011-11-04 11:18:17 +010010906static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
10907{
10908 struct cfg80211_registered_device *rdev = info->user_ptr[0];
Ben Greear37c73b52012-10-26 14:49:25 -070010909 struct cfg80211_beacon_registration *reg, *nreg;
10910 int rv;
Johannes Berg5e760232011-11-04 11:18:17 +010010911
10912 if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
10913 return -EOPNOTSUPP;
10914
Ben Greear37c73b52012-10-26 14:49:25 -070010915 nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
10916 if (!nreg)
10917 return -ENOMEM;
Johannes Berg5e760232011-11-04 11:18:17 +010010918
Ben Greear37c73b52012-10-26 14:49:25 -070010919 /* First, check if already registered. */
10920 spin_lock_bh(&rdev->beacon_registrations_lock);
10921 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
10922 if (reg->nlportid == info->snd_portid) {
10923 rv = -EALREADY;
10924 goto out_err;
10925 }
10926 }
10927 /* Add it to the list */
10928 nreg->nlportid = info->snd_portid;
10929 list_add(&nreg->list, &rdev->beacon_registrations);
10930
10931 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010010932
10933 return 0;
Ben Greear37c73b52012-10-26 14:49:25 -070010934out_err:
10935 spin_unlock_bh(&rdev->beacon_registrations_lock);
10936 kfree(nreg);
10937 return rv;
Johannes Berg5e760232011-11-04 11:18:17 +010010938}
10939
Johannes Berg98104fde2012-06-16 00:19:54 +020010940static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
10941{
10942 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10943 struct wireless_dev *wdev = info->user_ptr[1];
10944 int err;
10945
10946 if (!rdev->ops->start_p2p_device)
10947 return -EOPNOTSUPP;
10948
10949 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
10950 return -EOPNOTSUPP;
10951
Arend Van Spriel73c7da32016-10-20 20:08:22 +010010952 if (wdev_running(wdev))
Johannes Berg98104fde2012-06-16 00:19:54 +020010953 return 0;
10954
Luciano Coelhob6a55012014-02-27 11:07:21 +020010955 if (rfkill_blocked(rdev->rfkill))
10956 return -ERFKILL;
Johannes Berg98104fde2012-06-16 00:19:54 +020010957
Johannes Bergeeb126e2012-10-23 15:16:50 +020010958 err = rdev_start_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020010959 if (err)
10960 return err;
10961
Arend Van Spriel73c7da32016-10-20 20:08:22 +010010962 wdev->is_running = true;
Johannes Berg98104fde2012-06-16 00:19:54 +020010963 rdev->opencount++;
Johannes Berg98104fde2012-06-16 00:19:54 +020010964
10965 return 0;
10966}
10967
10968static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
10969{
10970 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10971 struct wireless_dev *wdev = info->user_ptr[1];
10972
10973 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
10974 return -EOPNOTSUPP;
10975
10976 if (!rdev->ops->stop_p2p_device)
10977 return -EOPNOTSUPP;
10978
Johannes Bergf9f47522013-03-19 15:04:07 +010010979 cfg80211_stop_p2p_device(rdev, wdev);
Johannes Berg98104fde2012-06-16 00:19:54 +020010980
10981 return 0;
10982}
10983
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010984static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
10985{
10986 struct cfg80211_registered_device *rdev = info->user_ptr[0];
10987 struct wireless_dev *wdev = info->user_ptr[1];
10988 struct cfg80211_nan_conf conf = {};
10989 int err;
10990
10991 if (wdev->iftype != NL80211_IFTYPE_NAN)
10992 return -EOPNOTSUPP;
10993
Johannes Bergeeb04a92016-11-21 13:55:48 +010010994 if (wdev_running(wdev))
Ayala Bekercb3b7d82016-09-20 17:31:13 +030010995 return -EEXIST;
10996
10997 if (rfkill_blocked(rdev->rfkill))
10998 return -ERFKILL;
10999
11000 if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
11001 return -EINVAL;
11002
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011003 conf.master_pref =
11004 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
11005 if (!conf.master_pref)
11006 return -EINVAL;
11007
Luca Coelho85859892017-02-08 15:00:34 +020011008 if (info->attrs[NL80211_ATTR_BANDS]) {
11009 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
11010
11011 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
11012 return -EOPNOTSUPP;
11013
11014 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
11015 return -EINVAL;
11016
11017 conf.bands = bands;
11018 }
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011019
11020 err = rdev_start_nan(rdev, wdev, &conf);
11021 if (err)
11022 return err;
11023
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011024 wdev->is_running = true;
Ayala Bekercb3b7d82016-09-20 17:31:13 +030011025 rdev->opencount++;
11026
11027 return 0;
11028}
11029
11030static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
11031{
11032 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11033 struct wireless_dev *wdev = info->user_ptr[1];
11034
11035 if (wdev->iftype != NL80211_IFTYPE_NAN)
11036 return -EOPNOTSUPP;
11037
11038 cfg80211_stop_nan(rdev, wdev);
11039
11040 return 0;
11041}
11042
Ayala Bekera442b762016-09-20 17:31:15 +030011043static int validate_nan_filter(struct nlattr *filter_attr)
11044{
11045 struct nlattr *attr;
11046 int len = 0, n_entries = 0, rem;
11047
11048 nla_for_each_nested(attr, filter_attr, rem) {
11049 len += nla_len(attr);
11050 n_entries++;
11051 }
11052
11053 if (len >= U8_MAX)
11054 return -EINVAL;
11055
11056 return n_entries;
11057}
11058
11059static int handle_nan_filter(struct nlattr *attr_filter,
11060 struct cfg80211_nan_func *func,
11061 bool tx)
11062{
11063 struct nlattr *attr;
11064 int n_entries, rem, i;
11065 struct cfg80211_nan_func_filter *filter;
11066
11067 n_entries = validate_nan_filter(attr_filter);
11068 if (n_entries < 0)
11069 return n_entries;
11070
11071 BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters));
11072
11073 filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL);
11074 if (!filter)
11075 return -ENOMEM;
11076
11077 i = 0;
11078 nla_for_each_nested(attr, attr_filter, rem) {
Thomas Grafb15ca182016-10-26 10:53:16 +020011079 filter[i].filter = nla_memdup(attr, GFP_KERNEL);
Ayala Bekera442b762016-09-20 17:31:15 +030011080 filter[i].len = nla_len(attr);
11081 i++;
11082 }
11083 if (tx) {
11084 func->num_tx_filters = n_entries;
11085 func->tx_filters = filter;
11086 } else {
11087 func->num_rx_filters = n_entries;
11088 func->rx_filters = filter;
11089 }
11090
11091 return 0;
11092}
11093
11094static int nl80211_nan_add_func(struct sk_buff *skb,
11095 struct genl_info *info)
11096{
11097 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11098 struct wireless_dev *wdev = info->user_ptr[1];
11099 struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR], *func_attr;
11100 struct cfg80211_nan_func *func;
11101 struct sk_buff *msg = NULL;
11102 void *hdr = NULL;
11103 int err = 0;
11104
11105 if (wdev->iftype != NL80211_IFTYPE_NAN)
11106 return -EOPNOTSUPP;
11107
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011108 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030011109 return -ENOTCONN;
11110
11111 if (!info->attrs[NL80211_ATTR_NAN_FUNC])
11112 return -EINVAL;
11113
11114 if (wdev->owner_nlportid &&
11115 wdev->owner_nlportid != info->snd_portid)
11116 return -ENOTCONN;
11117
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020011118 err = nla_parse_nested(tb, NL80211_NAN_FUNC_ATTR_MAX,
11119 info->attrs[NL80211_ATTR_NAN_FUNC],
11120 nl80211_nan_func_policy);
Ayala Bekera442b762016-09-20 17:31:15 +030011121 if (err)
11122 return err;
11123
11124 func = kzalloc(sizeof(*func), GFP_KERNEL);
11125 if (!func)
11126 return -ENOMEM;
11127
11128 func->cookie = wdev->wiphy->cookie_counter++;
11129
11130 if (!tb[NL80211_NAN_FUNC_TYPE] ||
11131 nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]) > NL80211_NAN_FUNC_MAX_TYPE) {
11132 err = -EINVAL;
11133 goto out;
11134 }
11135
11136
11137 func->type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]);
11138
11139 if (!tb[NL80211_NAN_FUNC_SERVICE_ID]) {
11140 err = -EINVAL;
11141 goto out;
11142 }
11143
11144 memcpy(func->service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]),
11145 sizeof(func->service_id));
11146
11147 func->close_range =
11148 nla_get_flag(tb[NL80211_NAN_FUNC_CLOSE_RANGE]);
11149
11150 if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) {
11151 func->serv_spec_info_len =
11152 nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
11153 func->serv_spec_info =
11154 kmemdup(nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]),
11155 func->serv_spec_info_len,
11156 GFP_KERNEL);
11157 if (!func->serv_spec_info) {
11158 err = -ENOMEM;
11159 goto out;
11160 }
11161 }
11162
11163 if (tb[NL80211_NAN_FUNC_TTL])
11164 func->ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]);
11165
11166 switch (func->type) {
11167 case NL80211_NAN_FUNC_PUBLISH:
11168 if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE]) {
11169 err = -EINVAL;
11170 goto out;
11171 }
11172
11173 func->publish_type =
11174 nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]);
11175 func->publish_bcast =
11176 nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]);
11177
11178 if ((!(func->publish_type & NL80211_NAN_SOLICITED_PUBLISH)) &&
11179 func->publish_bcast) {
11180 err = -EINVAL;
11181 goto out;
11182 }
11183 break;
11184 case NL80211_NAN_FUNC_SUBSCRIBE:
11185 func->subscribe_active =
11186 nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]);
11187 break;
11188 case NL80211_NAN_FUNC_FOLLOW_UP:
11189 if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] ||
11190 !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]) {
11191 err = -EINVAL;
11192 goto out;
11193 }
11194
11195 func->followup_id =
11196 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]);
11197 func->followup_reqid =
11198 nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]);
11199 memcpy(func->followup_dest.addr,
11200 nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]),
11201 sizeof(func->followup_dest.addr));
11202 if (func->ttl) {
11203 err = -EINVAL;
11204 goto out;
11205 }
11206 break;
11207 default:
11208 err = -EINVAL;
11209 goto out;
11210 }
11211
11212 if (tb[NL80211_NAN_FUNC_SRF]) {
11213 struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
11214
Johannes Bergbfe2c7b2016-10-26 14:42:21 +020011215 err = nla_parse_nested(srf_tb, NL80211_NAN_SRF_ATTR_MAX,
11216 tb[NL80211_NAN_FUNC_SRF],
11217 nl80211_nan_srf_policy);
Ayala Bekera442b762016-09-20 17:31:15 +030011218 if (err)
11219 goto out;
11220
11221 func->srf_include =
11222 nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]);
11223
11224 if (srf_tb[NL80211_NAN_SRF_BF]) {
11225 if (srf_tb[NL80211_NAN_SRF_MAC_ADDRS] ||
11226 !srf_tb[NL80211_NAN_SRF_BF_IDX]) {
11227 err = -EINVAL;
11228 goto out;
11229 }
11230
11231 func->srf_bf_len =
11232 nla_len(srf_tb[NL80211_NAN_SRF_BF]);
11233 func->srf_bf =
11234 kmemdup(nla_data(srf_tb[NL80211_NAN_SRF_BF]),
11235 func->srf_bf_len, GFP_KERNEL);
11236 if (!func->srf_bf) {
11237 err = -ENOMEM;
11238 goto out;
11239 }
11240
11241 func->srf_bf_idx =
11242 nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]);
11243 } else {
11244 struct nlattr *attr, *mac_attr =
11245 srf_tb[NL80211_NAN_SRF_MAC_ADDRS];
11246 int n_entries, rem, i = 0;
11247
11248 if (!mac_attr) {
11249 err = -EINVAL;
11250 goto out;
11251 }
11252
11253 n_entries = validate_acl_mac_addrs(mac_attr);
11254 if (n_entries <= 0) {
11255 err = -EINVAL;
11256 goto out;
11257 }
11258
11259 func->srf_num_macs = n_entries;
11260 func->srf_macs =
11261 kzalloc(sizeof(*func->srf_macs) * n_entries,
11262 GFP_KERNEL);
11263 if (!func->srf_macs) {
11264 err = -ENOMEM;
11265 goto out;
11266 }
11267
11268 nla_for_each_nested(attr, mac_attr, rem)
11269 memcpy(func->srf_macs[i++].addr, nla_data(attr),
11270 sizeof(*func->srf_macs));
11271 }
11272 }
11273
11274 if (tb[NL80211_NAN_FUNC_TX_MATCH_FILTER]) {
11275 err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER],
11276 func, true);
11277 if (err)
11278 goto out;
11279 }
11280
11281 if (tb[NL80211_NAN_FUNC_RX_MATCH_FILTER]) {
11282 err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER],
11283 func, false);
11284 if (err)
11285 goto out;
11286 }
11287
11288 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11289 if (!msg) {
11290 err = -ENOMEM;
11291 goto out;
11292 }
11293
11294 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11295 NL80211_CMD_ADD_NAN_FUNCTION);
11296 /* This can't really happen - we just allocated 4KB */
11297 if (WARN_ON(!hdr)) {
11298 err = -ENOMEM;
11299 goto out;
11300 }
11301
11302 err = rdev_add_nan_func(rdev, wdev, func);
11303out:
11304 if (err < 0) {
11305 cfg80211_free_nan_func(func);
11306 nlmsg_free(msg);
11307 return err;
11308 }
11309
11310 /* propagate the instance id and cookie to userspace */
11311 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, func->cookie,
11312 NL80211_ATTR_PAD))
11313 goto nla_put_failure;
11314
11315 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11316 if (!func_attr)
11317 goto nla_put_failure;
11318
11319 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID,
11320 func->instance_id))
11321 goto nla_put_failure;
11322
11323 nla_nest_end(msg, func_attr);
11324
11325 genlmsg_end(msg, hdr);
11326 return genlmsg_reply(msg, info);
11327
11328nla_put_failure:
11329 nlmsg_free(msg);
11330 return -ENOBUFS;
11331}
11332
11333static int nl80211_nan_del_func(struct sk_buff *skb,
11334 struct genl_info *info)
11335{
11336 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11337 struct wireless_dev *wdev = info->user_ptr[1];
11338 u64 cookie;
11339
11340 if (wdev->iftype != NL80211_IFTYPE_NAN)
11341 return -EOPNOTSUPP;
11342
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011343 if (!wdev_running(wdev))
Ayala Bekera442b762016-09-20 17:31:15 +030011344 return -ENOTCONN;
11345
11346 if (!info->attrs[NL80211_ATTR_COOKIE])
11347 return -EINVAL;
11348
11349 if (wdev->owner_nlportid &&
11350 wdev->owner_nlportid != info->snd_portid)
11351 return -ENOTCONN;
11352
11353 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
11354
11355 rdev_del_nan_func(rdev, wdev, cookie);
11356
11357 return 0;
11358}
11359
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011360static int nl80211_nan_change_config(struct sk_buff *skb,
11361 struct genl_info *info)
11362{
11363 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11364 struct wireless_dev *wdev = info->user_ptr[1];
11365 struct cfg80211_nan_conf conf = {};
11366 u32 changed = 0;
11367
11368 if (wdev->iftype != NL80211_IFTYPE_NAN)
11369 return -EOPNOTSUPP;
11370
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011371 if (!wdev_running(wdev))
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011372 return -ENOTCONN;
11373
11374 if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
11375 conf.master_pref =
11376 nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
11377 if (conf.master_pref <= 1 || conf.master_pref == 255)
11378 return -EINVAL;
11379
11380 changed |= CFG80211_NAN_CONF_CHANGED_PREF;
11381 }
11382
Luca Coelho85859892017-02-08 15:00:34 +020011383 if (info->attrs[NL80211_ATTR_BANDS]) {
11384 u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]);
11385
11386 if (bands & ~(u32)wdev->wiphy->nan_supported_bands)
11387 return -EOPNOTSUPP;
11388
11389 if (bands && !(bands & BIT(NL80211_BAND_2GHZ)))
11390 return -EINVAL;
11391
11392 conf.bands = bands;
11393 changed |= CFG80211_NAN_CONF_CHANGED_BANDS;
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030011394 }
11395
11396 if (!changed)
11397 return -EINVAL;
11398
11399 return rdev_nan_change_conf(rdev, wdev, &conf, changed);
11400}
11401
Ayala Beker50bcd312016-09-20 17:31:17 +030011402void cfg80211_nan_match(struct wireless_dev *wdev,
11403 struct cfg80211_nan_match_params *match, gfp_t gfp)
11404{
11405 struct wiphy *wiphy = wdev->wiphy;
11406 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11407 struct nlattr *match_attr, *local_func_attr, *peer_func_attr;
11408 struct sk_buff *msg;
11409 void *hdr;
11410
11411 if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr))
11412 return;
11413
11414 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11415 if (!msg)
11416 return;
11417
11418 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH);
11419 if (!hdr) {
11420 nlmsg_free(msg);
11421 return;
11422 }
11423
11424 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11425 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11426 wdev->netdev->ifindex)) ||
11427 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11428 NL80211_ATTR_PAD))
11429 goto nla_put_failure;
11430
11431 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie,
11432 NL80211_ATTR_PAD) ||
11433 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr))
11434 goto nla_put_failure;
11435
11436 match_attr = nla_nest_start(msg, NL80211_ATTR_NAN_MATCH);
11437 if (!match_attr)
11438 goto nla_put_failure;
11439
11440 local_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_LOCAL);
11441 if (!local_func_attr)
11442 goto nla_put_failure;
11443
11444 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id))
11445 goto nla_put_failure;
11446
11447 nla_nest_end(msg, local_func_attr);
11448
11449 peer_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_PEER);
11450 if (!peer_func_attr)
11451 goto nla_put_failure;
11452
11453 if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) ||
11454 nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id))
11455 goto nla_put_failure;
11456
11457 if (match->info && match->info_len &&
11458 nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len,
11459 match->info))
11460 goto nla_put_failure;
11461
11462 nla_nest_end(msg, peer_func_attr);
11463 nla_nest_end(msg, match_attr);
11464 genlmsg_end(msg, hdr);
11465
11466 if (!wdev->owner_nlportid)
11467 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11468 msg, 0, NL80211_MCGRP_NAN, gfp);
11469 else
11470 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11471 wdev->owner_nlportid);
11472
11473 return;
11474
11475nla_put_failure:
11476 nlmsg_free(msg);
11477}
11478EXPORT_SYMBOL(cfg80211_nan_match);
11479
Ayala Beker368e5a72016-09-20 17:31:18 +030011480void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
11481 u8 inst_id,
11482 enum nl80211_nan_func_term_reason reason,
11483 u64 cookie, gfp_t gfp)
11484{
11485 struct wiphy *wiphy = wdev->wiphy;
11486 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
11487 struct sk_buff *msg;
11488 struct nlattr *func_attr;
11489 void *hdr;
11490
11491 if (WARN_ON(!inst_id))
11492 return;
11493
11494 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
11495 if (!msg)
11496 return;
11497
11498 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_NAN_FUNCTION);
11499 if (!hdr) {
11500 nlmsg_free(msg);
11501 return;
11502 }
11503
11504 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
11505 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
11506 wdev->netdev->ifindex)) ||
11507 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
11508 NL80211_ATTR_PAD))
11509 goto nla_put_failure;
11510
11511 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
11512 NL80211_ATTR_PAD))
11513 goto nla_put_failure;
11514
11515 func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC);
11516 if (!func_attr)
11517 goto nla_put_failure;
11518
11519 if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, inst_id) ||
11520 nla_put_u8(msg, NL80211_NAN_FUNC_TERM_REASON, reason))
11521 goto nla_put_failure;
11522
11523 nla_nest_end(msg, func_attr);
11524 genlmsg_end(msg, hdr);
11525
11526 if (!wdev->owner_nlportid)
11527 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
11528 msg, 0, NL80211_MCGRP_NAN, gfp);
11529 else
11530 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
11531 wdev->owner_nlportid);
11532
11533 return;
11534
11535nla_put_failure:
11536 nlmsg_free(msg);
11537}
11538EXPORT_SYMBOL(cfg80211_nan_func_terminated);
11539
Johannes Berg3713b4e2013-02-14 16:19:38 +010011540static int nl80211_get_protocol_features(struct sk_buff *skb,
11541 struct genl_info *info)
11542{
11543 void *hdr;
11544 struct sk_buff *msg;
11545
11546 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11547 if (!msg)
11548 return -ENOMEM;
11549
11550 hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
11551 NL80211_CMD_GET_PROTOCOL_FEATURES);
11552 if (!hdr)
11553 goto nla_put_failure;
11554
11555 if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
11556 NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
11557 goto nla_put_failure;
11558
11559 genlmsg_end(msg, hdr);
11560 return genlmsg_reply(msg, info);
11561
11562 nla_put_failure:
11563 kfree_skb(msg);
11564 return -ENOBUFS;
11565}
11566
Jouni Malinen355199e2013-02-27 17:14:27 +020011567static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
11568{
11569 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11570 struct cfg80211_update_ft_ies_params ft_params;
11571 struct net_device *dev = info->user_ptr[1];
11572
11573 if (!rdev->ops->update_ft_ies)
11574 return -EOPNOTSUPP;
11575
11576 if (!info->attrs[NL80211_ATTR_MDID] ||
11577 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
11578 return -EINVAL;
11579
11580 memset(&ft_params, 0, sizeof(ft_params));
11581 ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
11582 ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
11583 ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
11584
11585 return rdev_update_ft_ies(rdev, dev, &ft_params);
11586}
11587
Arend van Spriel5de17982013-04-18 15:49:00 +020011588static int nl80211_crit_protocol_start(struct sk_buff *skb,
11589 struct genl_info *info)
11590{
11591 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11592 struct wireless_dev *wdev = info->user_ptr[1];
11593 enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
11594 u16 duration;
11595 int ret;
11596
11597 if (!rdev->ops->crit_proto_start)
11598 return -EOPNOTSUPP;
11599
11600 if (WARN_ON(!rdev->ops->crit_proto_stop))
11601 return -EINVAL;
11602
11603 if (rdev->crit_proto_nlportid)
11604 return -EBUSY;
11605
11606 /* determine protocol if provided */
11607 if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
11608 proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
11609
11610 if (proto >= NUM_NL80211_CRIT_PROTO)
11611 return -EINVAL;
11612
11613 /* timeout must be provided */
11614 if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
11615 return -EINVAL;
11616
11617 duration =
11618 nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
11619
11620 if (duration > NL80211_CRIT_PROTO_MAX_DURATION)
11621 return -ERANGE;
11622
11623 ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
11624 if (!ret)
11625 rdev->crit_proto_nlportid = info->snd_portid;
11626
11627 return ret;
11628}
11629
11630static int nl80211_crit_protocol_stop(struct sk_buff *skb,
11631 struct genl_info *info)
11632{
11633 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11634 struct wireless_dev *wdev = info->user_ptr[1];
11635
11636 if (!rdev->ops->crit_proto_stop)
11637 return -EOPNOTSUPP;
11638
11639 if (rdev->crit_proto_nlportid) {
11640 rdev->crit_proto_nlportid = 0;
11641 rdev_crit_proto_stop(rdev, wdev);
11642 }
11643 return 0;
11644}
11645
Johannes Bergad7e7182013-11-13 13:37:47 +010011646static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
11647{
11648 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11649 struct wireless_dev *wdev =
11650 __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
11651 int i, err;
11652 u32 vid, subcmd;
11653
11654 if (!rdev->wiphy.vendor_commands)
11655 return -EOPNOTSUPP;
11656
11657 if (IS_ERR(wdev)) {
11658 err = PTR_ERR(wdev);
11659 if (err != -EINVAL)
11660 return err;
11661 wdev = NULL;
11662 } else if (wdev->wiphy != &rdev->wiphy) {
11663 return -EINVAL;
11664 }
11665
11666 if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
11667 !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
11668 return -EINVAL;
11669
11670 vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
11671 subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
11672 for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
11673 const struct wiphy_vendor_command *vcmd;
11674 void *data = NULL;
11675 int len = 0;
11676
11677 vcmd = &rdev->wiphy.vendor_commands[i];
11678
11679 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
11680 continue;
11681
11682 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
11683 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
11684 if (!wdev)
11685 return -EINVAL;
11686 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
11687 !wdev->netdev)
11688 return -EINVAL;
11689
11690 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011691 if (!wdev_running(wdev))
Johannes Bergad7e7182013-11-13 13:37:47 +010011692 return -ENETDOWN;
11693 }
Johannes Berg7bdbe402015-08-15 22:39:49 +030011694
11695 if (!vcmd->doit)
11696 return -EOPNOTSUPP;
Johannes Bergad7e7182013-11-13 13:37:47 +010011697 } else {
11698 wdev = NULL;
11699 }
11700
11701 if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
11702 data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
11703 len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
11704 }
11705
11706 rdev->cur_cmd_info = info;
11707 err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
11708 data, len);
11709 rdev->cur_cmd_info = NULL;
11710 return err;
11711 }
11712
11713 return -EOPNOTSUPP;
11714}
11715
Johannes Berg7bdbe402015-08-15 22:39:49 +030011716static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
11717 struct netlink_callback *cb,
11718 struct cfg80211_registered_device **rdev,
11719 struct wireless_dev **wdev)
11720{
Johannes Bergc90c39d2016-10-24 14:40:01 +020011721 struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011722 u32 vid, subcmd;
11723 unsigned int i;
11724 int vcmd_idx = -1;
11725 int err;
11726 void *data = NULL;
11727 unsigned int data_len = 0;
11728
11729 rtnl_lock();
11730
11731 if (cb->args[0]) {
11732 /* subtract the 1 again here */
11733 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
11734 struct wireless_dev *tmp;
11735
11736 if (!wiphy) {
11737 err = -ENODEV;
11738 goto out_unlock;
11739 }
11740 *rdev = wiphy_to_rdev(wiphy);
11741 *wdev = NULL;
11742
11743 if (cb->args[1]) {
Johannes Berg53873f12016-05-03 16:52:04 +030011744 list_for_each_entry(tmp, &wiphy->wdev_list, list) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011745 if (tmp->identifier == cb->args[1] - 1) {
11746 *wdev = tmp;
11747 break;
11748 }
11749 }
11750 }
11751
11752 /* keep rtnl locked in successful case */
11753 return 0;
11754 }
11755
11756 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
Johannes Bergc90c39d2016-10-24 14:40:01 +020011757 attrbuf, nl80211_fam.maxattr, nl80211_policy);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011758 if (err)
11759 goto out_unlock;
11760
Johannes Bergc90c39d2016-10-24 14:40:01 +020011761 if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
11762 !attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011763 err = -EINVAL;
11764 goto out_unlock;
11765 }
11766
Johannes Bergc90c39d2016-10-24 14:40:01 +020011767 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011768 if (IS_ERR(*wdev))
11769 *wdev = NULL;
11770
Johannes Bergc90c39d2016-10-24 14:40:01 +020011771 *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011772 if (IS_ERR(*rdev)) {
11773 err = PTR_ERR(*rdev);
11774 goto out_unlock;
11775 }
11776
Johannes Bergc90c39d2016-10-24 14:40:01 +020011777 vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
11778 subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011779
11780 for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
11781 const struct wiphy_vendor_command *vcmd;
11782
11783 vcmd = &(*rdev)->wiphy.vendor_commands[i];
11784
11785 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
11786 continue;
11787
11788 if (!vcmd->dumpit) {
11789 err = -EOPNOTSUPP;
11790 goto out_unlock;
11791 }
11792
11793 vcmd_idx = i;
11794 break;
11795 }
11796
11797 if (vcmd_idx < 0) {
11798 err = -EOPNOTSUPP;
11799 goto out_unlock;
11800 }
11801
Johannes Bergc90c39d2016-10-24 14:40:01 +020011802 if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
11803 data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
11804 data_len = nla_len(attrbuf[NL80211_ATTR_VENDOR_DATA]);
Johannes Berg7bdbe402015-08-15 22:39:49 +030011805 }
11806
11807 /* 0 is the first index - add 1 to parse only once */
11808 cb->args[0] = (*rdev)->wiphy_idx + 1;
11809 /* add 1 to know if it was NULL */
11810 cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
11811 cb->args[2] = vcmd_idx;
11812 cb->args[3] = (unsigned long)data;
11813 cb->args[4] = data_len;
11814
11815 /* keep rtnl locked in successful case */
11816 return 0;
11817 out_unlock:
11818 rtnl_unlock();
11819 return err;
11820}
11821
11822static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
11823 struct netlink_callback *cb)
11824{
11825 struct cfg80211_registered_device *rdev;
11826 struct wireless_dev *wdev;
11827 unsigned int vcmd_idx;
11828 const struct wiphy_vendor_command *vcmd;
11829 void *data;
11830 int data_len;
11831 int err;
11832 struct nlattr *vendor_data;
11833
11834 err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
11835 if (err)
11836 return err;
11837
11838 vcmd_idx = cb->args[2];
11839 data = (void *)cb->args[3];
11840 data_len = cb->args[4];
11841 vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
11842
11843 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
11844 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
11845 if (!wdev)
11846 return -EINVAL;
11847 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
11848 !wdev->netdev)
11849 return -EINVAL;
11850
11851 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
Arend Van Spriel73c7da32016-10-20 20:08:22 +010011852 if (!wdev_running(wdev))
Johannes Berg7bdbe402015-08-15 22:39:49 +030011853 return -ENETDOWN;
11854 }
11855 }
11856
11857 while (1) {
11858 void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
11859 cb->nlh->nlmsg_seq, NLM_F_MULTI,
11860 NL80211_CMD_VENDOR);
11861 if (!hdr)
11862 break;
11863
11864 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020011865 (wdev && nla_put_u64_64bit(skb, NL80211_ATTR_WDEV,
11866 wdev_id(wdev),
11867 NL80211_ATTR_PAD))) {
Johannes Berg7bdbe402015-08-15 22:39:49 +030011868 genlmsg_cancel(skb, hdr);
11869 break;
11870 }
11871
11872 vendor_data = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
11873 if (!vendor_data) {
11874 genlmsg_cancel(skb, hdr);
11875 break;
11876 }
11877
11878 err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
11879 (unsigned long *)&cb->args[5]);
11880 nla_nest_end(skb, vendor_data);
11881
11882 if (err == -ENOBUFS || err == -ENOENT) {
11883 genlmsg_cancel(skb, hdr);
11884 break;
11885 } else if (err) {
11886 genlmsg_cancel(skb, hdr);
11887 goto out;
11888 }
11889
11890 genlmsg_end(skb, hdr);
11891 }
11892
11893 err = skb->len;
11894 out:
11895 rtnl_unlock();
11896 return err;
11897}
11898
Johannes Bergad7e7182013-11-13 13:37:47 +010011899struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
11900 enum nl80211_commands cmd,
11901 enum nl80211_attrs attr,
11902 int approxlen)
11903{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080011904 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Bergad7e7182013-11-13 13:37:47 +010011905
11906 if (WARN_ON(!rdev->cur_cmd_info))
11907 return NULL;
11908
Ahmad Kholaif6c09e792015-02-26 15:26:53 +020011909 return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
Johannes Bergad7e7182013-11-13 13:37:47 +010011910 rdev->cur_cmd_info->snd_portid,
11911 rdev->cur_cmd_info->snd_seq,
Johannes Berg567ffc32013-12-18 14:43:31 +010011912 cmd, attr, NULL, GFP_KERNEL);
Johannes Bergad7e7182013-11-13 13:37:47 +010011913}
11914EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
11915
11916int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
11917{
11918 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
11919 void *hdr = ((void **)skb->cb)[1];
11920 struct nlattr *data = ((void **)skb->cb)[2];
11921
Johannes Bergbd8c78e2014-07-30 14:55:26 +020011922 /* clear CB data for netlink core to own from now on */
11923 memset(skb->cb, 0, sizeof(skb->cb));
11924
Johannes Bergad7e7182013-11-13 13:37:47 +010011925 if (WARN_ON(!rdev->cur_cmd_info)) {
11926 kfree_skb(skb);
11927 return -EINVAL;
11928 }
11929
11930 nla_nest_end(skb, data);
11931 genlmsg_end(skb, hdr);
11932 return genlmsg_reply(skb, rdev->cur_cmd_info);
11933}
11934EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
11935
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080011936static int nl80211_set_qos_map(struct sk_buff *skb,
11937 struct genl_info *info)
11938{
11939 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11940 struct cfg80211_qos_map *qos_map = NULL;
11941 struct net_device *dev = info->user_ptr[1];
11942 u8 *pos, len, num_des, des_len, des;
11943 int ret;
11944
11945 if (!rdev->ops->set_qos_map)
11946 return -EOPNOTSUPP;
11947
11948 if (info->attrs[NL80211_ATTR_QOS_MAP]) {
11949 pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
11950 len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
11951
11952 if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
11953 len > IEEE80211_QOS_MAP_LEN_MAX)
11954 return -EINVAL;
11955
11956 qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
11957 if (!qos_map)
11958 return -ENOMEM;
11959
11960 num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
11961 if (num_des) {
11962 des_len = num_des *
11963 sizeof(struct cfg80211_dscp_exception);
11964 memcpy(qos_map->dscp_exception, pos, des_len);
11965 qos_map->num_des = num_des;
11966 for (des = 0; des < num_des; des++) {
11967 if (qos_map->dscp_exception[des].up > 7) {
11968 kfree(qos_map);
11969 return -EINVAL;
11970 }
11971 }
11972 pos += des_len;
11973 }
11974 memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
11975 }
11976
11977 wdev_lock(dev->ieee80211_ptr);
11978 ret = nl80211_key_allowed(dev->ieee80211_ptr);
11979 if (!ret)
11980 ret = rdev_set_qos_map(rdev, dev, qos_map);
11981 wdev_unlock(dev->ieee80211_ptr);
11982
11983 kfree(qos_map);
11984 return ret;
11985}
11986
Johannes Berg960d01a2014-09-09 22:55:35 +030011987static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
11988{
11989 struct cfg80211_registered_device *rdev = info->user_ptr[0];
11990 struct net_device *dev = info->user_ptr[1];
11991 struct wireless_dev *wdev = dev->ieee80211_ptr;
11992 const u8 *peer;
11993 u8 tsid, up;
11994 u16 admitted_time = 0;
11995 int err;
11996
Johannes Berg723e73a2014-10-22 09:25:06 +020011997 if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
Johannes Berg960d01a2014-09-09 22:55:35 +030011998 return -EOPNOTSUPP;
11999
12000 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
12001 !info->attrs[NL80211_ATTR_USER_PRIO])
12002 return -EINVAL;
12003
12004 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
12005 if (tsid >= IEEE80211_NUM_TIDS)
12006 return -EINVAL;
12007
12008 up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
12009 if (up >= IEEE80211_NUM_UPS)
12010 return -EINVAL;
12011
12012 /* WMM uses TIDs 0-7 even for TSPEC */
Johannes Berg723e73a2014-10-22 09:25:06 +020012013 if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
Johannes Berg960d01a2014-09-09 22:55:35 +030012014 /* TODO: handle 802.11 TSPEC/admission control
Johannes Berg723e73a2014-10-22 09:25:06 +020012015 * need more attributes for that (e.g. BA session requirement);
12016 * change the WMM adminssion test above to allow both then
Johannes Berg960d01a2014-09-09 22:55:35 +030012017 */
12018 return -EINVAL;
12019 }
12020
12021 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
12022
12023 if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
12024 admitted_time =
12025 nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
12026 if (!admitted_time)
12027 return -EINVAL;
12028 }
12029
12030 wdev_lock(wdev);
12031 switch (wdev->iftype) {
12032 case NL80211_IFTYPE_STATION:
12033 case NL80211_IFTYPE_P2P_CLIENT:
12034 if (wdev->current_bss)
12035 break;
12036 err = -ENOTCONN;
12037 goto out;
12038 default:
12039 err = -EOPNOTSUPP;
12040 goto out;
12041 }
12042
12043 err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
12044
12045 out:
12046 wdev_unlock(wdev);
12047 return err;
12048}
12049
12050static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
12051{
12052 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12053 struct net_device *dev = info->user_ptr[1];
12054 struct wireless_dev *wdev = dev->ieee80211_ptr;
12055 const u8 *peer;
12056 u8 tsid;
12057 int err;
12058
12059 if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
12060 return -EINVAL;
12061
12062 tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
12063 peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
12064
12065 wdev_lock(wdev);
12066 err = rdev_del_tx_ts(rdev, dev, tsid, peer);
12067 wdev_unlock(wdev);
12068
12069 return err;
12070}
12071
Arik Nemtsov1057d352014-11-19 12:54:26 +020012072static int nl80211_tdls_channel_switch(struct sk_buff *skb,
12073 struct genl_info *info)
12074{
12075 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12076 struct net_device *dev = info->user_ptr[1];
12077 struct wireless_dev *wdev = dev->ieee80211_ptr;
12078 struct cfg80211_chan_def chandef = {};
12079 const u8 *addr;
12080 u8 oper_class;
12081 int err;
12082
12083 if (!rdev->ops->tdls_channel_switch ||
12084 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
12085 return -EOPNOTSUPP;
12086
12087 switch (dev->ieee80211_ptr->iftype) {
12088 case NL80211_IFTYPE_STATION:
12089 case NL80211_IFTYPE_P2P_CLIENT:
12090 break;
12091 default:
12092 return -EOPNOTSUPP;
12093 }
12094
12095 if (!info->attrs[NL80211_ATTR_MAC] ||
12096 !info->attrs[NL80211_ATTR_OPER_CLASS])
12097 return -EINVAL;
12098
12099 err = nl80211_parse_chandef(rdev, info, &chandef);
12100 if (err)
12101 return err;
12102
12103 /*
12104 * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012
12105 * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the
12106 * specification is not defined for them.
12107 */
Johannes Berg57fbcce2016-04-12 15:56:15 +020012108 if (chandef.chan->band == NL80211_BAND_2GHZ &&
Arik Nemtsov1057d352014-11-19 12:54:26 +020012109 chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
12110 chandef.width != NL80211_CHAN_WIDTH_20)
12111 return -EINVAL;
12112
12113 /* we will be active on the TDLS link */
Arik Nemtsov923b3522015-07-08 15:41:44 +030012114 if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
12115 wdev->iftype))
Arik Nemtsov1057d352014-11-19 12:54:26 +020012116 return -EINVAL;
12117
12118 /* don't allow switching to DFS channels */
12119 if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype))
12120 return -EINVAL;
12121
12122 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
12123 oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]);
12124
12125 wdev_lock(wdev);
12126 err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef);
12127 wdev_unlock(wdev);
12128
12129 return err;
12130}
12131
12132static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
12133 struct genl_info *info)
12134{
12135 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12136 struct net_device *dev = info->user_ptr[1];
12137 struct wireless_dev *wdev = dev->ieee80211_ptr;
12138 const u8 *addr;
12139
12140 if (!rdev->ops->tdls_channel_switch ||
12141 !rdev->ops->tdls_cancel_channel_switch ||
12142 !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH))
12143 return -EOPNOTSUPP;
12144
12145 switch (dev->ieee80211_ptr->iftype) {
12146 case NL80211_IFTYPE_STATION:
12147 case NL80211_IFTYPE_P2P_CLIENT:
12148 break;
12149 default:
12150 return -EOPNOTSUPP;
12151 }
12152
12153 if (!info->attrs[NL80211_ATTR_MAC])
12154 return -EINVAL;
12155
12156 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
12157
12158 wdev_lock(wdev);
12159 rdev_tdls_cancel_channel_switch(rdev, dev, addr);
12160 wdev_unlock(wdev);
12161
12162 return 0;
12163}
12164
Michael Braunce0ce132016-10-10 19:12:22 +020012165static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
12166 struct genl_info *info)
12167{
12168 struct cfg80211_registered_device *rdev = info->user_ptr[0];
12169 struct net_device *dev = info->user_ptr[1];
12170 struct wireless_dev *wdev = dev->ieee80211_ptr;
12171 const struct nlattr *nla;
12172 bool enabled;
12173
Michael Braunce0ce132016-10-10 19:12:22 +020012174 if (!rdev->ops->set_multicast_to_unicast)
12175 return -EOPNOTSUPP;
12176
12177 if (wdev->iftype != NL80211_IFTYPE_AP &&
12178 wdev->iftype != NL80211_IFTYPE_P2P_GO)
12179 return -EOPNOTSUPP;
12180
12181 nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
12182 enabled = nla_get_flag(nla);
12183
12184 return rdev_set_multicast_to_unicast(rdev, dev, enabled);
12185}
12186
Johannes Berg4c476992010-10-04 21:36:35 +020012187#define NL80211_FLAG_NEED_WIPHY 0x01
12188#define NL80211_FLAG_NEED_NETDEV 0x02
12189#define NL80211_FLAG_NEED_RTNL 0x04
Johannes Berg41265712010-10-04 21:14:05 +020012190#define NL80211_FLAG_CHECK_NETDEV_UP 0x08
12191#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
12192 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg1bf614e2012-06-15 15:23:36 +020012193#define NL80211_FLAG_NEED_WDEV 0x10
Johannes Berg98104fde2012-06-16 00:19:54 +020012194/* If a netdev is associated, it must be UP, P2P must be started */
Johannes Berg1bf614e2012-06-15 15:23:36 +020012195#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
12196 NL80211_FLAG_CHECK_NETDEV_UP)
Johannes Berg5393b912014-09-10 15:00:16 +030012197#define NL80211_FLAG_CLEAR_SKB 0x20
Johannes Berg4c476992010-10-04 21:36:35 +020012198
Johannes Bergf84f7712013-11-14 17:14:45 +010012199static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020012200 struct genl_info *info)
12201{
12202 struct cfg80211_registered_device *rdev;
Johannes Berg89a54e42012-06-15 14:33:17 +020012203 struct wireless_dev *wdev;
Johannes Berg4c476992010-10-04 21:36:35 +020012204 struct net_device *dev;
Johannes Berg4c476992010-10-04 21:36:35 +020012205 bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
12206
12207 if (rtnl)
12208 rtnl_lock();
12209
12210 if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
Johannes Berg4f7eff12012-06-15 14:14:22 +020012211 rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
Johannes Berg4c476992010-10-04 21:36:35 +020012212 if (IS_ERR(rdev)) {
12213 if (rtnl)
12214 rtnl_unlock();
12215 return PTR_ERR(rdev);
12216 }
12217 info->user_ptr[0] = rdev;
Johannes Berg1bf614e2012-06-15 15:23:36 +020012218 } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
12219 ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
Johannes Berg5fe231e2013-05-08 21:45:15 +020012220 ASSERT_RTNL();
12221
Johannes Berg89a54e42012-06-15 14:33:17 +020012222 wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
12223 info->attrs);
12224 if (IS_ERR(wdev)) {
Johannes Berg4c476992010-10-04 21:36:35 +020012225 if (rtnl)
12226 rtnl_unlock();
Johannes Berg89a54e42012-06-15 14:33:17 +020012227 return PTR_ERR(wdev);
Johannes Berg4c476992010-10-04 21:36:35 +020012228 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012229
Johannes Berg89a54e42012-06-15 14:33:17 +020012230 dev = wdev->netdev;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080012231 rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg89a54e42012-06-15 14:33:17 +020012232
Johannes Berg1bf614e2012-06-15 15:23:36 +020012233 if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
12234 if (!dev) {
Johannes Berg1bf614e2012-06-15 15:23:36 +020012235 if (rtnl)
12236 rtnl_unlock();
12237 return -EINVAL;
12238 }
12239
12240 info->user_ptr[1] = dev;
12241 } else {
12242 info->user_ptr[1] = wdev;
Johannes Berg41265712010-10-04 21:14:05 +020012243 }
Johannes Berg89a54e42012-06-15 14:33:17 +020012244
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012245 if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
12246 !wdev_running(wdev)) {
12247 if (rtnl)
12248 rtnl_unlock();
12249 return -ENETDOWN;
Johannes Berg1bf614e2012-06-15 15:23:36 +020012250 }
12251
Arend Van Spriel73c7da32016-10-20 20:08:22 +010012252 if (dev)
12253 dev_hold(dev);
12254
Johannes Berg4c476992010-10-04 21:36:35 +020012255 info->user_ptr[0] = rdev;
Johannes Berg4c476992010-10-04 21:36:35 +020012256 }
12257
12258 return 0;
12259}
12260
Johannes Bergf84f7712013-11-14 17:14:45 +010012261static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
Johannes Berg4c476992010-10-04 21:36:35 +020012262 struct genl_info *info)
12263{
Johannes Berg1bf614e2012-06-15 15:23:36 +020012264 if (info->user_ptr[1]) {
12265 if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
12266 struct wireless_dev *wdev = info->user_ptr[1];
12267
12268 if (wdev->netdev)
12269 dev_put(wdev->netdev);
12270 } else {
12271 dev_put(info->user_ptr[1]);
12272 }
12273 }
Johannes Berg5393b912014-09-10 15:00:16 +030012274
Johannes Berg4c476992010-10-04 21:36:35 +020012275 if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
12276 rtnl_unlock();
Johannes Berg5393b912014-09-10 15:00:16 +030012277
12278 /* If needed, clear the netlink message payload from the SKB
12279 * as it might contain key data that shouldn't stick around on
12280 * the heap after the SKB is freed. The netlink message header
12281 * is still needed for further processing, so leave it intact.
12282 */
12283 if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) {
12284 struct nlmsghdr *nlh = nlmsg_hdr(skb);
12285
12286 memset(nlmsg_data(nlh), 0, nlmsg_len(nlh));
12287 }
Johannes Berg4c476992010-10-04 21:36:35 +020012288}
12289
Johannes Berg4534de82013-11-14 17:14:46 +010012290static const struct genl_ops nl80211_ops[] = {
Johannes Berg55682962007-09-20 13:09:35 -040012291 {
12292 .cmd = NL80211_CMD_GET_WIPHY,
12293 .doit = nl80211_get_wiphy,
12294 .dumpit = nl80211_dump_wiphy,
Johannes Berg86e8cf92013-06-19 10:57:22 +020012295 .done = nl80211_dump_wiphy_done,
Johannes Berg55682962007-09-20 13:09:35 -040012296 .policy = nl80211_policy,
12297 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012298 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12299 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012300 },
12301 {
12302 .cmd = NL80211_CMD_SET_WIPHY,
12303 .doit = nl80211_set_wiphy,
12304 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012305 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012306 .internal_flags = NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012307 },
12308 {
12309 .cmd = NL80211_CMD_GET_INTERFACE,
12310 .doit = nl80211_get_interface,
12311 .dumpit = nl80211_dump_interface,
12312 .policy = nl80211_policy,
12313 /* can be retrieved by unprivileged users */
Johannes Berg5fe231e2013-05-08 21:45:15 +020012314 .internal_flags = NL80211_FLAG_NEED_WDEV |
12315 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012316 },
12317 {
12318 .cmd = NL80211_CMD_SET_INTERFACE,
12319 .doit = nl80211_set_interface,
12320 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012321 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012322 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12323 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012324 },
12325 {
12326 .cmd = NL80211_CMD_NEW_INTERFACE,
12327 .doit = nl80211_new_interface,
12328 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012329 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012330 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12331 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012332 },
12333 {
12334 .cmd = NL80211_CMD_DEL_INTERFACE,
12335 .doit = nl80211_del_interface,
12336 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012337 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg84efbb82012-06-16 00:00:26 +020012338 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012339 NL80211_FLAG_NEED_RTNL,
Johannes Berg55682962007-09-20 13:09:35 -040012340 },
Johannes Berg41ade002007-12-19 02:03:29 +010012341 {
12342 .cmd = NL80211_CMD_GET_KEY,
12343 .doit = nl80211_get_key,
12344 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012345 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012346 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012347 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012348 },
12349 {
12350 .cmd = NL80211_CMD_SET_KEY,
12351 .doit = nl80211_set_key,
12352 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012353 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012354 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012355 NL80211_FLAG_NEED_RTNL |
12356 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012357 },
12358 {
12359 .cmd = NL80211_CMD_NEW_KEY,
12360 .doit = nl80211_new_key,
12361 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012362 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012363 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012364 NL80211_FLAG_NEED_RTNL |
12365 NL80211_FLAG_CLEAR_SKB,
Johannes Berg41ade002007-12-19 02:03:29 +010012366 },
12367 {
12368 .cmd = NL80211_CMD_DEL_KEY,
12369 .doit = nl80211_del_key,
12370 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012371 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012372 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012373 NL80211_FLAG_NEED_RTNL,
Johannes Berg41ade002007-12-19 02:03:29 +010012374 },
Johannes Berged1b6cc2007-12-19 02:03:32 +010012375 {
12376 .cmd = NL80211_CMD_SET_BEACON,
12377 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012378 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012379 .doit = nl80211_set_beacon,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012380 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012381 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012382 },
12383 {
Johannes Berg88600202012-02-13 15:17:18 +010012384 .cmd = NL80211_CMD_START_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012385 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012386 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012387 .doit = nl80211_start_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012388 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012389 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012390 },
12391 {
Johannes Berg88600202012-02-13 15:17:18 +010012392 .cmd = NL80211_CMD_STOP_AP,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012393 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012394 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg88600202012-02-13 15:17:18 +010012395 .doit = nl80211_stop_ap,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012396 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012397 NL80211_FLAG_NEED_RTNL,
Johannes Berged1b6cc2007-12-19 02:03:32 +010012398 },
Johannes Berg5727ef12007-12-19 02:03:34 +010012399 {
12400 .cmd = NL80211_CMD_GET_STATION,
12401 .doit = nl80211_get_station,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012402 .dumpit = nl80211_dump_station,
Johannes Berg5727ef12007-12-19 02:03:34 +010012403 .policy = nl80211_policy,
Johannes Berg4c476992010-10-04 21:36:35 +020012404 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12405 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012406 },
12407 {
12408 .cmd = NL80211_CMD_SET_STATION,
12409 .doit = nl80211_set_station,
12410 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012411 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012412 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012413 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012414 },
12415 {
12416 .cmd = NL80211_CMD_NEW_STATION,
12417 .doit = nl80211_new_station,
12418 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012419 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012420 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012421 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012422 },
12423 {
12424 .cmd = NL80211_CMD_DEL_STATION,
12425 .doit = nl80211_del_station,
12426 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012427 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012428 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012429 NL80211_FLAG_NEED_RTNL,
Johannes Berg5727ef12007-12-19 02:03:34 +010012430 },
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012431 {
12432 .cmd = NL80211_CMD_GET_MPATH,
12433 .doit = nl80211_get_mpath,
12434 .dumpit = nl80211_dump_mpath,
12435 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012436 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012437 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012438 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012439 },
12440 {
Henning Rogge66be7d22014-09-12 08:58:49 +020012441 .cmd = NL80211_CMD_GET_MPP,
12442 .doit = nl80211_get_mpp,
12443 .dumpit = nl80211_dump_mpp,
12444 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012445 .flags = GENL_UNS_ADMIN_PERM,
Henning Rogge66be7d22014-09-12 08:58:49 +020012446 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12447 NL80211_FLAG_NEED_RTNL,
12448 },
12449 {
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012450 .cmd = NL80211_CMD_SET_MPATH,
12451 .doit = nl80211_set_mpath,
12452 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012453 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012454 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012455 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012456 },
12457 {
12458 .cmd = NL80211_CMD_NEW_MPATH,
12459 .doit = nl80211_new_mpath,
12460 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012461 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012462 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012463 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012464 },
12465 {
12466 .cmd = NL80211_CMD_DEL_MPATH,
12467 .doit = nl80211_del_mpath,
12468 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012469 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012470 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012471 NL80211_FLAG_NEED_RTNL,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010012472 },
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012473 {
12474 .cmd = NL80211_CMD_SET_BSS,
12475 .doit = nl80211_set_bss,
12476 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012477 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012478 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012479 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9f1ba902008-08-07 20:07:01 +030012480 },
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012481 {
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012482 .cmd = NL80211_CMD_GET_REG,
Arik Nemtsovad30ca22014-12-15 19:25:59 +020012483 .doit = nl80211_get_reg_do,
12484 .dumpit = nl80211_get_reg_dump,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012485 .policy = nl80211_policy,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012486 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012487 /* can be retrieved by unprivileged users */
12488 },
Johannes Bergb6863032015-10-15 09:25:18 +020012489#ifdef CONFIG_CFG80211_CRDA_SUPPORT
Luis R. Rodriguezf1303472009-01-30 09:26:42 -080012490 {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012491 .cmd = NL80211_CMD_SET_REG,
12492 .doit = nl80211_set_reg,
12493 .policy = nl80211_policy,
12494 .flags = GENL_ADMIN_PERM,
Johannes Berg5fe231e2013-05-08 21:45:15 +020012495 .internal_flags = NL80211_FLAG_NEED_RTNL,
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012496 },
Johannes Bergb6863032015-10-15 09:25:18 +020012497#endif
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070012498 {
12499 .cmd = NL80211_CMD_REQ_SET_REG,
12500 .doit = nl80211_req_set_reg,
12501 .policy = nl80211_policy,
12502 .flags = GENL_ADMIN_PERM,
12503 },
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012504 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012505 .cmd = NL80211_CMD_GET_MESH_CONFIG,
12506 .doit = nl80211_get_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012507 .policy = nl80211_policy,
12508 /* can be retrieved by unprivileged users */
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012509 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012510 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012511 },
12512 {
Javier Cardona24bdd9f2010-12-16 17:37:48 -080012513 .cmd = NL80211_CMD_SET_MESH_CONFIG,
12514 .doit = nl80211_update_mesh_config,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012515 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012516 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012517 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012518 NL80211_FLAG_NEED_RTNL,
colin@cozybit.com93da9cc2008-10-21 12:03:48 -070012519 },
Jouni Malinen9aed3cc2009-01-13 16:03:29 +020012520 {
Johannes Berg2a519312009-02-10 21:25:55 +010012521 .cmd = NL80211_CMD_TRIGGER_SCAN,
12522 .doit = nl80211_trigger_scan,
12523 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012524 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergfd014282012-06-18 19:17:03 +020012525 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012526 NL80211_FLAG_NEED_RTNL,
Johannes Berg2a519312009-02-10 21:25:55 +010012527 },
12528 {
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053012529 .cmd = NL80211_CMD_ABORT_SCAN,
12530 .doit = nl80211_abort_scan,
12531 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012532 .flags = GENL_UNS_ADMIN_PERM,
Vidyullatha Kanchanapally91d3ab42015-10-30 19:14:49 +053012533 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12534 NL80211_FLAG_NEED_RTNL,
12535 },
12536 {
Johannes Berg2a519312009-02-10 21:25:55 +010012537 .cmd = NL80211_CMD_GET_SCAN,
12538 .policy = nl80211_policy,
12539 .dumpit = nl80211_dump_scan,
12540 },
Jouni Malinen636a5d32009-03-19 13:39:22 +020012541 {
Luciano Coelho807f8a82011-05-11 17:09:35 +030012542 .cmd = NL80211_CMD_START_SCHED_SCAN,
12543 .doit = nl80211_start_sched_scan,
12544 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012545 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012546 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12547 NL80211_FLAG_NEED_RTNL,
12548 },
12549 {
12550 .cmd = NL80211_CMD_STOP_SCHED_SCAN,
12551 .doit = nl80211_stop_sched_scan,
12552 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012553 .flags = GENL_UNS_ADMIN_PERM,
Luciano Coelho807f8a82011-05-11 17:09:35 +030012554 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12555 NL80211_FLAG_NEED_RTNL,
12556 },
12557 {
Jouni Malinen636a5d32009-03-19 13:39:22 +020012558 .cmd = NL80211_CMD_AUTHENTICATE,
12559 .doit = nl80211_authenticate,
12560 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012561 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012562 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012563 NL80211_FLAG_NEED_RTNL |
12564 NL80211_FLAG_CLEAR_SKB,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012565 },
12566 {
12567 .cmd = NL80211_CMD_ASSOCIATE,
12568 .doit = nl80211_associate,
12569 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012570 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012571 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012572 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012573 },
12574 {
12575 .cmd = NL80211_CMD_DEAUTHENTICATE,
12576 .doit = nl80211_deauthenticate,
12577 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012578 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012579 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012580 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012581 },
12582 {
12583 .cmd = NL80211_CMD_DISASSOCIATE,
12584 .doit = nl80211_disassociate,
12585 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012586 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012587 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012588 NL80211_FLAG_NEED_RTNL,
Jouni Malinen636a5d32009-03-19 13:39:22 +020012589 },
Johannes Berg04a773a2009-04-19 21:24:32 +020012590 {
12591 .cmd = NL80211_CMD_JOIN_IBSS,
12592 .doit = nl80211_join_ibss,
12593 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012594 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012595 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012596 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020012597 },
12598 {
12599 .cmd = NL80211_CMD_LEAVE_IBSS,
12600 .doit = nl80211_leave_ibss,
12601 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012602 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012603 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012604 NL80211_FLAG_NEED_RTNL,
Johannes Berg04a773a2009-04-19 21:24:32 +020012605 },
Johannes Bergaff89a92009-07-01 21:26:51 +020012606#ifdef CONFIG_NL80211_TESTMODE
12607 {
12608 .cmd = NL80211_CMD_TESTMODE,
12609 .doit = nl80211_testmode_do,
Wey-Yi Guy71063f02011-05-20 09:05:54 -070012610 .dumpit = nl80211_testmode_dump,
Johannes Bergaff89a92009-07-01 21:26:51 +020012611 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012612 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012613 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12614 NL80211_FLAG_NEED_RTNL,
Johannes Bergaff89a92009-07-01 21:26:51 +020012615 },
12616#endif
Samuel Ortizb23aa672009-07-01 21:26:54 +020012617 {
12618 .cmd = NL80211_CMD_CONNECT,
12619 .doit = nl80211_connect,
12620 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012621 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012622 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012623 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020012624 },
12625 {
vamsi krishna088e8df2016-10-27 16:51:11 +030012626 .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
12627 .doit = nl80211_update_connect_params,
12628 .policy = nl80211_policy,
12629 .flags = GENL_ADMIN_PERM,
12630 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12631 NL80211_FLAG_NEED_RTNL,
12632 },
12633 {
Samuel Ortizb23aa672009-07-01 21:26:54 +020012634 .cmd = NL80211_CMD_DISCONNECT,
12635 .doit = nl80211_disconnect,
12636 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012637 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg41265712010-10-04 21:14:05 +020012638 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012639 NL80211_FLAG_NEED_RTNL,
Samuel Ortizb23aa672009-07-01 21:26:54 +020012640 },
Johannes Berg463d0182009-07-14 00:33:35 +020012641 {
12642 .cmd = NL80211_CMD_SET_WIPHY_NETNS,
12643 .doit = nl80211_wiphy_netns,
12644 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012645 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012646 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12647 NL80211_FLAG_NEED_RTNL,
Johannes Berg463d0182009-07-14 00:33:35 +020012648 },
Holger Schurig61fa7132009-11-11 12:25:40 +010012649 {
12650 .cmd = NL80211_CMD_GET_SURVEY,
12651 .policy = nl80211_policy,
12652 .dumpit = nl80211_dump_survey,
12653 },
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012654 {
12655 .cmd = NL80211_CMD_SET_PMKSA,
12656 .doit = nl80211_setdel_pmksa,
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,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012661 },
12662 {
12663 .cmd = NL80211_CMD_DEL_PMKSA,
12664 .doit = nl80211_setdel_pmksa,
12665 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012666 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012667 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012668 NL80211_FLAG_NEED_RTNL,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012669 },
12670 {
12671 .cmd = NL80211_CMD_FLUSH_PMKSA,
12672 .doit = nl80211_flush_pmksa,
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,
Samuel Ortiz67fbb162009-11-24 23:59:15 +010012677 },
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012678 {
12679 .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
12680 .doit = nl80211_remain_on_channel,
12681 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012682 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012683 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012684 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012685 },
12686 {
12687 .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
12688 .doit = nl80211_cancel_remain_on_channel,
12689 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012690 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012691 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012692 NL80211_FLAG_NEED_RTNL,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010012693 },
Jouni Malinen13ae75b2009-12-29 12:59:45 +020012694 {
12695 .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
12696 .doit = nl80211_set_tx_bitrate_mask,
12697 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012698 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012699 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12700 NL80211_FLAG_NEED_RTNL,
Jouni Malinen13ae75b2009-12-29 12:59:45 +020012701 },
Jouni Malinen026331c2010-02-15 12:53:10 +020012702 {
Johannes Berg2e161f72010-08-12 15:38:38 +020012703 .cmd = NL80211_CMD_REGISTER_FRAME,
12704 .doit = nl80211_register_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020012705 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012706 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012707 .internal_flags = NL80211_FLAG_NEED_WDEV |
Johannes Berg4c476992010-10-04 21:36:35 +020012708 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020012709 },
12710 {
Johannes Berg2e161f72010-08-12 15:38:38 +020012711 .cmd = NL80211_CMD_FRAME,
12712 .doit = nl80211_tx_mgmt,
Jouni Malinen026331c2010-02-15 12:53:10 +020012713 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012714 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012715 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Berg4c476992010-10-04 21:36:35 +020012716 NL80211_FLAG_NEED_RTNL,
Jouni Malinen026331c2010-02-15 12:53:10 +020012717 },
Kalle Valoffb9eb32010-02-17 17:58:10 +020012718 {
Johannes Bergf7ca38d2010-11-25 10:02:29 +010012719 .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
12720 .doit = nl80211_tx_mgmt_cancel_wait,
12721 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012722 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg71bbc992012-06-15 15:30:18 +020012723 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
Johannes Bergf7ca38d2010-11-25 10:02:29 +010012724 NL80211_FLAG_NEED_RTNL,
12725 },
12726 {
Kalle Valoffb9eb32010-02-17 17:58:10 +020012727 .cmd = NL80211_CMD_SET_POWER_SAVE,
12728 .doit = nl80211_set_power_save,
12729 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012730 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012731 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12732 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020012733 },
12734 {
12735 .cmd = NL80211_CMD_GET_POWER_SAVE,
12736 .doit = nl80211_get_power_save,
12737 .policy = nl80211_policy,
12738 /* can be retrieved by unprivileged users */
Johannes Berg4c476992010-10-04 21:36:35 +020012739 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12740 NL80211_FLAG_NEED_RTNL,
Kalle Valoffb9eb32010-02-17 17:58:10 +020012741 },
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012742 {
12743 .cmd = NL80211_CMD_SET_CQM,
12744 .doit = nl80211_set_cqm,
12745 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012746 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012747 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12748 NL80211_FLAG_NEED_RTNL,
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020012749 },
Johannes Bergf444de02010-05-05 15:25:02 +020012750 {
12751 .cmd = NL80211_CMD_SET_CHANNEL,
12752 .doit = nl80211_set_channel,
12753 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012754 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg4c476992010-10-04 21:36:35 +020012755 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12756 NL80211_FLAG_NEED_RTNL,
Johannes Bergf444de02010-05-05 15:25:02 +020012757 },
Bill Jordane8347eb2010-10-01 13:54:28 -040012758 {
12759 .cmd = NL80211_CMD_SET_WDS_PEER,
12760 .doit = nl80211_set_wds_peer,
12761 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012762 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg43b19952010-10-07 13:10:30 +020012763 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12764 NL80211_FLAG_NEED_RTNL,
Bill Jordane8347eb2010-10-01 13:54:28 -040012765 },
Johannes Berg29cbe682010-12-03 09:20:44 +010012766 {
12767 .cmd = NL80211_CMD_JOIN_MESH,
12768 .doit = nl80211_join_mesh,
12769 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012770 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012771 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12772 NL80211_FLAG_NEED_RTNL,
12773 },
12774 {
12775 .cmd = NL80211_CMD_LEAVE_MESH,
12776 .doit = nl80211_leave_mesh,
12777 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012778 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg29cbe682010-12-03 09:20:44 +010012779 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12780 NL80211_FLAG_NEED_RTNL,
12781 },
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012782 {
12783 .cmd = NL80211_CMD_JOIN_OCB,
12784 .doit = nl80211_join_ocb,
12785 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012786 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012787 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12788 NL80211_FLAG_NEED_RTNL,
12789 },
12790 {
12791 .cmd = NL80211_CMD_LEAVE_OCB,
12792 .doit = nl80211_leave_ocb,
12793 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012794 .flags = GENL_UNS_ADMIN_PERM,
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +010012795 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12796 NL80211_FLAG_NEED_RTNL,
12797 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020012798#ifdef CONFIG_PM
Johannes Bergff1b6e62011-05-04 15:37:28 +020012799 {
12800 .cmd = NL80211_CMD_GET_WOWLAN,
12801 .doit = nl80211_get_wowlan,
12802 .policy = nl80211_policy,
12803 /* can be retrieved by unprivileged users */
12804 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12805 NL80211_FLAG_NEED_RTNL,
12806 },
12807 {
12808 .cmd = NL80211_CMD_SET_WOWLAN,
12809 .doit = nl80211_set_wowlan,
12810 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012811 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergff1b6e62011-05-04 15:37:28 +020012812 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12813 NL80211_FLAG_NEED_RTNL,
12814 },
Johannes Bergdfb89c52012-06-27 09:23:48 +020012815#endif
Johannes Berge5497d72011-07-05 16:35:40 +020012816 {
12817 .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
12818 .doit = nl80211_set_rekey_data,
12819 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012820 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berge5497d72011-07-05 16:35:40 +020012821 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg5393b912014-09-10 15:00:16 +030012822 NL80211_FLAG_NEED_RTNL |
12823 NL80211_FLAG_CLEAR_SKB,
Johannes Berge5497d72011-07-05 16:35:40 +020012824 },
Arik Nemtsov109086c2011-09-28 14:12:50 +030012825 {
12826 .cmd = NL80211_CMD_TDLS_MGMT,
12827 .doit = nl80211_tdls_mgmt,
12828 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012829 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030012830 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12831 NL80211_FLAG_NEED_RTNL,
12832 },
12833 {
12834 .cmd = NL80211_CMD_TDLS_OPER,
12835 .doit = nl80211_tdls_oper,
12836 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012837 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov109086c2011-09-28 14:12:50 +030012838 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12839 NL80211_FLAG_NEED_RTNL,
12840 },
Johannes Berg28946da2011-11-04 11:18:12 +010012841 {
12842 .cmd = NL80211_CMD_UNEXPECTED_FRAME,
12843 .doit = nl80211_register_unexpected_frame,
12844 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012845 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg28946da2011-11-04 11:18:12 +010012846 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12847 NL80211_FLAG_NEED_RTNL,
12848 },
Johannes Berg7f6cf312011-11-04 11:18:15 +010012849 {
12850 .cmd = NL80211_CMD_PROBE_CLIENT,
12851 .doit = nl80211_probe_client,
12852 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012853 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg2b5f8b02012-04-02 10:51:55 +020012854 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
Johannes Berg7f6cf312011-11-04 11:18:15 +010012855 NL80211_FLAG_NEED_RTNL,
12856 },
Johannes Berg5e760232011-11-04 11:18:17 +010012857 {
12858 .cmd = NL80211_CMD_REGISTER_BEACONS,
12859 .doit = nl80211_register_beacons,
12860 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012861 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg5e760232011-11-04 11:18:17 +010012862 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12863 NL80211_FLAG_NEED_RTNL,
12864 },
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010012865 {
12866 .cmd = NL80211_CMD_SET_NOACK_MAP,
12867 .doit = nl80211_set_noack_map,
12868 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012869 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich1d9d9212011-11-18 14:20:43 +010012870 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12871 NL80211_FLAG_NEED_RTNL,
12872 },
Johannes Berg98104fde2012-06-16 00:19:54 +020012873 {
12874 .cmd = NL80211_CMD_START_P2P_DEVICE,
12875 .doit = nl80211_start_p2p_device,
12876 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012877 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020012878 .internal_flags = NL80211_FLAG_NEED_WDEV |
12879 NL80211_FLAG_NEED_RTNL,
12880 },
12881 {
12882 .cmd = NL80211_CMD_STOP_P2P_DEVICE,
12883 .doit = nl80211_stop_p2p_device,
12884 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012885 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg98104fde2012-06-16 00:19:54 +020012886 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12887 NL80211_FLAG_NEED_RTNL,
12888 },
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012889 {
Ayala Bekercb3b7d82016-09-20 17:31:13 +030012890 .cmd = NL80211_CMD_START_NAN,
12891 .doit = nl80211_start_nan,
12892 .policy = nl80211_policy,
12893 .flags = GENL_ADMIN_PERM,
12894 .internal_flags = NL80211_FLAG_NEED_WDEV |
12895 NL80211_FLAG_NEED_RTNL,
12896 },
12897 {
12898 .cmd = NL80211_CMD_STOP_NAN,
12899 .doit = nl80211_stop_nan,
12900 .policy = nl80211_policy,
12901 .flags = GENL_ADMIN_PERM,
12902 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12903 NL80211_FLAG_NEED_RTNL,
12904 },
12905 {
Ayala Bekera442b762016-09-20 17:31:15 +030012906 .cmd = NL80211_CMD_ADD_NAN_FUNCTION,
12907 .doit = nl80211_nan_add_func,
12908 .policy = nl80211_policy,
12909 .flags = GENL_ADMIN_PERM,
12910 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12911 NL80211_FLAG_NEED_RTNL,
12912 },
12913 {
12914 .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
12915 .doit = nl80211_nan_del_func,
12916 .policy = nl80211_policy,
12917 .flags = GENL_ADMIN_PERM,
12918 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12919 NL80211_FLAG_NEED_RTNL,
12920 },
12921 {
Ayala Bekera5a9dcf2016-09-20 17:31:16 +030012922 .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
12923 .doit = nl80211_nan_change_config,
12924 .policy = nl80211_policy,
12925 .flags = GENL_ADMIN_PERM,
12926 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12927 NL80211_FLAG_NEED_RTNL,
12928 },
12929 {
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012930 .cmd = NL80211_CMD_SET_MCAST_RATE,
12931 .doit = nl80211_set_mcast_rate,
12932 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012933 .flags = GENL_UNS_ADMIN_PERM,
Antonio Quartullif4e583c2012-11-02 13:27:48 +010012934 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12935 NL80211_FLAG_NEED_RTNL,
12936 },
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053012937 {
12938 .cmd = NL80211_CMD_SET_MAC_ACL,
12939 .doit = nl80211_set_mac_acl,
12940 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012941 .flags = GENL_UNS_ADMIN_PERM,
Vasanthakumar Thiagarajan77765ea2013-01-18 11:18:45 +053012942 .internal_flags = NL80211_FLAG_NEED_NETDEV |
12943 NL80211_FLAG_NEED_RTNL,
12944 },
Simon Wunderlich04f39042013-02-08 18:16:19 +010012945 {
12946 .cmd = NL80211_CMD_RADAR_DETECT,
12947 .doit = nl80211_start_radar_detection,
12948 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012949 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich04f39042013-02-08 18:16:19 +010012950 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12951 NL80211_FLAG_NEED_RTNL,
12952 },
Johannes Berg3713b4e2013-02-14 16:19:38 +010012953 {
12954 .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
12955 .doit = nl80211_get_protocol_features,
12956 .policy = nl80211_policy,
12957 },
Jouni Malinen355199e2013-02-27 17:14:27 +020012958 {
12959 .cmd = NL80211_CMD_UPDATE_FT_IES,
12960 .doit = nl80211_update_ft_ies,
12961 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012962 .flags = GENL_UNS_ADMIN_PERM,
Jouni Malinen355199e2013-02-27 17:14:27 +020012963 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
12964 NL80211_FLAG_NEED_RTNL,
12965 },
Arend van Spriel5de17982013-04-18 15:49:00 +020012966 {
12967 .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
12968 .doit = nl80211_crit_protocol_start,
12969 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012970 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020012971 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12972 NL80211_FLAG_NEED_RTNL,
12973 },
12974 {
12975 .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
12976 .doit = nl80211_crit_protocol_stop,
12977 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012978 .flags = GENL_UNS_ADMIN_PERM,
Arend van Spriel5de17982013-04-18 15:49:00 +020012979 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
12980 NL80211_FLAG_NEED_RTNL,
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070012981 },
12982 {
12983 .cmd = NL80211_CMD_GET_COALESCE,
12984 .doit = nl80211_get_coalesce,
12985 .policy = nl80211_policy,
12986 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12987 NL80211_FLAG_NEED_RTNL,
12988 },
12989 {
12990 .cmd = NL80211_CMD_SET_COALESCE,
12991 .doit = nl80211_set_coalesce,
12992 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020012993 .flags = GENL_UNS_ADMIN_PERM,
Amitkumar Karwarbe29b992013-06-28 11:51:26 -070012994 .internal_flags = NL80211_FLAG_NEED_WIPHY |
12995 NL80211_FLAG_NEED_RTNL,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020012996 },
12997 {
12998 .cmd = NL80211_CMD_CHANNEL_SWITCH,
12999 .doit = nl80211_channel_switch,
13000 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013001 .flags = GENL_UNS_ADMIN_PERM,
Simon Wunderlich16ef1fe2013-07-11 16:09:05 +020013002 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13003 NL80211_FLAG_NEED_RTNL,
13004 },
Johannes Bergad7e7182013-11-13 13:37:47 +010013005 {
13006 .cmd = NL80211_CMD_VENDOR,
13007 .doit = nl80211_vendor_cmd,
Johannes Berg7bdbe402015-08-15 22:39:49 +030013008 .dumpit = nl80211_vendor_cmd_dump,
Johannes Bergad7e7182013-11-13 13:37:47 +010013009 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013010 .flags = GENL_UNS_ADMIN_PERM,
Johannes Bergad7e7182013-11-13 13:37:47 +010013011 .internal_flags = NL80211_FLAG_NEED_WIPHY |
13012 NL80211_FLAG_NEED_RTNL,
13013 },
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080013014 {
13015 .cmd = NL80211_CMD_SET_QOS_MAP,
13016 .doit = nl80211_set_qos_map,
13017 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013018 .flags = GENL_UNS_ADMIN_PERM,
Kyeyoon Parkfa9ffc72013-12-16 23:01:30 -080013019 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13020 NL80211_FLAG_NEED_RTNL,
13021 },
Johannes Berg960d01a2014-09-09 22:55:35 +030013022 {
13023 .cmd = NL80211_CMD_ADD_TX_TS,
13024 .doit = nl80211_add_tx_ts,
13025 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013026 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030013027 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13028 NL80211_FLAG_NEED_RTNL,
13029 },
13030 {
13031 .cmd = NL80211_CMD_DEL_TX_TS,
13032 .doit = nl80211_del_tx_ts,
13033 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013034 .flags = GENL_UNS_ADMIN_PERM,
Johannes Berg960d01a2014-09-09 22:55:35 +030013035 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13036 NL80211_FLAG_NEED_RTNL,
13037 },
Arik Nemtsov1057d352014-11-19 12:54:26 +020013038 {
13039 .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
13040 .doit = nl80211_tdls_channel_switch,
13041 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013042 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020013043 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13044 NL80211_FLAG_NEED_RTNL,
13045 },
13046 {
13047 .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
13048 .doit = nl80211_tdls_cancel_channel_switch,
13049 .policy = nl80211_policy,
Martin Willi5617c6c2016-05-09 18:33:58 +020013050 .flags = GENL_UNS_ADMIN_PERM,
Arik Nemtsov1057d352014-11-19 12:54:26 +020013051 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
13052 NL80211_FLAG_NEED_RTNL,
13053 },
Michael Braunce0ce132016-10-10 19:12:22 +020013054 {
13055 .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
13056 .doit = nl80211_set_multicast_to_unicast,
13057 .policy = nl80211_policy,
13058 .flags = GENL_UNS_ADMIN_PERM,
13059 .internal_flags = NL80211_FLAG_NEED_NETDEV |
13060 NL80211_FLAG_NEED_RTNL,
13061 },
Johannes Berg55682962007-09-20 13:09:35 -040013062};
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013063
Johannes Berg56989f62016-10-24 14:40:05 +020013064static struct genl_family nl80211_fam __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +020013065 .name = NL80211_GENL_NAME, /* have users key off the name instead */
13066 .hdrsize = 0, /* no private header */
13067 .version = 1, /* no particular meaning now */
13068 .maxattr = NL80211_ATTR_MAX,
13069 .netnsok = true,
13070 .pre_doit = nl80211_pre_doit,
13071 .post_doit = nl80211_post_doit,
13072 .module = THIS_MODULE,
13073 .ops = nl80211_ops,
13074 .n_ops = ARRAY_SIZE(nl80211_ops),
13075 .mcgrps = nl80211_mcgrps,
13076 .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
13077};
13078
Johannes Berg55682962007-09-20 13:09:35 -040013079/* notification functions */
13080
Johannes Berg3bb20552014-05-26 13:52:25 +020013081void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
13082 enum nl80211_commands cmd)
Johannes Berg55682962007-09-20 13:09:35 -040013083{
13084 struct sk_buff *msg;
Johannes Berg86e8cf92013-06-19 10:57:22 +020013085 struct nl80211_dump_wiphy_state state = {};
Johannes Berg55682962007-09-20 13:09:35 -040013086
Johannes Berg3bb20552014-05-26 13:52:25 +020013087 WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
13088 cmd != NL80211_CMD_DEL_WIPHY);
13089
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013090 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040013091 if (!msg)
13092 return;
13093
Johannes Berg3bb20552014-05-26 13:52:25 +020013094 if (nl80211_send_wiphy(rdev, cmd, msg, 0, 0, 0, &state) < 0) {
Johannes Berg55682962007-09-20 13:09:35 -040013095 nlmsg_free(msg);
13096 return;
13097 }
13098
Johannes Berg68eb5502013-11-19 15:19:38 +010013099 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013100 NL80211_MCGRP_CONFIG, GFP_KERNEL);
Johannes Berg55682962007-09-20 13:09:35 -040013101}
13102
Denis Kenzior896ff062016-08-03 16:58:33 -050013103void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
13104 struct wireless_dev *wdev,
13105 enum nl80211_commands cmd)
13106{
13107 struct sk_buff *msg;
13108
13109 WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
13110 cmd != NL80211_CMD_DEL_INTERFACE);
13111
13112 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13113 if (!msg)
13114 return;
13115
13116 if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
13117 cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
13118 nlmsg_free(msg);
13119 return;
13120 }
13121
13122 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
13123 NL80211_MCGRP_CONFIG, GFP_KERNEL);
13124}
13125
Johannes Berg362a4152009-05-24 16:43:15 +020013126static int nl80211_add_scan_req(struct sk_buff *msg,
13127 struct cfg80211_registered_device *rdev)
13128{
13129 struct cfg80211_scan_request *req = rdev->scan_req;
13130 struct nlattr *nest;
13131 int i;
13132
13133 if (WARN_ON(!req))
13134 return 0;
13135
13136 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
13137 if (!nest)
13138 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040013139 for (i = 0; i < req->n_ssids; i++) {
13140 if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
13141 goto nla_put_failure;
13142 }
Johannes Berg362a4152009-05-24 16:43:15 +020013143 nla_nest_end(msg, nest);
13144
13145 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
13146 if (!nest)
13147 goto nla_put_failure;
David S. Miller9360ffd2012-03-29 04:41:26 -040013148 for (i = 0; i < req->n_channels; i++) {
13149 if (nla_put_u32(msg, i, req->channels[i]->center_freq))
13150 goto nla_put_failure;
13151 }
Johannes Berg362a4152009-05-24 16:43:15 +020013152 nla_nest_end(msg, nest);
13153
David S. Miller9360ffd2012-03-29 04:41:26 -040013154 if (req->ie &&
13155 nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
13156 goto nla_put_failure;
Johannes Berg362a4152009-05-24 16:43:15 +020013157
Johannes Bergae917c92013-10-25 11:05:22 +020013158 if (req->flags &&
13159 nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
13160 goto nla_put_failure;
Sam Lefflered4737712012-10-11 21:03:31 -070013161
Avraham Stern1d762502016-07-05 17:10:13 +030013162 if (req->info.scan_start_tsf &&
13163 (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
13164 req->info.scan_start_tsf, NL80211_BSS_PAD) ||
13165 nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
13166 req->info.tsf_bssid)))
13167 goto nla_put_failure;
13168
Johannes Berg362a4152009-05-24 16:43:15 +020013169 return 0;
13170 nla_put_failure:
13171 return -ENOBUFS;
13172}
13173
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013174static int nl80211_prep_scan_msg(struct sk_buff *msg,
Johannes Berga538e2d2009-06-16 19:56:42 +020013175 struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020013176 struct wireless_dev *wdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000013177 u32 portid, u32 seq, int flags,
Johannes Berga538e2d2009-06-16 19:56:42 +020013178 u32 cmd)
Johannes Berg2a519312009-02-10 21:25:55 +010013179{
13180 void *hdr;
13181
Eric W. Biederman15e47302012-09-07 20:12:54 +000013182 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Johannes Berg2a519312009-02-10 21:25:55 +010013183 if (!hdr)
13184 return -1;
13185
David S. Miller9360ffd2012-03-29 04:41:26 -040013186 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Bergfd014282012-06-18 19:17:03 +020013187 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13188 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013189 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13190 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013191 goto nla_put_failure;
Johannes Berg2a519312009-02-10 21:25:55 +010013192
Johannes Berg362a4152009-05-24 16:43:15 +020013193 /* ignore errors and send incomplete event anyway */
13194 nl80211_add_scan_req(msg, rdev);
Johannes Berg2a519312009-02-10 21:25:55 +010013195
Johannes Berg053c0952015-01-16 22:09:00 +010013196 genlmsg_end(msg, hdr);
13197 return 0;
Johannes Berg2a519312009-02-10 21:25:55 +010013198
13199 nla_put_failure:
13200 genlmsg_cancel(msg, hdr);
13201 return -EMSGSIZE;
13202}
13203
Luciano Coelho807f8a82011-05-11 17:09:35 +030013204static int
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013205nl80211_prep_sched_scan_msg(struct sk_buff *msg,
Luciano Coelho807f8a82011-05-11 17:09:35 +030013206 struct cfg80211_registered_device *rdev,
13207 struct net_device *netdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000013208 u32 portid, u32 seq, int flags, u32 cmd)
Luciano Coelho807f8a82011-05-11 17:09:35 +030013209{
13210 void *hdr;
13211
Eric W. Biederman15e47302012-09-07 20:12:54 +000013212 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013213 if (!hdr)
13214 return -1;
13215
David S. Miller9360ffd2012-03-29 04:41:26 -040013216 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13217 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
13218 goto nla_put_failure;
Luciano Coelho807f8a82011-05-11 17:09:35 +030013219
Johannes Berg053c0952015-01-16 22:09:00 +010013220 genlmsg_end(msg, hdr);
13221 return 0;
Luciano Coelho807f8a82011-05-11 17:09:35 +030013222
13223 nla_put_failure:
13224 genlmsg_cancel(msg, hdr);
13225 return -EMSGSIZE;
13226}
13227
Johannes Berga538e2d2009-06-16 19:56:42 +020013228void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
Johannes Bergfd014282012-06-18 19:17:03 +020013229 struct wireless_dev *wdev)
Johannes Berga538e2d2009-06-16 19:56:42 +020013230{
13231 struct sk_buff *msg;
13232
Thomas Graf58050fc2012-06-28 03:57:45 +000013233 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013234 if (!msg)
13235 return;
13236
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013237 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Berga538e2d2009-06-16 19:56:42 +020013238 NL80211_CMD_TRIGGER_SCAN) < 0) {
13239 nlmsg_free(msg);
13240 return;
13241 }
13242
Johannes Berg68eb5502013-11-19 15:19:38 +010013243 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013244 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berga538e2d2009-06-16 19:56:42 +020013245}
13246
Johannes Bergf9d15d12014-01-22 11:14:19 +020013247struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
13248 struct wireless_dev *wdev, bool aborted)
Johannes Berg2a519312009-02-10 21:25:55 +010013249{
13250 struct sk_buff *msg;
13251
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013252 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013253 if (!msg)
Johannes Bergf9d15d12014-01-22 11:14:19 +020013254 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013255
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013256 if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
Johannes Bergf9d15d12014-01-22 11:14:19 +020013257 aborted ? NL80211_CMD_SCAN_ABORTED :
13258 NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
Johannes Berg2a519312009-02-10 21:25:55 +010013259 nlmsg_free(msg);
Johannes Bergf9d15d12014-01-22 11:14:19 +020013260 return NULL;
Johannes Berg2a519312009-02-10 21:25:55 +010013261 }
13262
Johannes Bergf9d15d12014-01-22 11:14:19 +020013263 return msg;
Johannes Berg2a519312009-02-10 21:25:55 +010013264}
13265
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013266/* send message created by nl80211_build_scan_msg() */
13267void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
13268 struct sk_buff *msg)
Johannes Berg2a519312009-02-10 21:25:55 +010013269{
Johannes Berg2a519312009-02-10 21:25:55 +010013270 if (!msg)
13271 return;
13272
Johannes Berg68eb5502013-11-19 15:19:38 +010013273 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013274 NL80211_MCGRP_SCAN, GFP_KERNEL);
Johannes Berg2a519312009-02-10 21:25:55 +010013275}
13276
Luciano Coelho807f8a82011-05-11 17:09:35 +030013277void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
13278 struct net_device *netdev, u32 cmd)
13279{
13280 struct sk_buff *msg;
13281
Thomas Graf58050fc2012-06-28 03:57:45 +000013282 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013283 if (!msg)
13284 return;
13285
Arend Van Spriel505a2e82016-12-16 11:21:54 +000013286 if (nl80211_prep_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
Luciano Coelho807f8a82011-05-11 17:09:35 +030013287 nlmsg_free(msg);
13288 return;
13289 }
13290
Johannes Berg68eb5502013-11-19 15:19:38 +010013291 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013292 NL80211_MCGRP_SCAN, GFP_KERNEL);
Luciano Coelho807f8a82011-05-11 17:09:35 +030013293}
13294
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013295static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
13296 struct regulatory_request *request)
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013297{
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013298 /* Userspace can always count this one always being set */
David S. Miller9360ffd2012-03-29 04:41:26 -040013299 if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
13300 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013301
David S. Miller9360ffd2012-03-29 04:41:26 -040013302 if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
13303 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13304 NL80211_REGDOM_TYPE_WORLD))
13305 goto nla_put_failure;
13306 } else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
13307 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13308 NL80211_REGDOM_TYPE_CUSTOM_WORLD))
13309 goto nla_put_failure;
13310 } else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
13311 request->intersect) {
13312 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13313 NL80211_REGDOM_TYPE_INTERSECTION))
13314 goto nla_put_failure;
13315 } else {
13316 if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
13317 NL80211_REGDOM_TYPE_COUNTRY) ||
13318 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
13319 request->alpha2))
13320 goto nla_put_failure;
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013321 }
13322
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013323 if (request->wiphy_idx != WIPHY_IDX_INVALID) {
13324 struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
13325
13326 if (wiphy &&
13327 nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
13328 goto nla_put_failure;
Arik Nemtsov1bdd7162014-12-15 19:26:01 +020013329
13330 if (wiphy &&
13331 wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
13332 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
13333 goto nla_put_failure;
Arik Nemtsovad30ca22014-12-15 19:25:59 +020013334 }
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013335
Jonathan Doronb0d7aa52014-12-15 19:26:00 +020013336 return true;
13337
13338nla_put_failure:
13339 return false;
13340}
13341
13342/*
13343 * This can happen on global regulatory changes or device specific settings
13344 * based on custom regulatory domains.
13345 */
13346void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
13347 struct regulatory_request *request)
13348{
13349 struct sk_buff *msg;
13350 void *hdr;
13351
13352 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13353 if (!msg)
13354 return;
13355
13356 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
13357 if (!hdr) {
13358 nlmsg_free(msg);
13359 return;
13360 }
13361
13362 if (nl80211_reg_change_event_fill(msg, request) == false)
13363 goto nla_put_failure;
13364
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013365 genlmsg_end(msg, hdr);
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013366
Johannes Bergbc43b282009-07-25 10:54:13 +020013367 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010013368 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013369 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Bergbc43b282009-07-25 10:54:13 +020013370 rcu_read_unlock();
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -040013371
13372 return;
13373
13374nla_put_failure:
13375 genlmsg_cancel(msg, hdr);
13376 nlmsg_free(msg);
13377}
13378
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013379static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
13380 struct net_device *netdev,
13381 const u8 *buf, size_t len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013382 enum nl80211_commands cmd, gfp_t gfp,
13383 int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013384{
13385 struct sk_buff *msg;
13386 void *hdr;
13387
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013388 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013389 if (!msg)
13390 return;
13391
13392 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13393 if (!hdr) {
13394 nlmsg_free(msg);
13395 return;
13396 }
13397
David S. Miller9360ffd2012-03-29 04:41:26 -040013398 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13399 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13400 nla_put(msg, NL80211_ATTR_FRAME, len, buf))
13401 goto nla_put_failure;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013402
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013403 if (uapsd_queues >= 0) {
13404 struct nlattr *nla_wmm =
13405 nla_nest_start(msg, NL80211_ATTR_STA_WME);
13406 if (!nla_wmm)
13407 goto nla_put_failure;
13408
13409 if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
13410 uapsd_queues))
13411 goto nla_put_failure;
13412
13413 nla_nest_end(msg, nla_wmm);
13414 }
13415
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013416 genlmsg_end(msg, hdr);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013417
Johannes Berg68eb5502013-11-19 15:19:38 +010013418 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013419 NL80211_MCGRP_MLME, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013420 return;
13421
13422 nla_put_failure:
13423 genlmsg_cancel(msg, hdr);
13424 nlmsg_free(msg);
13425}
13426
13427void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013428 struct net_device *netdev, const u8 *buf,
13429 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013430{
13431 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013432 NL80211_CMD_AUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013433}
13434
13435void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
13436 struct net_device *netdev, const u8 *buf,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013437 size_t len, gfp_t gfp, int uapsd_queues)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013438{
Johannes Berge6d6e342009-07-01 21:26:47 +020013439 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013440 NL80211_CMD_ASSOCIATE, gfp, uapsd_queues);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013441}
13442
Jouni Malinen53b46b82009-03-27 20:53:56 +020013443void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013444 struct net_device *netdev, const u8 *buf,
13445 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013446{
13447 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013448 NL80211_CMD_DEAUTHENTICATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013449}
13450
Jouni Malinen53b46b82009-03-27 20:53:56 +020013451void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
13452 struct net_device *netdev, const u8 *buf,
Johannes Berge6d6e342009-07-01 21:26:47 +020013453 size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013454{
13455 nl80211_send_mlme_event(rdev, netdev, buf, len,
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013456 NL80211_CMD_DISASSOCIATE, gfp, -1);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020013457}
13458
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013459void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
13460 size_t len)
Jouni Malinencf4e5942010-12-16 00:52:40 +020013461{
Johannes Berg947add32013-02-22 22:05:20 +010013462 struct wireless_dev *wdev = dev->ieee80211_ptr;
13463 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013464 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013465 const struct ieee80211_mgmt *mgmt = (void *)buf;
13466 u32 cmd;
Jouni Malinencf4e5942010-12-16 00:52:40 +020013467
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013468 if (WARN_ON(len < 2))
13469 return;
13470
13471 if (ieee80211_is_deauth(mgmt->frame_control))
13472 cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
13473 else
13474 cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
13475
13476 trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
Eliad Pellerb0b6aa22014-09-09 17:09:45 +030013477 nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1);
Jouni Malinencf4e5942010-12-16 00:52:40 +020013478}
Johannes Berg6ff57cf2013-05-16 00:55:00 +020013479EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
Jouni Malinencf4e5942010-12-16 00:52:40 +020013480
Luis R. Rodriguez1b06bb42009-05-02 00:34:48 -040013481static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
13482 struct net_device *netdev, int cmd,
Johannes Berge6d6e342009-07-01 21:26:47 +020013483 const u8 *addr, gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013484{
13485 struct sk_buff *msg;
13486 void *hdr;
13487
Johannes Berge6d6e342009-07-01 21:26:47 +020013488 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013489 if (!msg)
13490 return;
13491
13492 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13493 if (!hdr) {
13494 nlmsg_free(msg);
13495 return;
13496 }
13497
David S. Miller9360ffd2012-03-29 04:41:26 -040013498 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13499 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13500 nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
13501 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
13502 goto nla_put_failure;
Jouni Malinen1965c852009-04-22 21:38:25 +030013503
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013504 genlmsg_end(msg, hdr);
Jouni Malinen1965c852009-04-22 21:38:25 +030013505
Johannes Berg68eb5502013-11-19 15:19:38 +010013506 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013507 NL80211_MCGRP_MLME, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013508 return;
13509
13510 nla_put_failure:
13511 genlmsg_cancel(msg, hdr);
13512 nlmsg_free(msg);
13513}
13514
13515void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013516 struct net_device *netdev, const u8 *addr,
13517 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013518{
13519 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
Johannes Berge6d6e342009-07-01 21:26:47 +020013520 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013521}
13522
13523void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
Johannes Berge6d6e342009-07-01 21:26:47 +020013524 struct net_device *netdev, const u8 *addr,
13525 gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030013526{
Johannes Berge6d6e342009-07-01 21:26:47 +020013527 nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
13528 addr, gfp);
Jouni Malinen1965c852009-04-22 21:38:25 +030013529}
13530
Samuel Ortizb23aa672009-07-01 21:26:54 +020013531void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030013532 struct net_device *netdev,
13533 struct cfg80211_connect_resp_params *cr,
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020013534 gfp_t gfp)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013535{
13536 struct sk_buff *msg;
13537 void *hdr;
13538
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030013539 msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
13540 cr->fils_kek_len + cr->pmk_len +
13541 (cr->pmkid ? WLAN_PMKID_LEN : 0), gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013542 if (!msg)
13543 return;
13544
13545 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
13546 if (!hdr) {
13547 nlmsg_free(msg);
13548 return;
13549 }
13550
David S. Miller9360ffd2012-03-29 04:41:26 -040013551 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13552 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030013553 (cr->bssid &&
13554 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
Jouni Malinenbf1ecd22016-05-31 00:16:50 +030013555 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030013556 cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
13557 cr->status) ||
13558 (cr->status < 0 &&
Purushottam Kushwaha3093ebbeab2017-01-13 01:12:21 +020013559 (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
Vidyullatha Kanchanapally5349a0f2017-03-31 00:22:33 +030013560 nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
13561 cr->timeout_reason))) ||
13562 (cr->req_ie &&
13563 nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
13564 (cr->resp_ie &&
13565 nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
Vidyullatha Kanchanapallya3caf742017-03-31 00:22:34 +030013566 cr->resp_ie)) ||
13567 (cr->update_erp_next_seq_num &&
13568 nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
13569 cr->fils_erp_next_seq_num)) ||
13570 (cr->status == WLAN_STATUS_SUCCESS &&
13571 ((cr->fils_kek &&
13572 nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils_kek_len,
13573 cr->fils_kek)) ||
13574 (cr->pmk &&
13575 nla_put(msg, NL80211_ATTR_PMK, cr->pmk_len, cr->pmk)) ||
13576 (cr->pmkid &&
13577 nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->pmkid)))))
David S. Miller9360ffd2012-03-29 04:41:26 -040013578 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013579
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013580 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013581
Johannes Berg68eb5502013-11-19 15:19:38 +010013582 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013583 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013584 return;
13585
13586 nla_put_failure:
13587 genlmsg_cancel(msg, hdr);
13588 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013589}
13590
13591void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
13592 struct net_device *netdev, const u8 *bssid,
13593 const u8 *req_ie, size_t req_ie_len,
13594 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
13595{
13596 struct sk_buff *msg;
13597 void *hdr;
13598
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013599 msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013600 if (!msg)
13601 return;
13602
13603 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
13604 if (!hdr) {
13605 nlmsg_free(msg);
13606 return;
13607 }
13608
David S. Miller9360ffd2012-03-29 04:41:26 -040013609 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13610 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13611 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
13612 (req_ie &&
13613 nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
13614 (resp_ie &&
13615 nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
13616 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013617
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013618 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013619
Johannes Berg68eb5502013-11-19 15:19:38 +010013620 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013621 NL80211_MCGRP_MLME, gfp);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013622 return;
13623
13624 nla_put_failure:
13625 genlmsg_cancel(msg, hdr);
13626 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013627}
13628
13629void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
13630 struct net_device *netdev, u16 reason,
Johannes Berg667503d2009-07-07 03:56:11 +020013631 const u8 *ie, size_t ie_len, bool from_ap)
Samuel Ortizb23aa672009-07-01 21:26:54 +020013632{
13633 struct sk_buff *msg;
13634 void *hdr;
13635
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013636 msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013637 if (!msg)
13638 return;
13639
13640 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
13641 if (!hdr) {
13642 nlmsg_free(msg);
13643 return;
13644 }
13645
David S. Miller9360ffd2012-03-29 04:41:26 -040013646 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13647 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13648 (from_ap && reason &&
13649 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
13650 (from_ap &&
13651 nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
13652 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
13653 goto nla_put_failure;
Samuel Ortizb23aa672009-07-01 21:26:54 +020013654
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013655 genlmsg_end(msg, hdr);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013656
Johannes Berg68eb5502013-11-19 15:19:38 +010013657 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013658 NL80211_MCGRP_MLME, GFP_KERNEL);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013659 return;
13660
13661 nla_put_failure:
13662 genlmsg_cancel(msg, hdr);
13663 nlmsg_free(msg);
Samuel Ortizb23aa672009-07-01 21:26:54 +020013664}
13665
Johannes Berg04a773a2009-04-19 21:24:32 +020013666void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
13667 struct net_device *netdev, const u8 *bssid,
13668 gfp_t gfp)
13669{
13670 struct sk_buff *msg;
13671 void *hdr;
13672
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013673 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020013674 if (!msg)
13675 return;
13676
13677 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
13678 if (!hdr) {
13679 nlmsg_free(msg);
13680 return;
13681 }
13682
David S. Miller9360ffd2012-03-29 04:41:26 -040013683 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13684 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13685 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
13686 goto nla_put_failure;
Johannes Berg04a773a2009-04-19 21:24:32 +020013687
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013688 genlmsg_end(msg, hdr);
Johannes Berg04a773a2009-04-19 21:24:32 +020013689
Johannes Berg68eb5502013-11-19 15:19:38 +010013690 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013691 NL80211_MCGRP_MLME, gfp);
Johannes Berg04a773a2009-04-19 21:24:32 +020013692 return;
13693
13694 nla_put_failure:
13695 genlmsg_cancel(msg, hdr);
13696 nlmsg_free(msg);
13697}
13698
Johannes Berg947add32013-02-22 22:05:20 +010013699void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
13700 const u8* ie, u8 ie_len, gfp_t gfp)
Javier Cardonac93b5e72011-04-07 15:08:34 -070013701{
Johannes Berg947add32013-02-22 22:05:20 +010013702 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013703 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013704 struct sk_buff *msg;
13705 void *hdr;
13706
Johannes Berg947add32013-02-22 22:05:20 +010013707 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
13708 return;
13709
13710 trace_cfg80211_notify_new_peer_candidate(dev, addr);
13711
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010013712 msg = nlmsg_new(100 + ie_len, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013713 if (!msg)
13714 return;
13715
13716 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
13717 if (!hdr) {
13718 nlmsg_free(msg);
13719 return;
13720 }
13721
David S. Miller9360ffd2012-03-29 04:41:26 -040013722 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010013723 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13724 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013725 (ie_len && ie &&
13726 nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
13727 goto nla_put_failure;
Javier Cardonac93b5e72011-04-07 15:08:34 -070013728
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013729 genlmsg_end(msg, hdr);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013730
Johannes Berg68eb5502013-11-19 15:19:38 +010013731 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013732 NL80211_MCGRP_MLME, gfp);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013733 return;
13734
13735 nla_put_failure:
13736 genlmsg_cancel(msg, hdr);
13737 nlmsg_free(msg);
13738}
Johannes Berg947add32013-02-22 22:05:20 +010013739EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
Javier Cardonac93b5e72011-04-07 15:08:34 -070013740
Jouni Malinena3b8b052009-03-27 21:59:49 +020013741void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
13742 struct net_device *netdev, const u8 *addr,
13743 enum nl80211_key_type key_type, int key_id,
Johannes Berge6d6e342009-07-01 21:26:47 +020013744 const u8 *tsc, gfp_t gfp)
Jouni Malinena3b8b052009-03-27 21:59:49 +020013745{
13746 struct sk_buff *msg;
13747 void *hdr;
13748
Johannes Berge6d6e342009-07-01 21:26:47 +020013749 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013750 if (!msg)
13751 return;
13752
13753 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
13754 if (!hdr) {
13755 nlmsg_free(msg);
13756 return;
13757 }
13758
David S. Miller9360ffd2012-03-29 04:41:26 -040013759 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
13760 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
13761 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
13762 nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
13763 (key_id != -1 &&
13764 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
13765 (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
13766 goto nla_put_failure;
Jouni Malinena3b8b052009-03-27 21:59:49 +020013767
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013768 genlmsg_end(msg, hdr);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013769
Johannes Berg68eb5502013-11-19 15:19:38 +010013770 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013771 NL80211_MCGRP_MLME, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +020013772 return;
13773
13774 nla_put_failure:
13775 genlmsg_cancel(msg, hdr);
13776 nlmsg_free(msg);
13777}
13778
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013779void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
13780 struct ieee80211_channel *channel_before,
13781 struct ieee80211_channel *channel_after)
13782{
13783 struct sk_buff *msg;
13784 void *hdr;
13785 struct nlattr *nl_freq;
13786
Pablo Neira Ayusofd2120c2009-05-19 15:27:55 -070013787 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013788 if (!msg)
13789 return;
13790
13791 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
13792 if (!hdr) {
13793 nlmsg_free(msg);
13794 return;
13795 }
13796
13797 /*
13798 * Since we are applying the beacon hint to a wiphy we know its
13799 * wiphy_idx is valid
13800 */
David S. Miller9360ffd2012-03-29 04:41:26 -040013801 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
13802 goto nla_put_failure;
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013803
13804 /* Before */
13805 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
13806 if (!nl_freq)
13807 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +010013808 if (nl80211_msg_put_channel(msg, channel_before, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013809 goto nla_put_failure;
13810 nla_nest_end(msg, nl_freq);
13811
13812 /* After */
13813 nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
13814 if (!nl_freq)
13815 goto nla_put_failure;
Johannes Bergcdc89b92013-02-18 23:54:36 +010013816 if (nl80211_msg_put_channel(msg, channel_after, false))
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013817 goto nla_put_failure;
13818 nla_nest_end(msg, nl_freq);
13819
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013820 genlmsg_end(msg, hdr);
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013821
Johannes Berg463d0182009-07-14 00:33:35 +020013822 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +010013823 genlmsg_multicast_allns(&nl80211_fam, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013824 NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
Johannes Berg463d0182009-07-14 00:33:35 +020013825 rcu_read_unlock();
Luis R. Rodriguez6bad8762009-04-02 14:08:09 -040013826
13827 return;
13828
13829nla_put_failure:
13830 genlmsg_cancel(msg, hdr);
13831 nlmsg_free(msg);
13832}
13833
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013834static void nl80211_send_remain_on_chan_event(
13835 int cmd, struct cfg80211_registered_device *rdev,
Johannes Berg71bbc992012-06-15 15:30:18 +020013836 struct wireless_dev *wdev, u64 cookie,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013837 struct ieee80211_channel *chan,
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013838 unsigned int duration, gfp_t gfp)
13839{
13840 struct sk_buff *msg;
13841 void *hdr;
13842
13843 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
13844 if (!msg)
13845 return;
13846
13847 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
13848 if (!hdr) {
13849 nlmsg_free(msg);
13850 return;
13851 }
13852
David S. Miller9360ffd2012-03-29 04:41:26 -040013853 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020013854 (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
13855 wdev->netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013856 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
13857 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040013858 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
Johannes Berg42d97a52012-11-08 18:31:02 +010013859 nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
13860 NL80211_CHAN_NO_HT) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020013861 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
13862 NL80211_ATTR_PAD))
David S. Miller9360ffd2012-03-29 04:41:26 -040013863 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013864
David S. Miller9360ffd2012-03-29 04:41:26 -040013865 if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
13866 nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
13867 goto nla_put_failure;
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013868
Johannes Berg3b7b72e2011-10-22 19:05:51 +020013869 genlmsg_end(msg, hdr);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013870
Johannes Berg68eb5502013-11-19 15:19:38 +010013871 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013872 NL80211_MCGRP_MLME, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013873 return;
13874
13875 nla_put_failure:
13876 genlmsg_cancel(msg, hdr);
13877 nlmsg_free(msg);
13878}
13879
Johannes Berg947add32013-02-22 22:05:20 +010013880void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
13881 struct ieee80211_channel *chan,
13882 unsigned int duration, gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013883{
Johannes Berg947add32013-02-22 22:05:20 +010013884 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013885 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010013886
13887 trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013888 nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
Johannes Berg71bbc992012-06-15 15:30:18 +020013889 rdev, wdev, cookie, chan,
Johannes Berg42d97a52012-11-08 18:31:02 +010013890 duration, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013891}
Johannes Berg947add32013-02-22 22:05:20 +010013892EXPORT_SYMBOL(cfg80211_ready_on_channel);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013893
Johannes Berg947add32013-02-22 22:05:20 +010013894void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
13895 struct ieee80211_channel *chan,
13896 gfp_t gfp)
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013897{
Johannes Berg947add32013-02-22 22:05:20 +010013898 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013899 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010013900
13901 trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013902 nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
Johannes Berg42d97a52012-11-08 18:31:02 +010013903 rdev, wdev, cookie, chan, 0, gfp);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013904}
Johannes Berg947add32013-02-22 22:05:20 +010013905EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
Jouni Malinen9588bbd2009-12-23 13:15:41 +010013906
Johannes Berg947add32013-02-22 22:05:20 +010013907void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
13908 struct station_info *sinfo, gfp_t gfp)
Johannes Berg98b62182009-12-23 13:15:44 +010013909{
Johannes Berg947add32013-02-22 22:05:20 +010013910 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013911 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg98b62182009-12-23 13:15:44 +010013912 struct sk_buff *msg;
13913
Johannes Berg947add32013-02-22 22:05:20 +010013914 trace_cfg80211_new_sta(dev, mac_addr, sinfo);
13915
Thomas Graf58050fc2012-06-28 03:57:45 +000013916 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010013917 if (!msg)
13918 return;
13919
Johannes Bergcf5ead82014-11-14 17:14:00 +010013920 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
John W. Linville66266b32012-03-15 13:25:41 -040013921 rdev, dev, mac_addr, sinfo) < 0) {
Johannes Berg98b62182009-12-23 13:15:44 +010013922 nlmsg_free(msg);
13923 return;
13924 }
13925
Johannes Berg68eb5502013-11-19 15:19:38 +010013926 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013927 NL80211_MCGRP_MLME, gfp);
Johannes Berg98b62182009-12-23 13:15:44 +010013928}
Johannes Berg947add32013-02-22 22:05:20 +010013929EXPORT_SYMBOL(cfg80211_new_sta);
Johannes Berg98b62182009-12-23 13:15:44 +010013930
Johannes Bergcf5ead82014-11-14 17:14:00 +010013931void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
13932 struct station_info *sinfo, gfp_t gfp)
Jouni Malinenec15e682011-03-23 15:29:52 +020013933{
Johannes Berg947add32013-02-22 22:05:20 +010013934 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013935 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinenec15e682011-03-23 15:29:52 +020013936 struct sk_buff *msg;
Johannes Bergcf5ead82014-11-14 17:14:00 +010013937 struct station_info empty_sinfo = {};
13938
13939 if (!sinfo)
13940 sinfo = &empty_sinfo;
Jouni Malinenec15e682011-03-23 15:29:52 +020013941
Johannes Berg947add32013-02-22 22:05:20 +010013942 trace_cfg80211_del_sta(dev, mac_addr);
13943
Thomas Graf58050fc2012-06-28 03:57:45 +000013944 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020013945 if (!msg)
13946 return;
13947
Johannes Bergcf5ead82014-11-14 17:14:00 +010013948 if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
Johannes Berg57007122015-01-16 21:05:02 +010013949 rdev, dev, mac_addr, sinfo) < 0) {
Jouni Malinenec15e682011-03-23 15:29:52 +020013950 nlmsg_free(msg);
13951 return;
13952 }
13953
Johannes Berg68eb5502013-11-19 15:19:38 +010013954 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013955 NL80211_MCGRP_MLME, gfp);
Jouni Malinenec15e682011-03-23 15:29:52 +020013956}
Johannes Bergcf5ead82014-11-14 17:14:00 +010013957EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
Jouni Malinenec15e682011-03-23 15:29:52 +020013958
Johannes Berg947add32013-02-22 22:05:20 +010013959void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
13960 enum nl80211_connect_failed_reason reason,
13961 gfp_t gfp)
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013962{
Johannes Berg947add32013-02-22 22:05:20 +010013963 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013964 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013965 struct sk_buff *msg;
13966 void *hdr;
13967
13968 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
13969 if (!msg)
13970 return;
13971
13972 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED);
13973 if (!hdr) {
13974 nlmsg_free(msg);
13975 return;
13976 }
13977
13978 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
13979 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
13980 nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason))
13981 goto nla_put_failure;
13982
13983 genlmsg_end(msg, hdr);
13984
Johannes Berg68eb5502013-11-19 15:19:38 +010013985 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010013986 NL80211_MCGRP_MLME, gfp);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013987 return;
13988
13989 nla_put_failure:
13990 genlmsg_cancel(msg, hdr);
13991 nlmsg_free(msg);
13992}
Johannes Berg947add32013-02-22 22:05:20 +010013993EXPORT_SYMBOL(cfg80211_conn_failed);
Pandiyarajan Pitchaimuthued44a952012-09-18 16:50:49 +053013994
Johannes Bergb92ab5d2011-11-04 11:18:19 +010013995static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
13996 const u8 *addr, gfp_t gfp)
Johannes Berg28946da2011-11-04 11:18:12 +010013997{
13998 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080013999 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg28946da2011-11-04 11:18:12 +010014000 struct sk_buff *msg;
14001 void *hdr;
Eric W. Biederman15e47302012-09-07 20:12:54 +000014002 u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010014003
Eric W. Biederman15e47302012-09-07 20:12:54 +000014004 if (!nlportid)
Johannes Berg28946da2011-11-04 11:18:12 +010014005 return false;
14006
14007 msg = nlmsg_new(100, gfp);
14008 if (!msg)
14009 return true;
14010
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014011 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
Johannes Berg28946da2011-11-04 11:18:12 +010014012 if (!hdr) {
14013 nlmsg_free(msg);
14014 return true;
14015 }
14016
David S. Miller9360ffd2012-03-29 04:41:26 -040014017 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14018 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14019 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
14020 goto nla_put_failure;
Johannes Berg28946da2011-11-04 11:18:12 +010014021
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014022 genlmsg_end(msg, hdr);
Eric W. Biederman15e47302012-09-07 20:12:54 +000014023 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Johannes Berg28946da2011-11-04 11:18:12 +010014024 return true;
14025
14026 nla_put_failure:
14027 genlmsg_cancel(msg, hdr);
14028 nlmsg_free(msg);
14029 return true;
14030}
14031
Johannes Berg947add32013-02-22 22:05:20 +010014032bool cfg80211_rx_spurious_frame(struct net_device *dev,
14033 const u8 *addr, gfp_t gfp)
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014034{
Johannes Berg947add32013-02-22 22:05:20 +010014035 struct wireless_dev *wdev = dev->ieee80211_ptr;
14036 bool ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014037
Johannes Berg947add32013-02-22 22:05:20 +010014038 trace_cfg80211_rx_spurious_frame(dev, addr);
14039
14040 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
14041 wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
14042 trace_cfg80211_return_bool(false);
14043 return false;
14044 }
14045 ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
14046 addr, gfp);
14047 trace_cfg80211_return_bool(ret);
14048 return ret;
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014049}
Johannes Berg947add32013-02-22 22:05:20 +010014050EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
14051
14052bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
14053 const u8 *addr, gfp_t gfp)
14054{
14055 struct wireless_dev *wdev = dev->ieee80211_ptr;
14056 bool ret;
14057
14058 trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
14059
14060 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
14061 wdev->iftype != NL80211_IFTYPE_P2P_GO &&
14062 wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
14063 trace_cfg80211_return_bool(false);
14064 return false;
14065 }
14066 ret = __nl80211_unexpected_frame(dev,
14067 NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
14068 addr, gfp);
14069 trace_cfg80211_return_bool(ret);
14070 return ret;
14071}
14072EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
Johannes Bergb92ab5d2011-11-04 11:18:19 +010014073
Johannes Berg2e161f72010-08-12 15:38:38 +020014074int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
Eric W. Biederman15e47302012-09-07 20:12:54 +000014075 struct wireless_dev *wdev, u32 nlportid,
Johannes Berg804483e2012-03-05 22:18:41 +010014076 int freq, int sig_dbm,
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030014077 const u8 *buf, size_t len, u32 flags, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020014078{
Johannes Berg71bbc992012-06-15 15:30:18 +020014079 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020014080 struct sk_buff *msg;
14081 void *hdr;
Jouni Malinen026331c2010-02-15 12:53:10 +020014082
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014083 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014084 if (!msg)
14085 return -ENOMEM;
14086
Johannes Berg2e161f72010-08-12 15:38:38 +020014087 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
Jouni Malinen026331c2010-02-15 12:53:10 +020014088 if (!hdr) {
14089 nlmsg_free(msg);
14090 return -ENOMEM;
14091 }
14092
David S. Miller9360ffd2012-03-29 04:41:26 -040014093 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020014094 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14095 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014096 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14097 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014098 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
14099 (sig_dbm &&
14100 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
Vladimir Kondratiev19504cf2013-08-15 14:51:28 +030014101 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
14102 (flags &&
14103 nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
David S. Miller9360ffd2012-03-29 04:41:26 -040014104 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020014105
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014106 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020014107
Eric W. Biederman15e47302012-09-07 20:12:54 +000014108 return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
Jouni Malinen026331c2010-02-15 12:53:10 +020014109
14110 nla_put_failure:
14111 genlmsg_cancel(msg, hdr);
14112 nlmsg_free(msg);
14113 return -ENOBUFS;
14114}
14115
Johannes Berg947add32013-02-22 22:05:20 +010014116void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
14117 const u8 *buf, size_t len, bool ack, gfp_t gfp)
Jouni Malinen026331c2010-02-15 12:53:10 +020014118{
Johannes Berg947add32013-02-22 22:05:20 +010014119 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014120 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg71bbc992012-06-15 15:30:18 +020014121 struct net_device *netdev = wdev->netdev;
Jouni Malinen026331c2010-02-15 12:53:10 +020014122 struct sk_buff *msg;
14123 void *hdr;
14124
Johannes Berg947add32013-02-22 22:05:20 +010014125 trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
14126
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014127 msg = nlmsg_new(100 + len, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014128 if (!msg)
14129 return;
14130
Johannes Berg2e161f72010-08-12 15:38:38 +020014131 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
Jouni Malinen026331c2010-02-15 12:53:10 +020014132 if (!hdr) {
14133 nlmsg_free(msg);
14134 return;
14135 }
14136
David S. Miller9360ffd2012-03-29 04:41:26 -040014137 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg71bbc992012-06-15 15:30:18 +020014138 (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14139 netdev->ifindex)) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014140 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14141 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014142 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014143 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14144 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014145 (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
14146 goto nla_put_failure;
Jouni Malinen026331c2010-02-15 12:53:10 +020014147
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014148 genlmsg_end(msg, hdr);
Jouni Malinen026331c2010-02-15 12:53:10 +020014149
Johannes Berg68eb5502013-11-19 15:19:38 +010014150 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014151 NL80211_MCGRP_MLME, gfp);
Jouni Malinen026331c2010-02-15 12:53:10 +020014152 return;
14153
14154 nla_put_failure:
14155 genlmsg_cancel(msg, hdr);
14156 nlmsg_free(msg);
14157}
Johannes Berg947add32013-02-22 22:05:20 +010014158EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
Jouni Malinen026331c2010-02-15 12:53:10 +020014159
Johannes Berg5b97f492014-11-26 12:37:43 +010014160static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
14161 const char *mac, gfp_t gfp)
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014162{
Johannes Berg947add32013-02-22 22:05:20 +010014163 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg5b97f492014-11-26 12:37:43 +010014164 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
14165 struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14166 void **cb;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014167
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014168 if (!msg)
Johannes Berg5b97f492014-11-26 12:37:43 +010014169 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014170
Johannes Berg5b97f492014-11-26 12:37:43 +010014171 cb = (void **)msg->cb;
14172
14173 cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
14174 if (!cb[0]) {
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014175 nlmsg_free(msg);
Johannes Berg5b97f492014-11-26 12:37:43 +010014176 return NULL;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014177 }
14178
David S. Miller9360ffd2012-03-29 04:41:26 -040014179 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Johannes Berg947add32013-02-22 22:05:20 +010014180 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
David S. Miller9360ffd2012-03-29 04:41:26 -040014181 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014182
Johannes Berg5b97f492014-11-26 12:37:43 +010014183 if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014184 goto nla_put_failure;
14185
Johannes Berg5b97f492014-11-26 12:37:43 +010014186 cb[1] = nla_nest_start(msg, NL80211_ATTR_CQM);
14187 if (!cb[1])
14188 goto nla_put_failure;
14189
14190 cb[2] = rdev;
14191
14192 return msg;
14193 nla_put_failure:
14194 nlmsg_free(msg);
14195 return NULL;
14196}
14197
14198static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
14199{
14200 void **cb = (void **)msg->cb;
14201 struct cfg80211_registered_device *rdev = cb[2];
14202
14203 nla_nest_end(msg, cb[1]);
14204 genlmsg_end(msg, cb[0]);
14205
14206 memset(msg->cb, 0, sizeof(msg->cb));
14207
14208 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
14209 NL80211_MCGRP_MLME, gfp);
14210}
14211
14212void cfg80211_cqm_rssi_notify(struct net_device *dev,
14213 enum nl80211_cqm_rssi_threshold_event rssi_event,
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010014214 s32 rssi_level, gfp_t gfp)
Johannes Berg5b97f492014-11-26 12:37:43 +010014215{
14216 struct sk_buff *msg;
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010014217 struct wireless_dev *wdev = dev->ieee80211_ptr;
14218 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg5b97f492014-11-26 12:37:43 +010014219
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010014220 trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
Johannes Berg5b97f492014-11-26 12:37:43 +010014221
Johannes Berg98f03342014-11-26 12:42:02 +010014222 if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
14223 rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
14224 return;
14225
Andrew Zaborowski4a4b8162017-02-10 10:02:31 +010014226 if (wdev->cqm_config) {
14227 wdev->cqm_config->last_rssi_event_value = rssi_level;
14228
14229 cfg80211_cqm_rssi_update(rdev, dev);
14230
14231 if (rssi_level == 0)
14232 rssi_level = wdev->cqm_config->last_rssi_event_value;
14233 }
14234
Johannes Berg5b97f492014-11-26 12:37:43 +010014235 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
14236 if (!msg)
14237 return;
14238
David S. Miller9360ffd2012-03-29 04:41:26 -040014239 if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
14240 rssi_event))
14241 goto nla_put_failure;
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014242
Andrzej Zaborowskibee427b2017-01-25 12:43:41 +010014243 if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
14244 rssi_level))
14245 goto nla_put_failure;
14246
Johannes Berg5b97f492014-11-26 12:37:43 +010014247 cfg80211_send_cqm(msg, gfp);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014248
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014249 return;
14250
14251 nla_put_failure:
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014252 nlmsg_free(msg);
14253}
Johannes Berg947add32013-02-22 22:05:20 +010014254EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
Juuso Oikarinend6dc1a32010-03-23 09:02:33 +020014255
Johannes Berg5b97f492014-11-26 12:37:43 +010014256void cfg80211_cqm_txe_notify(struct net_device *dev,
14257 const u8 *peer, u32 num_packets,
14258 u32 rate, u32 intvl, gfp_t gfp)
14259{
14260 struct sk_buff *msg;
14261
14262 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14263 if (!msg)
14264 return;
14265
14266 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
14267 goto nla_put_failure;
14268
14269 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
14270 goto nla_put_failure;
14271
14272 if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
14273 goto nla_put_failure;
14274
14275 cfg80211_send_cqm(msg, gfp);
14276 return;
14277
14278 nla_put_failure:
14279 nlmsg_free(msg);
14280}
14281EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
14282
14283void cfg80211_cqm_pktloss_notify(struct net_device *dev,
14284 const u8 *peer, u32 num_packets, gfp_t gfp)
14285{
14286 struct sk_buff *msg;
14287
14288 trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
14289
14290 msg = cfg80211_prepare_cqm(dev, peer, gfp);
14291 if (!msg)
14292 return;
14293
14294 if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
14295 goto nla_put_failure;
14296
14297 cfg80211_send_cqm(msg, gfp);
14298 return;
14299
14300 nla_put_failure:
14301 nlmsg_free(msg);
14302}
14303EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
14304
Johannes Berg98f03342014-11-26 12:42:02 +010014305void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
14306{
14307 struct sk_buff *msg;
14308
14309 msg = cfg80211_prepare_cqm(dev, NULL, gfp);
14310 if (!msg)
14311 return;
14312
14313 if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
14314 goto nla_put_failure;
14315
14316 cfg80211_send_cqm(msg, gfp);
14317 return;
14318
14319 nla_put_failure:
14320 nlmsg_free(msg);
14321}
14322EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
14323
Johannes Berg947add32013-02-22 22:05:20 +010014324static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
14325 struct net_device *netdev, const u8 *bssid,
14326 const u8 *replay_ctr, gfp_t gfp)
Johannes Berge5497d72011-07-05 16:35:40 +020014327{
14328 struct sk_buff *msg;
14329 struct nlattr *rekey_attr;
14330 void *hdr;
14331
Thomas Graf58050fc2012-06-28 03:57:45 +000014332 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014333 if (!msg)
14334 return;
14335
14336 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
14337 if (!hdr) {
14338 nlmsg_free(msg);
14339 return;
14340 }
14341
David S. Miller9360ffd2012-03-29 04:41:26 -040014342 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14343 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14344 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
14345 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014346
14347 rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
14348 if (!rekey_attr)
14349 goto nla_put_failure;
14350
David S. Miller9360ffd2012-03-29 04:41:26 -040014351 if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
14352 NL80211_REPLAY_CTR_LEN, replay_ctr))
14353 goto nla_put_failure;
Johannes Berge5497d72011-07-05 16:35:40 +020014354
14355 nla_nest_end(msg, rekey_attr);
14356
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014357 genlmsg_end(msg, hdr);
Johannes Berge5497d72011-07-05 16:35:40 +020014358
Johannes Berg68eb5502013-11-19 15:19:38 +010014359 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014360 NL80211_MCGRP_MLME, gfp);
Johannes Berge5497d72011-07-05 16:35:40 +020014361 return;
14362
14363 nla_put_failure:
14364 genlmsg_cancel(msg, hdr);
14365 nlmsg_free(msg);
14366}
14367
Johannes Berg947add32013-02-22 22:05:20 +010014368void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
14369 const u8 *replay_ctr, gfp_t gfp)
14370{
14371 struct wireless_dev *wdev = dev->ieee80211_ptr;
14372 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014373 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014374
14375 trace_cfg80211_gtk_rekey_notify(dev, bssid);
14376 nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
14377}
14378EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
14379
14380static void
14381nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
14382 struct net_device *netdev, int index,
14383 const u8 *bssid, bool preauth, gfp_t gfp)
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014384{
14385 struct sk_buff *msg;
14386 struct nlattr *attr;
14387 void *hdr;
14388
Thomas Graf58050fc2012-06-28 03:57:45 +000014389 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014390 if (!msg)
14391 return;
14392
14393 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
14394 if (!hdr) {
14395 nlmsg_free(msg);
14396 return;
14397 }
14398
David S. Miller9360ffd2012-03-29 04:41:26 -040014399 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14400 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
14401 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014402
14403 attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE);
14404 if (!attr)
14405 goto nla_put_failure;
14406
David S. Miller9360ffd2012-03-29 04:41:26 -040014407 if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
14408 nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
14409 (preauth &&
14410 nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
14411 goto nla_put_failure;
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014412
14413 nla_nest_end(msg, attr);
14414
Johannes Berg3b7b72e2011-10-22 19:05:51 +020014415 genlmsg_end(msg, hdr);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014416
Johannes Berg68eb5502013-11-19 15:19:38 +010014417 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014418 NL80211_MCGRP_MLME, gfp);
Jouni Malinenc9df56b2011-09-16 18:56:23 +030014419 return;
14420
14421 nla_put_failure:
14422 genlmsg_cancel(msg, hdr);
14423 nlmsg_free(msg);
14424}
14425
Johannes Berg947add32013-02-22 22:05:20 +010014426void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
14427 const u8 *bssid, bool preauth, gfp_t gfp)
14428{
14429 struct wireless_dev *wdev = dev->ieee80211_ptr;
14430 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014431 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014432
14433 trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
14434 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
14435}
14436EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
14437
14438static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
14439 struct net_device *netdev,
14440 struct cfg80211_chan_def *chandef,
Luciano Coelhof8d75522014-11-07 14:31:35 +020014441 gfp_t gfp,
14442 enum nl80211_commands notif,
14443 u8 count)
Thomas Pedersen53145262012-04-06 13:35:47 -070014444{
14445 struct sk_buff *msg;
14446 void *hdr;
14447
Thomas Graf58050fc2012-06-28 03:57:45 +000014448 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070014449 if (!msg)
14450 return;
14451
Luciano Coelhof8d75522014-11-07 14:31:35 +020014452 hdr = nl80211hdr_put(msg, 0, 0, 0, notif);
Thomas Pedersen53145262012-04-06 13:35:47 -070014453 if (!hdr) {
14454 nlmsg_free(msg);
14455 return;
14456 }
14457
Johannes Berg683b6d32012-11-08 21:25:48 +010014458 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
14459 goto nla_put_failure;
14460
14461 if (nl80211_send_chandef(msg, chandef))
John W. Linville7eab0f62012-04-12 14:25:14 -040014462 goto nla_put_failure;
Thomas Pedersen53145262012-04-06 13:35:47 -070014463
Luciano Coelhof8d75522014-11-07 14:31:35 +020014464 if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) &&
14465 (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count)))
14466 goto nla_put_failure;
14467
Thomas Pedersen53145262012-04-06 13:35:47 -070014468 genlmsg_end(msg, hdr);
14469
Johannes Berg68eb5502013-11-19 15:19:38 +010014470 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014471 NL80211_MCGRP_MLME, gfp);
Thomas Pedersen53145262012-04-06 13:35:47 -070014472 return;
14473
14474 nla_put_failure:
14475 genlmsg_cancel(msg, hdr);
14476 nlmsg_free(msg);
14477}
14478
Johannes Berg947add32013-02-22 22:05:20 +010014479void cfg80211_ch_switch_notify(struct net_device *dev,
14480 struct cfg80211_chan_def *chandef)
Thomas Pedersen84f10702012-07-12 16:17:33 -070014481{
Johannes Berg947add32013-02-22 22:05:20 +010014482 struct wireless_dev *wdev = dev->ieee80211_ptr;
14483 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014484 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg947add32013-02-22 22:05:20 +010014485
Simon Wunderliche487eae2013-11-21 18:19:51 +010014486 ASSERT_WDEV_LOCK(wdev);
Johannes Berg947add32013-02-22 22:05:20 +010014487
Simon Wunderliche487eae2013-11-21 18:19:51 +010014488 trace_cfg80211_ch_switch_notify(dev, chandef);
Johannes Berg947add32013-02-22 22:05:20 +010014489
Michal Kazior9e0e2962014-01-29 14:22:27 +010014490 wdev->chandef = *chandef;
Janusz Dziedzic96f55f12014-01-24 14:29:21 +010014491 wdev->preset_chandef = *chandef;
Luciano Coelhof8d75522014-11-07 14:31:35 +020014492 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
14493 NL80211_CMD_CH_SWITCH_NOTIFY, 0);
Johannes Berg947add32013-02-22 22:05:20 +010014494}
14495EXPORT_SYMBOL(cfg80211_ch_switch_notify);
14496
Luciano Coelhof8d75522014-11-07 14:31:35 +020014497void cfg80211_ch_switch_started_notify(struct net_device *dev,
14498 struct cfg80211_chan_def *chandef,
14499 u8 count)
14500{
14501 struct wireless_dev *wdev = dev->ieee80211_ptr;
14502 struct wiphy *wiphy = wdev->wiphy;
14503 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
14504
14505 trace_cfg80211_ch_switch_started_notify(dev, chandef);
14506
14507 nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
14508 NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count);
14509}
14510EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
14511
Thomas Pedersen84f10702012-07-12 16:17:33 -070014512void
Simon Wunderlich04f39042013-02-08 18:16:19 +010014513nl80211_radar_notify(struct cfg80211_registered_device *rdev,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +010014514 const struct cfg80211_chan_def *chandef,
Simon Wunderlich04f39042013-02-08 18:16:19 +010014515 enum nl80211_radar_event event,
14516 struct net_device *netdev, gfp_t gfp)
14517{
14518 struct sk_buff *msg;
14519 void *hdr;
14520
14521 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14522 if (!msg)
14523 return;
14524
14525 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
14526 if (!hdr) {
14527 nlmsg_free(msg);
14528 return;
14529 }
14530
14531 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
14532 goto nla_put_failure;
14533
14534 /* NOP and radar events don't need a netdev parameter */
14535 if (netdev) {
14536 struct wireless_dev *wdev = netdev->ieee80211_ptr;
14537
14538 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014539 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14540 NL80211_ATTR_PAD))
Simon Wunderlich04f39042013-02-08 18:16:19 +010014541 goto nla_put_failure;
14542 }
14543
14544 if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
14545 goto nla_put_failure;
14546
14547 if (nl80211_send_chandef(msg, chandef))
14548 goto nla_put_failure;
14549
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014550 genlmsg_end(msg, hdr);
Simon Wunderlich04f39042013-02-08 18:16:19 +010014551
Johannes Berg68eb5502013-11-19 15:19:38 +010014552 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014553 NL80211_MCGRP_MLME, gfp);
Simon Wunderlich04f39042013-02-08 18:16:19 +010014554 return;
14555
14556 nla_put_failure:
14557 genlmsg_cancel(msg, hdr);
14558 nlmsg_free(msg);
14559}
14560
Johannes Berg7f6cf312011-11-04 11:18:15 +010014561void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
14562 u64 cookie, bool acked, gfp_t gfp)
14563{
14564 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014565 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014566 struct sk_buff *msg;
14567 void *hdr;
Johannes Berg7f6cf312011-11-04 11:18:15 +010014568
Beni Lev4ee3e062012-08-27 12:49:39 +030014569 trace_cfg80211_probe_status(dev, addr, cookie, acked);
14570
Thomas Graf58050fc2012-06-28 03:57:45 +000014571 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
Beni Lev4ee3e062012-08-27 12:49:39 +030014572
Johannes Berg7f6cf312011-11-04 11:18:15 +010014573 if (!msg)
14574 return;
14575
14576 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
14577 if (!hdr) {
14578 nlmsg_free(msg);
14579 return;
14580 }
14581
David S. Miller9360ffd2012-03-29 04:41:26 -040014582 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14583 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14584 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014585 nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
14586 NL80211_ATTR_PAD) ||
David S. Miller9360ffd2012-03-29 04:41:26 -040014587 (acked && nla_put_flag(msg, NL80211_ATTR_ACK)))
14588 goto nla_put_failure;
Johannes Berg7f6cf312011-11-04 11:18:15 +010014589
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014590 genlmsg_end(msg, hdr);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014591
Johannes Berg68eb5502013-11-19 15:19:38 +010014592 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014593 NL80211_MCGRP_MLME, gfp);
Johannes Berg7f6cf312011-11-04 11:18:15 +010014594 return;
14595
14596 nla_put_failure:
14597 genlmsg_cancel(msg, hdr);
14598 nlmsg_free(msg);
14599}
14600EXPORT_SYMBOL(cfg80211_probe_status);
14601
Johannes Berg5e760232011-11-04 11:18:17 +010014602void cfg80211_report_obss_beacon(struct wiphy *wiphy,
14603 const u8 *frame, size_t len,
Ben Greear37c73b52012-10-26 14:49:25 -070014604 int freq, int sig_dbm)
Johannes Berg5e760232011-11-04 11:18:17 +010014605{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014606 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg5e760232011-11-04 11:18:17 +010014607 struct sk_buff *msg;
14608 void *hdr;
Ben Greear37c73b52012-10-26 14:49:25 -070014609 struct cfg80211_beacon_registration *reg;
Johannes Berg5e760232011-11-04 11:18:17 +010014610
Beni Lev4ee3e062012-08-27 12:49:39 +030014611 trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
14612
Ben Greear37c73b52012-10-26 14:49:25 -070014613 spin_lock_bh(&rdev->beacon_registrations_lock);
14614 list_for_each_entry(reg, &rdev->beacon_registrations, list) {
14615 msg = nlmsg_new(len + 100, GFP_ATOMIC);
14616 if (!msg) {
14617 spin_unlock_bh(&rdev->beacon_registrations_lock);
14618 return;
14619 }
Johannes Berg5e760232011-11-04 11:18:17 +010014620
Ben Greear37c73b52012-10-26 14:49:25 -070014621 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
14622 if (!hdr)
14623 goto nla_put_failure;
Johannes Berg5e760232011-11-04 11:18:17 +010014624
Ben Greear37c73b52012-10-26 14:49:25 -070014625 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14626 (freq &&
14627 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
14628 (sig_dbm &&
14629 nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
14630 nla_put(msg, NL80211_ATTR_FRAME, len, frame))
14631 goto nla_put_failure;
14632
14633 genlmsg_end(msg, hdr);
14634
14635 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
Johannes Berg5e760232011-11-04 11:18:17 +010014636 }
Ben Greear37c73b52012-10-26 14:49:25 -070014637 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg5e760232011-11-04 11:18:17 +010014638 return;
14639
14640 nla_put_failure:
Ben Greear37c73b52012-10-26 14:49:25 -070014641 spin_unlock_bh(&rdev->beacon_registrations_lock);
14642 if (hdr)
14643 genlmsg_cancel(msg, hdr);
Johannes Berg5e760232011-11-04 11:18:17 +010014644 nlmsg_free(msg);
14645}
14646EXPORT_SYMBOL(cfg80211_report_obss_beacon);
14647
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014648#ifdef CONFIG_PM
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014649static int cfg80211_net_detect_results(struct sk_buff *msg,
14650 struct cfg80211_wowlan_wakeup *wakeup)
14651{
14652 struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect;
14653 struct nlattr *nl_results, *nl_match, *nl_freqs;
14654 int i, j;
14655
14656 nl_results = nla_nest_start(
14657 msg, NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS);
14658 if (!nl_results)
14659 return -EMSGSIZE;
14660
14661 for (i = 0; i < nd->n_matches; i++) {
14662 struct cfg80211_wowlan_nd_match *match = nd->matches[i];
14663
14664 nl_match = nla_nest_start(msg, i);
14665 if (!nl_match)
14666 break;
14667
14668 /* The SSID attribute is optional in nl80211, but for
14669 * simplicity reasons it's always present in the
14670 * cfg80211 structure. If a driver can't pass the
14671 * SSID, that needs to be changed. A zero length SSID
14672 * is still a valid SSID (wildcard), so it cannot be
14673 * used for this purpose.
14674 */
14675 if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len,
14676 match->ssid.ssid)) {
14677 nla_nest_cancel(msg, nl_match);
14678 goto out;
14679 }
14680
14681 if (match->n_channels) {
14682 nl_freqs = nla_nest_start(
14683 msg, NL80211_ATTR_SCAN_FREQUENCIES);
14684 if (!nl_freqs) {
14685 nla_nest_cancel(msg, nl_match);
14686 goto out;
14687 }
14688
14689 for (j = 0; j < match->n_channels; j++) {
Samuel Tan5528fae82015-02-09 21:29:15 +020014690 if (nla_put_u32(msg, j, match->channels[j])) {
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014691 nla_nest_cancel(msg, nl_freqs);
14692 nla_nest_cancel(msg, nl_match);
14693 goto out;
14694 }
14695 }
14696
14697 nla_nest_end(msg, nl_freqs);
14698 }
14699
14700 nla_nest_end(msg, nl_match);
14701 }
14702
14703out:
14704 nla_nest_end(msg, nl_results);
14705 return 0;
14706}
14707
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014708void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
14709 struct cfg80211_wowlan_wakeup *wakeup,
14710 gfp_t gfp)
14711{
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014712 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014713 struct sk_buff *msg;
14714 void *hdr;
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014715 int size = 200;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014716
14717 trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
14718
14719 if (wakeup)
14720 size += wakeup->packet_present_len;
14721
14722 msg = nlmsg_new(size, gfp);
14723 if (!msg)
14724 return;
14725
14726 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN);
14727 if (!hdr)
14728 goto free_msg;
14729
14730 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020014731 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
14732 NL80211_ATTR_PAD))
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014733 goto free_msg;
14734
14735 if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
14736 wdev->netdev->ifindex))
14737 goto free_msg;
14738
14739 if (wakeup) {
14740 struct nlattr *reasons;
14741
14742 reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
Johannes Berg7fa322c2013-10-25 11:16:58 +020014743 if (!reasons)
14744 goto free_msg;
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014745
14746 if (wakeup->disconnect &&
14747 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
14748 goto free_msg;
14749 if (wakeup->magic_pkt &&
14750 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT))
14751 goto free_msg;
14752 if (wakeup->gtk_rekey_failure &&
14753 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE))
14754 goto free_msg;
14755 if (wakeup->eap_identity_req &&
14756 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST))
14757 goto free_msg;
14758 if (wakeup->four_way_handshake &&
14759 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE))
14760 goto free_msg;
14761 if (wakeup->rfkill_release &&
14762 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))
14763 goto free_msg;
14764
14765 if (wakeup->pattern_idx >= 0 &&
14766 nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
14767 wakeup->pattern_idx))
14768 goto free_msg;
14769
Johannes Bergae917c92013-10-25 11:05:22 +020014770 if (wakeup->tcp_match &&
14771 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
14772 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014773
Johannes Bergae917c92013-10-25 11:05:22 +020014774 if (wakeup->tcp_connlost &&
14775 nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
14776 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014777
Johannes Bergae917c92013-10-25 11:05:22 +020014778 if (wakeup->tcp_nomoretokens &&
14779 nla_put_flag(msg,
14780 NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
14781 goto free_msg;
Johannes Berg2a0e0472013-01-23 22:57:40 +010014782
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014783 if (wakeup->packet) {
14784 u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
14785 u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN;
14786
14787 if (!wakeup->packet_80211) {
14788 pkt_attr =
14789 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023;
14790 len_attr =
14791 NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN;
14792 }
14793
14794 if (wakeup->packet_len &&
14795 nla_put_u32(msg, len_attr, wakeup->packet_len))
14796 goto free_msg;
14797
14798 if (nla_put(msg, pkt_attr, wakeup->packet_present_len,
14799 wakeup->packet))
14800 goto free_msg;
14801 }
14802
Luciano Coelho8cd4d452014-09-17 11:55:28 +030014803 if (wakeup->net_detect &&
14804 cfg80211_net_detect_results(msg, wakeup))
14805 goto free_msg;
14806
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014807 nla_nest_end(msg, reasons);
14808 }
14809
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014810 genlmsg_end(msg, hdr);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014811
Johannes Berg68eb5502013-11-19 15:19:38 +010014812 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014813 NL80211_MCGRP_MLME, gfp);
Johannes Bergcd8f7cb2013-01-22 12:34:29 +010014814 return;
14815
14816 free_msg:
14817 nlmsg_free(msg);
14818}
14819EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup);
14820#endif
14821
Jouni Malinen3475b092012-11-16 22:49:57 +020014822void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
14823 enum nl80211_tdls_operation oper,
14824 u16 reason_code, gfp_t gfp)
14825{
14826 struct wireless_dev *wdev = dev->ieee80211_ptr;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014827 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
Jouni Malinen3475b092012-11-16 22:49:57 +020014828 struct sk_buff *msg;
14829 void *hdr;
Jouni Malinen3475b092012-11-16 22:49:57 +020014830
14831 trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
14832 reason_code);
14833
14834 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14835 if (!msg)
14836 return;
14837
14838 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
14839 if (!hdr) {
14840 nlmsg_free(msg);
14841 return;
14842 }
14843
14844 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14845 nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
14846 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
14847 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
14848 (reason_code > 0 &&
14849 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
14850 goto nla_put_failure;
14851
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014852 genlmsg_end(msg, hdr);
Jouni Malinen3475b092012-11-16 22:49:57 +020014853
Johannes Berg68eb5502013-11-19 15:19:38 +010014854 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014855 NL80211_MCGRP_MLME, gfp);
Jouni Malinen3475b092012-11-16 22:49:57 +020014856 return;
14857
14858 nla_put_failure:
14859 genlmsg_cancel(msg, hdr);
14860 nlmsg_free(msg);
14861}
14862EXPORT_SYMBOL(cfg80211_tdls_oper_request);
14863
Jouni Malinen026331c2010-02-15 12:53:10 +020014864static int nl80211_netlink_notify(struct notifier_block * nb,
14865 unsigned long state,
14866 void *_notify)
14867{
14868 struct netlink_notify *notify = _notify;
14869 struct cfg80211_registered_device *rdev;
14870 struct wireless_dev *wdev;
Ben Greear37c73b52012-10-26 14:49:25 -070014871 struct cfg80211_beacon_registration *reg, *tmp;
Jouni Malinen026331c2010-02-15 12:53:10 +020014872
Dmitry Ivanov8f815cd2016-04-06 17:23:18 +030014873 if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
Jouni Malinen026331c2010-02-15 12:53:10 +020014874 return NOTIFY_DONE;
14875
14876 rcu_read_lock();
14877
Johannes Berg5e760232011-11-04 11:18:17 +010014878 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
Johannes Berg78f22b62014-03-24 17:57:27 +010014879 bool schedule_destroy_work = false;
Jukka Rissanen93a1e862014-12-15 13:25:39 +020014880 struct cfg80211_sched_scan_request *sched_scan_req =
14881 rcu_dereference(rdev->sched_scan_req);
14882
14883 if (sched_scan_req && notify->portid &&
Johannes Berg753aacf2017-01-05 10:57:14 +010014884 sched_scan_req->owner_nlportid == notify->portid) {
14885 sched_scan_req->owner_nlportid = 0;
14886
14887 if (rdev->ops->sched_scan_stop &&
14888 rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
14889 schedule_work(&rdev->sched_scan_stop_wk);
14890 }
Johannes Berg78f22b62014-03-24 17:57:27 +010014891
Johannes Berg53873f12016-05-03 16:52:04 +030014892 list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
Eric W. Biederman15e47302012-09-07 20:12:54 +000014893 cfg80211_mlme_unregister_socket(wdev, notify->portid);
Ben Greear37c73b52012-10-26 14:49:25 -070014894
Johannes Berg78f22b62014-03-24 17:57:27 +010014895 if (wdev->owner_nlportid == notify->portid)
14896 schedule_destroy_work = true;
Andrzej Zaborowskibd2522b2017-01-06 16:33:43 -050014897 else if (wdev->conn_owner_nlportid == notify->portid)
14898 schedule_work(&wdev->disconnect_wk);
Johannes Berg78f22b62014-03-24 17:57:27 +010014899 }
14900
Ben Greear37c73b52012-10-26 14:49:25 -070014901 spin_lock_bh(&rdev->beacon_registrations_lock);
14902 list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
14903 list) {
14904 if (reg->nlportid == notify->portid) {
14905 list_del(&reg->list);
14906 kfree(reg);
14907 break;
14908 }
14909 }
14910 spin_unlock_bh(&rdev->beacon_registrations_lock);
Johannes Berg78f22b62014-03-24 17:57:27 +010014911
14912 if (schedule_destroy_work) {
14913 struct cfg80211_iface_destroy *destroy;
14914
14915 destroy = kzalloc(sizeof(*destroy), GFP_ATOMIC);
14916 if (destroy) {
14917 destroy->nlportid = notify->portid;
14918 spin_lock(&rdev->destroy_list_lock);
14919 list_add(&destroy->list, &rdev->destroy_list);
14920 spin_unlock(&rdev->destroy_list_lock);
14921 schedule_work(&rdev->destroy_work);
14922 }
14923 }
Johannes Berg5e760232011-11-04 11:18:17 +010014924 }
Jouni Malinen026331c2010-02-15 12:53:10 +020014925
14926 rcu_read_unlock();
14927
Ilan peer05050752015-03-04 00:32:06 -050014928 /*
14929 * It is possible that the user space process that is controlling the
14930 * indoor setting disappeared, so notify the regulatory core.
14931 */
14932 regulatory_netlink_notify(notify->portid);
Zhao, Gang6784c7d2014-04-21 12:53:04 +080014933 return NOTIFY_OK;
Jouni Malinen026331c2010-02-15 12:53:10 +020014934}
14935
14936static struct notifier_block nl80211_netlink_notifier = {
14937 .notifier_call = nl80211_netlink_notify,
14938};
14939
Jouni Malinen355199e2013-02-27 17:14:27 +020014940void cfg80211_ft_event(struct net_device *netdev,
14941 struct cfg80211_ft_event_params *ft_event)
14942{
14943 struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014944 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Jouni Malinen355199e2013-02-27 17:14:27 +020014945 struct sk_buff *msg;
14946 void *hdr;
Jouni Malinen355199e2013-02-27 17:14:27 +020014947
14948 trace_cfg80211_ft_event(wiphy, netdev, ft_event);
14949
14950 if (!ft_event->target_ap)
14951 return;
14952
Johannes Berg4ef8c1c2017-01-09 11:10:42 +010014953 msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
Jouni Malinen355199e2013-02-27 17:14:27 +020014954 if (!msg)
14955 return;
14956
14957 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
Johannes Bergae917c92013-10-25 11:05:22 +020014958 if (!hdr)
14959 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020014960
Johannes Bergae917c92013-10-25 11:05:22 +020014961 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
14962 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
14963 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
14964 goto out;
14965
14966 if (ft_event->ies &&
14967 nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
14968 goto out;
14969 if (ft_event->ric_ies &&
14970 nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
14971 ft_event->ric_ies))
14972 goto out;
Jouni Malinen355199e2013-02-27 17:14:27 +020014973
Johannes Berg9c90a9f2013-06-04 12:46:03 +020014974 genlmsg_end(msg, hdr);
Jouni Malinen355199e2013-02-27 17:14:27 +020014975
Johannes Berg68eb5502013-11-19 15:19:38 +010014976 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +010014977 NL80211_MCGRP_MLME, GFP_KERNEL);
Johannes Bergae917c92013-10-25 11:05:22 +020014978 return;
14979 out:
14980 nlmsg_free(msg);
Jouni Malinen355199e2013-02-27 17:14:27 +020014981}
14982EXPORT_SYMBOL(cfg80211_ft_event);
14983
Arend van Spriel5de17982013-04-18 15:49:00 +020014984void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
14985{
14986 struct cfg80211_registered_device *rdev;
14987 struct sk_buff *msg;
14988 void *hdr;
14989 u32 nlportid;
14990
Zhao, Gangf26cbf42014-04-21 12:53:03 +080014991 rdev = wiphy_to_rdev(wdev->wiphy);
Arend van Spriel5de17982013-04-18 15:49:00 +020014992 if (!rdev->crit_proto_nlportid)
14993 return;
14994
14995 nlportid = rdev->crit_proto_nlportid;
14996 rdev->crit_proto_nlportid = 0;
14997
14998 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
14999 if (!msg)
15000 return;
15001
15002 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
15003 if (!hdr)
15004 goto nla_put_failure;
15005
15006 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015007 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15008 NL80211_ATTR_PAD))
Arend van Spriel5de17982013-04-18 15:49:00 +020015009 goto nla_put_failure;
15010
15011 genlmsg_end(msg, hdr);
15012
15013 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
15014 return;
15015
15016 nla_put_failure:
15017 if (hdr)
15018 genlmsg_cancel(msg, hdr);
15019 nlmsg_free(msg);
Arend van Spriel5de17982013-04-18 15:49:00 +020015020}
15021EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
15022
Johannes Berg348baf02014-01-24 14:06:29 +010015023void nl80211_send_ap_stopped(struct wireless_dev *wdev)
15024{
15025 struct wiphy *wiphy = wdev->wiphy;
Zhao, Gangf26cbf42014-04-21 12:53:03 +080015026 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Johannes Berg348baf02014-01-24 14:06:29 +010015027 struct sk_buff *msg;
15028 void *hdr;
15029
15030 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
15031 if (!msg)
15032 return;
15033
15034 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
15035 if (!hdr)
15036 goto out;
15037
15038 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
15039 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
Nicolas Dichtel2dad6242016-04-25 10:25:22 +020015040 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
15041 NL80211_ATTR_PAD))
Johannes Berg348baf02014-01-24 14:06:29 +010015042 goto out;
15043
15044 genlmsg_end(msg, hdr);
15045
15046 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
15047 NL80211_MCGRP_MLME, GFP_KERNEL);
15048 return;
15049 out:
15050 nlmsg_free(msg);
15051}
15052
Johannes Berg55682962007-09-20 13:09:35 -040015053/* initialisation/exit functions */
15054
Johannes Berg56989f62016-10-24 14:40:05 +020015055int __init nl80211_init(void)
Johannes Berg55682962007-09-20 13:09:35 -040015056{
Michał Mirosław0d63cbb2009-05-21 10:34:06 +000015057 int err;
Johannes Berg55682962007-09-20 13:09:35 -040015058
Johannes Berg489111e2016-10-24 14:40:03 +020015059 err = genl_register_family(&nl80211_fam);
Johannes Berg55682962007-09-20 13:09:35 -040015060 if (err)
15061 return err;
15062
Jouni Malinen026331c2010-02-15 12:53:10 +020015063 err = netlink_register_notifier(&nl80211_netlink_notifier);
15064 if (err)
15065 goto err_out;
15066
Johannes Berg55682962007-09-20 13:09:35 -040015067 return 0;
15068 err_out:
15069 genl_unregister_family(&nl80211_fam);
15070 return err;
15071}
15072
15073void nl80211_exit(void)
15074{
Jouni Malinen026331c2010-02-15 12:53:10 +020015075 netlink_unregister_notifier(&nl80211_netlink_notifier);
Johannes Berg55682962007-09-20 13:09:35 -040015076 genl_unregister_family(&nl80211_fam);
15077}